├── .env.development ├── .env.production ├── .env.staging ├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── README.md ├── bin ├── build.bat ├── package.bat └── run-web.bat ├── html └── ie.html ├── index.html ├── package.json ├── public └── favicon.ico ├── src ├── App.vue ├── api │ ├── login.js │ ├── menu.js │ ├── monitor │ │ ├── cache.js │ │ ├── job.js │ │ ├── jobLog.js │ │ ├── logininfor.js │ │ ├── online.js │ │ ├── operlog.js │ │ └── server.js │ ├── system │ │ ├── config.js │ │ ├── dept.js │ │ ├── dict │ │ │ ├── data.js │ │ │ └── type.js │ │ ├── menu.js │ │ ├── notice.js │ │ ├── post.js │ │ ├── role.js │ │ └── user.js │ └── tool │ │ └── gen.js ├── assets │ ├── 401_images │ │ └── 401.gif │ ├── 404_images │ │ ├── 404.png │ │ └── 404_cloud.png │ ├── icons │ │ └── svg │ │ │ ├── 404.svg │ │ │ ├── bug.svg │ │ │ ├── build.svg │ │ │ ├── button.svg │ │ │ ├── cascader.svg │ │ │ ├── chart.svg │ │ │ ├── checkbox.svg │ │ │ ├── clipboard.svg │ │ │ ├── code.svg │ │ │ ├── color.svg │ │ │ ├── component.svg │ │ │ ├── dashboard.svg │ │ │ ├── date-range.svg │ │ │ ├── date.svg │ │ │ ├── dict.svg │ │ │ ├── documentation.svg │ │ │ ├── download.svg │ │ │ ├── drag.svg │ │ │ ├── druid.svg │ │ │ ├── edit.svg │ │ │ ├── education.svg │ │ │ ├── email.svg │ │ │ ├── example.svg │ │ │ ├── excel.svg │ │ │ ├── exit-fullscreen.svg │ │ │ ├── eye-open.svg │ │ │ ├── eye.svg │ │ │ ├── form.svg │ │ │ ├── fullscreen.svg │ │ │ ├── github.svg │ │ │ ├── guide.svg │ │ │ ├── icon.svg │ │ │ ├── input.svg │ │ │ ├── international.svg │ │ │ ├── job.svg │ │ │ ├── language.svg │ │ │ ├── link.svg │ │ │ ├── list.svg │ │ │ ├── lock.svg │ │ │ ├── log.svg │ │ │ ├── logininfor.svg │ │ │ ├── message.svg │ │ │ ├── money.svg │ │ │ ├── monitor.svg │ │ │ ├── nested.svg │ │ │ ├── number.svg │ │ │ ├── online.svg │ │ │ ├── password.svg │ │ │ ├── pdf.svg │ │ │ ├── people.svg │ │ │ ├── peoples.svg │ │ │ ├── phone.svg │ │ │ ├── post.svg │ │ │ ├── qq.svg │ │ │ ├── question.svg │ │ │ ├── radio.svg │ │ │ ├── rate.svg │ │ │ ├── redis-list.svg │ │ │ ├── redis.svg │ │ │ ├── row.svg │ │ │ ├── search.svg │ │ │ ├── select.svg │ │ │ ├── server.svg │ │ │ ├── shopping.svg │ │ │ ├── size.svg │ │ │ ├── skill.svg │ │ │ ├── slider.svg │ │ │ ├── star.svg │ │ │ ├── swagger.svg │ │ │ ├── switch.svg │ │ │ ├── system.svg │ │ │ ├── tab.svg │ │ │ ├── table.svg │ │ │ ├── textarea.svg │ │ │ ├── theme.svg │ │ │ ├── time-range.svg │ │ │ ├── time.svg │ │ │ ├── tool.svg │ │ │ ├── tree-table.svg │ │ │ ├── tree.svg │ │ │ ├── upload.svg │ │ │ ├── user.svg │ │ │ ├── validCode.svg │ │ │ ├── wechat.svg │ │ │ └── zip.svg │ ├── images │ │ ├── dark.svg │ │ ├── light.svg │ │ ├── login-background.jpg │ │ ├── pay.png │ │ └── profile.jpg │ ├── logo │ │ └── logo.png │ └── styles │ │ ├── btn.scss │ │ ├── element-ui.scss │ │ ├── index.scss │ │ ├── mixin.scss │ │ ├── ruoyi.scss │ │ ├── sidebar.scss │ │ ├── transition.scss │ │ └── variables.module.scss ├── components │ ├── Breadcrumb │ │ └── index.vue │ ├── Crontab │ │ ├── day.vue │ │ ├── hour.vue │ │ ├── index.vue │ │ ├── min.vue │ │ ├── month.vue │ │ ├── result.vue │ │ ├── second.vue │ │ ├── week.vue │ │ └── year.vue │ ├── DictTag │ │ └── index.vue │ ├── Editor │ │ └── index.vue │ ├── FileUpload │ │ └── index.vue │ ├── Hamburger │ │ └── index.vue │ ├── HeaderSearch │ │ └── index.vue │ ├── IconSelect │ │ ├── index.vue │ │ └── requireIcons.js │ ├── ImagePreview │ │ └── index.vue │ ├── ImageUpload │ │ └── index.vue │ ├── Pagination │ │ └── index.vue │ ├── ParentView │ │ └── index.vue │ ├── RightToolbar │ │ └── index.vue │ ├── RuoYi │ │ ├── Doc │ │ │ └── index.vue │ │ └── Git │ │ │ └── index.vue │ ├── Screenfull │ │ └── index.vue │ ├── SizeSelect │ │ └── index.vue │ ├── SvgIcon │ │ ├── index.vue │ │ └── svgicon.js │ ├── TopNav │ │ └── index.vue │ ├── TreeSelect │ │ └── index.vue │ └── iFrame │ │ └── index.vue ├── directive │ ├── common │ │ └── copyText.js │ ├── index.js │ └── permission │ │ ├── hasPermi.js │ │ └── hasRole.js ├── layout │ ├── components │ │ ├── AppMain.vue │ │ ├── IframeToggle │ │ │ └── index.vue │ │ ├── InnerLink │ │ │ └── index.vue │ │ ├── Navbar.vue │ │ ├── Settings │ │ │ └── index.vue │ │ ├── Sidebar │ │ │ ├── Link.vue │ │ │ ├── Logo.vue │ │ │ ├── SidebarItem.vue │ │ │ └── index.vue │ │ ├── TagsView │ │ │ ├── ScrollPane.vue │ │ │ └── index.vue │ │ └── index.js │ └── index.vue ├── main.js ├── permission.js ├── plugins │ ├── auth.js │ ├── cache.js │ ├── download.js │ ├── index.js │ ├── modal.js │ └── tab.js ├── router │ └── index.js ├── settings.js ├── store │ ├── index.js │ └── modules │ │ ├── app.js │ │ ├── dict.js │ │ ├── permission.js │ │ ├── settings.js │ │ ├── tagsView.js │ │ └── user.js ├── utils │ ├── auth.js │ ├── dict.js │ ├── dynamicTitle.js │ ├── errorCode.js │ ├── index.js │ ├── jsencrypt.js │ ├── permission.js │ ├── request.js │ ├── ruoyi.js │ ├── scroll-to.js │ ├── theme.js │ └── validate.js └── views │ ├── error │ ├── 401.vue │ └── 404.vue │ ├── index.vue │ ├── login.vue │ ├── monitor │ ├── cache │ │ ├── index.vue │ │ └── list.vue │ ├── druid │ │ └── index.vue │ ├── job │ │ ├── index.vue │ │ └── log.vue │ ├── logininfor │ │ └── index.vue │ ├── online │ │ └── index.vue │ ├── operlog │ │ └── index.vue │ └── server │ │ └── index.vue │ ├── redirect │ └── index.vue │ ├── register.vue │ ├── system │ ├── config │ │ └── index.vue │ ├── dept │ │ └── index.vue │ ├── dict │ │ ├── data.vue │ │ └── index.vue │ ├── menu │ │ └── index.vue │ ├── notice │ │ └── index.vue │ ├── post │ │ └── index.vue │ ├── role │ │ ├── authUser.vue │ │ ├── index.vue │ │ └── selectUser.vue │ └── user │ │ ├── authRole.vue │ │ ├── index.vue │ │ └── profile │ │ ├── index.vue │ │ ├── resetPwd.vue │ │ ├── userAvatar.vue │ │ └── userInfo.vue │ └── tool │ ├── build │ └── index.vue │ ├── gen │ ├── basicInfoForm.vue │ ├── createTable.vue │ ├── editTable.vue │ ├── genInfoForm.vue │ ├── importTable.vue │ └── index.vue │ └── swagger │ └── index.vue ├── vite.config.js └── vite └── plugins ├── auto-import.js ├── compression.js ├── index.js ├── setup-extend.js └── svg-icon.js /.env.development: -------------------------------------------------------------------------------- 1 | # 页面标题 2 | VITE_APP_TITLE = 若依管理系统 3 | 4 | # 开发环境配置 5 | VITE_APP_ENV = 'development' 6 | 7 | # 若依管理系统/开发环境 8 | VITE_APP_BASE_API = '/dev-api' 9 | -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | # 页面标题 2 | VITE_APP_TITLE = 若依管理系统 3 | 4 | # 生产环境配置 5 | VITE_APP_ENV = 'production' 6 | 7 | # 若依管理系统/生产环境 8 | VITE_APP_BASE_API = '/prod-api' 9 | 10 | # 是否在打包时开启压缩,支持 gzip 和 brotli 11 | VITE_BUILD_COMPRESS = gzip -------------------------------------------------------------------------------- /.env.staging: -------------------------------------------------------------------------------- 1 | # 页面标题 2 | VITE_APP_TITLE = 若依管理系统 3 | 4 | # 生产环境配置 5 | VITE_APP_ENV = 'staging' 6 | 7 | # 若依管理系统/生产环境 8 | VITE_APP_BASE_API = '/stage-api' 9 | 10 | # 是否在打包时开启压缩,支持 gzip 和 brotli 11 | VITE_BUILD_COMPRESS = gzip -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: http://doc.ruoyi.vip/ruoyi-vue/other/donate.html 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | **/*.log 8 | 9 | tests/**/coverage/ 10 | tests/e2e/reports 11 | selenium-debug.log 12 | 13 | # Editor directories and files 14 | .idea 15 | .vscode 16 | *.suo 17 | *.ntvs* 18 | *.njsproj 19 | *.sln 20 | *.local 21 | 22 | package-lock.json 23 | yarn.lock 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 RuoYi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /bin/build.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snowMan128/Vue3/ce91e30c588c41f73317aeb2fe605a77fd0c0a7a/bin/build.bat -------------------------------------------------------------------------------- /bin/package.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snowMan128/Vue3/ce91e30c588c41f73317aeb2fe605a77fd0c0a7a/bin/package.bat -------------------------------------------------------------------------------- /bin/run-web.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snowMan128/Vue3/ce91e30c588c41f73317aeb2fe605a77fd0c0a7a/bin/run-web.bat -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ruoyi", 3 | "version": "3.8.7", 4 | "description": "若依管理系统", 5 | "author": "若依", 6 | "license": "MIT", 7 | "type": "module", 8 | "scripts": { 9 | "dev": "vite", 10 | "build:prod": "vite build", 11 | "build:stage": "vite build --mode staging", 12 | "preview": "vite preview" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://gitee.com/y_project/RuoYi-Vue.git" 17 | }, 18 | "dependencies": { 19 | "@element-plus/icons-vue": "2.3.1", 20 | "@vueup/vue-quill": "1.2.0", 21 | "@vueuse/core": "10.6.1", 22 | "axios": "0.27.2", 23 | "echarts": "5.4.3", 24 | "element-plus": "2.4.3", 25 | "file-saver": "2.0.5", 26 | "fuse.js": "6.6.2", 27 | "js-cookie": "3.0.5", 28 | "jsencrypt": "3.3.2", 29 | "nprogress": "0.2.0", 30 | "pinia": "2.1.7", 31 | "vue": "3.3.9", 32 | "vue-cropper": "1.1.1", 33 | "vue-router": "4.2.5" 34 | }, 35 | "devDependencies": { 36 | "@vitejs/plugin-vue": "4.5.0", 37 | "@vue/compiler-sfc": "3.3.9", 38 | "sass": "1.69.5", 39 | "unplugin-auto-import": "0.17.1", 40 | "vite": "5.0.4", 41 | "vite-plugin-compression": "0.5.1", 42 | "vite-plugin-svg-icons": "2.0.1", 43 | "unplugin-vue-setup-extend-plus": "1.0.0" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snowMan128/Vue3/ce91e30c588c41f73317aeb2fe605a77fd0c0a7a/public/favicon.ico -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | -------------------------------------------------------------------------------- /src/api/login.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 登录方法 4 | export function login(username, password, code, uuid) { 5 | const data = { 6 | username, 7 | password, 8 | code, 9 | uuid 10 | } 11 | return request({ 12 | url: '/login', 13 | headers: { 14 | isToken: false, 15 | repeatSubmit: false 16 | }, 17 | method: 'post', 18 | data: data 19 | }) 20 | } 21 | 22 | // 注册方法 23 | export function register(data) { 24 | return request({ 25 | url: '/register', 26 | headers: { 27 | isToken: false 28 | }, 29 | method: 'post', 30 | data: data 31 | }) 32 | } 33 | 34 | // 获取用户详细信息 35 | export function getInfo() { 36 | return request({ 37 | url: '/getInfo', 38 | method: 'get' 39 | }) 40 | } 41 | 42 | // 退出方法 43 | export function logout() { 44 | return request({ 45 | url: '/logout', 46 | method: 'post' 47 | }) 48 | } 49 | 50 | // 获取验证码 51 | export function getCodeImg() { 52 | return request({ 53 | url: '/captchaImage', 54 | headers: { 55 | isToken: false 56 | }, 57 | method: 'get', 58 | timeout: 20000 59 | }) 60 | } -------------------------------------------------------------------------------- /src/api/menu.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 获取路由 4 | export const getRouters = () => { 5 | return request({ 6 | url: '/getRouters', 7 | method: 'get' 8 | }) 9 | } -------------------------------------------------------------------------------- /src/api/monitor/cache.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询缓存详细 4 | export function getCache() { 5 | return request({ 6 | url: '/monitor/cache', 7 | method: 'get' 8 | }) 9 | } 10 | 11 | // 查询缓存名称列表 12 | export function listCacheName() { 13 | return request({ 14 | url: '/monitor/cache/getNames', 15 | method: 'get' 16 | }) 17 | } 18 | 19 | // 查询缓存键名列表 20 | export function listCacheKey(cacheName) { 21 | return request({ 22 | url: '/monitor/cache/getKeys/' + cacheName, 23 | method: 'get' 24 | }) 25 | } 26 | 27 | // 查询缓存内容 28 | export function getCacheValue(cacheName, cacheKey) { 29 | return request({ 30 | url: '/monitor/cache/getValue/' + cacheName + '/' + cacheKey, 31 | method: 'get' 32 | }) 33 | } 34 | 35 | // 清理指定名称缓存 36 | export function clearCacheName(cacheName) { 37 | return request({ 38 | url: '/monitor/cache/clearCacheName/' + cacheName, 39 | method: 'delete' 40 | }) 41 | } 42 | 43 | // 清理指定键名缓存 44 | export function clearCacheKey(cacheKey) { 45 | return request({ 46 | url: '/monitor/cache/clearCacheKey/' + cacheKey, 47 | method: 'delete' 48 | }) 49 | } 50 | 51 | // 清理全部缓存 52 | export function clearCacheAll() { 53 | return request({ 54 | url: '/monitor/cache/clearCacheAll', 55 | method: 'delete' 56 | }) 57 | } 58 | -------------------------------------------------------------------------------- /src/api/monitor/job.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询定时任务调度列表 4 | export function listJob(query) { 5 | return request({ 6 | url: '/monitor/job/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询定时任务调度详细 13 | export function getJob(jobId) { 14 | return request({ 15 | url: '/monitor/job/' + jobId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 新增定时任务调度 21 | export function addJob(data) { 22 | return request({ 23 | url: '/monitor/job', 24 | method: 'post', 25 | data: data 26 | }) 27 | } 28 | 29 | // 修改定时任务调度 30 | export function updateJob(data) { 31 | return request({ 32 | url: '/monitor/job', 33 | method: 'put', 34 | data: data 35 | }) 36 | } 37 | 38 | // 删除定时任务调度 39 | export function delJob(jobId) { 40 | return request({ 41 | url: '/monitor/job/' + jobId, 42 | method: 'delete' 43 | }) 44 | } 45 | 46 | // 任务状态修改 47 | export function changeJobStatus(jobId, status) { 48 | const data = { 49 | jobId, 50 | status 51 | } 52 | return request({ 53 | url: '/monitor/job/changeStatus', 54 | method: 'put', 55 | data: data 56 | }) 57 | } 58 | 59 | 60 | // 定时任务立即执行一次 61 | export function runJob(jobId, jobGroup) { 62 | const data = { 63 | jobId, 64 | jobGroup 65 | } 66 | return request({ 67 | url: '/monitor/job/run', 68 | method: 'put', 69 | data: data 70 | }) 71 | } -------------------------------------------------------------------------------- /src/api/monitor/jobLog.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询调度日志列表 4 | export function listJobLog(query) { 5 | return request({ 6 | url: '/monitor/jobLog/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 删除调度日志 13 | export function delJobLog(jobLogId) { 14 | return request({ 15 | url: '/monitor/jobLog/' + jobLogId, 16 | method: 'delete' 17 | }) 18 | } 19 | 20 | // 清空调度日志 21 | export function cleanJobLog() { 22 | return request({ 23 | url: '/monitor/jobLog/clean', 24 | method: 'delete' 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /src/api/monitor/logininfor.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询登录日志列表 4 | export function list(query) { 5 | return request({ 6 | url: '/monitor/logininfor/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 删除登录日志 13 | export function delLogininfor(infoId) { 14 | return request({ 15 | url: '/monitor/logininfor/' + infoId, 16 | method: 'delete' 17 | }) 18 | } 19 | 20 | // 解锁用户登录状态 21 | export function unlockLogininfor(userName) { 22 | return request({ 23 | url: '/monitor/logininfor/unlock/' + userName, 24 | method: 'get' 25 | }) 26 | } 27 | 28 | // 清空登录日志 29 | export function cleanLogininfor() { 30 | return request({ 31 | url: '/monitor/logininfor/clean', 32 | method: 'delete' 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /src/api/monitor/online.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询在线用户列表 4 | export function list(query) { 5 | return request({ 6 | url: '/monitor/online/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 强退用户 13 | export function forceLogout(tokenId) { 14 | return request({ 15 | url: '/monitor/online/' + tokenId, 16 | method: 'delete' 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /src/api/monitor/operlog.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询操作日志列表 4 | export function list(query) { 5 | return request({ 6 | url: '/monitor/operlog/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 删除操作日志 13 | export function delOperlog(operId) { 14 | return request({ 15 | url: '/monitor/operlog/' + operId, 16 | method: 'delete' 17 | }) 18 | } 19 | 20 | // 清空操作日志 21 | export function cleanOperlog() { 22 | return request({ 23 | url: '/monitor/operlog/clean', 24 | method: 'delete' 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /src/api/monitor/server.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 获取服务信息 4 | export function getServer() { 5 | return request({ 6 | url: '/monitor/server', 7 | method: 'get' 8 | }) 9 | } -------------------------------------------------------------------------------- /src/api/system/config.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询参数列表 4 | export function listConfig(query) { 5 | return request({ 6 | url: '/system/config/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询参数详细 13 | export function getConfig(configId) { 14 | return request({ 15 | url: '/system/config/' + configId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 根据参数键名查询参数值 21 | export function getConfigKey(configKey) { 22 | return request({ 23 | url: '/system/config/configKey/' + configKey, 24 | method: 'get' 25 | }) 26 | } 27 | 28 | // 新增参数配置 29 | export function addConfig(data) { 30 | return request({ 31 | url: '/system/config', 32 | method: 'post', 33 | data: data 34 | }) 35 | } 36 | 37 | // 修改参数配置 38 | export function updateConfig(data) { 39 | return request({ 40 | url: '/system/config', 41 | method: 'put', 42 | data: data 43 | }) 44 | } 45 | 46 | // 删除参数配置 47 | export function delConfig(configId) { 48 | return request({ 49 | url: '/system/config/' + configId, 50 | method: 'delete' 51 | }) 52 | } 53 | 54 | // 刷新参数缓存 55 | export function refreshCache() { 56 | return request({ 57 | url: '/system/config/refreshCache', 58 | method: 'delete' 59 | }) 60 | } 61 | -------------------------------------------------------------------------------- /src/api/system/dept.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询部门列表 4 | export function listDept(query) { 5 | return request({ 6 | url: '/system/dept/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询部门列表(排除节点) 13 | export function listDeptExcludeChild(deptId) { 14 | return request({ 15 | url: '/system/dept/list/exclude/' + deptId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 查询部门详细 21 | export function getDept(deptId) { 22 | return request({ 23 | url: '/system/dept/' + deptId, 24 | method: 'get' 25 | }) 26 | } 27 | 28 | // 新增部门 29 | export function addDept(data) { 30 | return request({ 31 | url: '/system/dept', 32 | method: 'post', 33 | data: data 34 | }) 35 | } 36 | 37 | // 修改部门 38 | export function updateDept(data) { 39 | return request({ 40 | url: '/system/dept', 41 | method: 'put', 42 | data: data 43 | }) 44 | } 45 | 46 | // 删除部门 47 | export function delDept(deptId) { 48 | return request({ 49 | url: '/system/dept/' + deptId, 50 | method: 'delete' 51 | }) 52 | } -------------------------------------------------------------------------------- /src/api/system/dict/data.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询字典数据列表 4 | export function listData(query) { 5 | return request({ 6 | url: '/system/dict/data/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询字典数据详细 13 | export function getData(dictCode) { 14 | return request({ 15 | url: '/system/dict/data/' + dictCode, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 根据字典类型查询字典数据信息 21 | export function getDicts(dictType) { 22 | return request({ 23 | url: '/system/dict/data/type/' + dictType, 24 | method: 'get' 25 | }) 26 | } 27 | 28 | // 新增字典数据 29 | export function addData(data) { 30 | return request({ 31 | url: '/system/dict/data', 32 | method: 'post', 33 | data: data 34 | }) 35 | } 36 | 37 | // 修改字典数据 38 | export function updateData(data) { 39 | return request({ 40 | url: '/system/dict/data', 41 | method: 'put', 42 | data: data 43 | }) 44 | } 45 | 46 | // 删除字典数据 47 | export function delData(dictCode) { 48 | return request({ 49 | url: '/system/dict/data/' + dictCode, 50 | method: 'delete' 51 | }) 52 | } 53 | -------------------------------------------------------------------------------- /src/api/system/dict/type.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询字典类型列表 4 | export function listType(query) { 5 | return request({ 6 | url: '/system/dict/type/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询字典类型详细 13 | export function getType(dictId) { 14 | return request({ 15 | url: '/system/dict/type/' + dictId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 新增字典类型 21 | export function addType(data) { 22 | return request({ 23 | url: '/system/dict/type', 24 | method: 'post', 25 | data: data 26 | }) 27 | } 28 | 29 | // 修改字典类型 30 | export function updateType(data) { 31 | return request({ 32 | url: '/system/dict/type', 33 | method: 'put', 34 | data: data 35 | }) 36 | } 37 | 38 | // 删除字典类型 39 | export function delType(dictId) { 40 | return request({ 41 | url: '/system/dict/type/' + dictId, 42 | method: 'delete' 43 | }) 44 | } 45 | 46 | // 刷新字典缓存 47 | export function refreshCache() { 48 | return request({ 49 | url: '/system/dict/type/refreshCache', 50 | method: 'delete' 51 | }) 52 | } 53 | 54 | // 获取字典选择框列表 55 | export function optionselect() { 56 | return request({ 57 | url: '/system/dict/type/optionselect', 58 | method: 'get' 59 | }) 60 | } 61 | -------------------------------------------------------------------------------- /src/api/system/menu.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询菜单列表 4 | export function listMenu(query) { 5 | return request({ 6 | url: '/system/menu/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询菜单详细 13 | export function getMenu(menuId) { 14 | return request({ 15 | url: '/system/menu/' + menuId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 查询菜单下拉树结构 21 | export function treeselect() { 22 | return request({ 23 | url: '/system/menu/treeselect', 24 | method: 'get' 25 | }) 26 | } 27 | 28 | // 根据角色ID查询菜单下拉树结构 29 | export function roleMenuTreeselect(roleId) { 30 | return request({ 31 | url: '/system/menu/roleMenuTreeselect/' + roleId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | // 新增菜单 37 | export function addMenu(data) { 38 | return request({ 39 | url: '/system/menu', 40 | method: 'post', 41 | data: data 42 | }) 43 | } 44 | 45 | // 修改菜单 46 | export function updateMenu(data) { 47 | return request({ 48 | url: '/system/menu', 49 | method: 'put', 50 | data: data 51 | }) 52 | } 53 | 54 | // 删除菜单 55 | export function delMenu(menuId) { 56 | return request({ 57 | url: '/system/menu/' + menuId, 58 | method: 'delete' 59 | }) 60 | } -------------------------------------------------------------------------------- /src/api/system/notice.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询公告列表 4 | export function listNotice(query) { 5 | return request({ 6 | url: '/system/notice/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询公告详细 13 | export function getNotice(noticeId) { 14 | return request({ 15 | url: '/system/notice/' + noticeId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 新增公告 21 | export function addNotice(data) { 22 | return request({ 23 | url: '/system/notice', 24 | method: 'post', 25 | data: data 26 | }) 27 | } 28 | 29 | // 修改公告 30 | export function updateNotice(data) { 31 | return request({ 32 | url: '/system/notice', 33 | method: 'put', 34 | data: data 35 | }) 36 | } 37 | 38 | // 删除公告 39 | export function delNotice(noticeId) { 40 | return request({ 41 | url: '/system/notice/' + noticeId, 42 | method: 'delete' 43 | }) 44 | } -------------------------------------------------------------------------------- /src/api/system/post.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询岗位列表 4 | export function listPost(query) { 5 | return request({ 6 | url: '/system/post/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询岗位详细 13 | export function getPost(postId) { 14 | return request({ 15 | url: '/system/post/' + postId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 新增岗位 21 | export function addPost(data) { 22 | return request({ 23 | url: '/system/post', 24 | method: 'post', 25 | data: data 26 | }) 27 | } 28 | 29 | // 修改岗位 30 | export function updatePost(data) { 31 | return request({ 32 | url: '/system/post', 33 | method: 'put', 34 | data: data 35 | }) 36 | } 37 | 38 | // 删除岗位 39 | export function delPost(postId) { 40 | return request({ 41 | url: '/system/post/' + postId, 42 | method: 'delete' 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /src/api/system/role.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询角色列表 4 | export function listRole(query) { 5 | return request({ 6 | url: '/system/role/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询角色详细 13 | export function getRole(roleId) { 14 | return request({ 15 | url: '/system/role/' + roleId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 新增角色 21 | export function addRole(data) { 22 | return request({ 23 | url: '/system/role', 24 | method: 'post', 25 | data: data 26 | }) 27 | } 28 | 29 | // 修改角色 30 | export function updateRole(data) { 31 | return request({ 32 | url: '/system/role', 33 | method: 'put', 34 | data: data 35 | }) 36 | } 37 | 38 | // 角色数据权限 39 | export function dataScope(data) { 40 | return request({ 41 | url: '/system/role/dataScope', 42 | method: 'put', 43 | data: data 44 | }) 45 | } 46 | 47 | // 角色状态修改 48 | export function changeRoleStatus(roleId, status) { 49 | const data = { 50 | roleId, 51 | status 52 | } 53 | return request({ 54 | url: '/system/role/changeStatus', 55 | method: 'put', 56 | data: data 57 | }) 58 | } 59 | 60 | // 删除角色 61 | export function delRole(roleId) { 62 | return request({ 63 | url: '/system/role/' + roleId, 64 | method: 'delete' 65 | }) 66 | } 67 | 68 | // 查询角色已授权用户列表 69 | export function allocatedUserList(query) { 70 | return request({ 71 | url: '/system/role/authUser/allocatedList', 72 | method: 'get', 73 | params: query 74 | }) 75 | } 76 | 77 | // 查询角色未授权用户列表 78 | export function unallocatedUserList(query) { 79 | return request({ 80 | url: '/system/role/authUser/unallocatedList', 81 | method: 'get', 82 | params: query 83 | }) 84 | } 85 | 86 | // 取消用户授权角色 87 | export function authUserCancel(data) { 88 | return request({ 89 | url: '/system/role/authUser/cancel', 90 | method: 'put', 91 | data: data 92 | }) 93 | } 94 | 95 | // 批量取消用户授权角色 96 | export function authUserCancelAll(data) { 97 | return request({ 98 | url: '/system/role/authUser/cancelAll', 99 | method: 'put', 100 | params: data 101 | }) 102 | } 103 | 104 | // 授权用户选择 105 | export function authUserSelectAll(data) { 106 | return request({ 107 | url: '/system/role/authUser/selectAll', 108 | method: 'put', 109 | params: data 110 | }) 111 | } 112 | 113 | // 根据角色ID查询部门树结构 114 | export function deptTreeSelect(roleId) { 115 | return request({ 116 | url: '/system/role/deptTree/' + roleId, 117 | method: 'get' 118 | }) 119 | } 120 | -------------------------------------------------------------------------------- /src/api/tool/gen.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询生成表数据 4 | export function listTable(query) { 5 | return request({ 6 | url: '/tool/gen/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | // 查询db数据库列表 12 | export function listDbTable(query) { 13 | return request({ 14 | url: '/tool/gen/db/list', 15 | method: 'get', 16 | params: query 17 | }) 18 | } 19 | 20 | // 查询表详细信息 21 | export function getGenTable(tableId) { 22 | return request({ 23 | url: '/tool/gen/' + tableId, 24 | method: 'get' 25 | }) 26 | } 27 | 28 | // 修改代码生成信息 29 | export function updateGenTable(data) { 30 | return request({ 31 | url: '/tool/gen', 32 | method: 'put', 33 | data: data 34 | }) 35 | } 36 | 37 | // 导入表 38 | export function importTable(data) { 39 | return request({ 40 | url: '/tool/gen/importTable', 41 | method: 'post', 42 | params: data 43 | }) 44 | } 45 | 46 | // 创建表 47 | export function createTable(data) { 48 | return request({ 49 | url: '/tool/gen/createTable', 50 | method: 'post', 51 | params: data 52 | }) 53 | } 54 | 55 | // 预览生成代码 56 | export function previewTable(tableId) { 57 | return request({ 58 | url: '/tool/gen/preview/' + tableId, 59 | method: 'get' 60 | }) 61 | } 62 | 63 | // 删除表数据 64 | export function delTable(tableId) { 65 | return request({ 66 | url: '/tool/gen/' + tableId, 67 | method: 'delete' 68 | }) 69 | } 70 | 71 | // 生成代码(自定义路径) 72 | export function genCode(tableName) { 73 | return request({ 74 | url: '/tool/gen/genCode/' + tableName, 75 | method: 'get' 76 | }) 77 | } 78 | 79 | // 同步数据库 80 | export function synchDb(tableName) { 81 | return request({ 82 | url: '/tool/gen/synchDb/' + tableName, 83 | method: 'get' 84 | }) 85 | } 86 | -------------------------------------------------------------------------------- /src/assets/401_images/401.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snowMan128/Vue3/ce91e30c588c41f73317aeb2fe605a77fd0c0a7a/src/assets/401_images/401.gif -------------------------------------------------------------------------------- /src/assets/404_images/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snowMan128/Vue3/ce91e30c588c41f73317aeb2fe605a77fd0c0a7a/src/assets/404_images/404.png -------------------------------------------------------------------------------- /src/assets/404_images/404_cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snowMan128/Vue3/ce91e30c588c41f73317aeb2fe605a77fd0c0a7a/src/assets/404_images/404_cloud.png -------------------------------------------------------------------------------- /src/assets/icons/svg/404.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/bug.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/build.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/button.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/cascader.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/chart.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/checkbox.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/clipboard.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/code.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/component.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/dashboard.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/date-range.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/dict.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/documentation.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/download.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/drag.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/druid.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/edit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/education.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/email.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/example.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/excel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/exit-fullscreen.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/eye-open.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/eye.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/form.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/fullscreen.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/guide.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/input.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/international.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/job.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/language.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/link.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/list.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/lock.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/log.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/logininfor.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/message.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/money.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/monitor.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/nested.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/password.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/pdf.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/people.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/peoples.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/phone.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/post.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/question.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/radio.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/rate.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/redis-list.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/redis.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/row.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/search.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/select.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/server.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/shopping.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/size.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/skill.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/slider.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/star.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/swagger.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/switch.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/tab.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/table.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/textarea.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/theme.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/time.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/tool.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/tree-table.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/tree.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/upload.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/user.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/validCode.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/wechat.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/zip.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/assets/images/light.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/assets/images/login-background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snowMan128/Vue3/ce91e30c588c41f73317aeb2fe605a77fd0c0a7a/src/assets/images/login-background.jpg -------------------------------------------------------------------------------- /src/assets/images/pay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snowMan128/Vue3/ce91e30c588c41f73317aeb2fe605a77fd0c0a7a/src/assets/images/pay.png -------------------------------------------------------------------------------- /src/assets/images/profile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snowMan128/Vue3/ce91e30c588c41f73317aeb2fe605a77fd0c0a7a/src/assets/images/profile.jpg -------------------------------------------------------------------------------- /src/assets/logo/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snowMan128/Vue3/ce91e30c588c41f73317aeb2fe605a77fd0c0a7a/src/assets/logo/logo.png -------------------------------------------------------------------------------- /src/assets/styles/btn.scss: -------------------------------------------------------------------------------- 1 | @import './variables.module.scss'; 2 | 3 | @mixin colorBtn($color) { 4 | background: $color; 5 | 6 | &:hover { 7 | color: $color; 8 | 9 | &:before, 10 | &:after { 11 | background: $color; 12 | } 13 | } 14 | } 15 | 16 | .blue-btn { 17 | @include colorBtn($blue) 18 | } 19 | 20 | .light-blue-btn { 21 | @include colorBtn($light-blue) 22 | } 23 | 24 | .red-btn { 25 | @include colorBtn($red) 26 | } 27 | 28 | .pink-btn { 29 | @include colorBtn($pink) 30 | } 31 | 32 | .green-btn { 33 | @include colorBtn($green) 34 | } 35 | 36 | .tiffany-btn { 37 | @include colorBtn($tiffany) 38 | } 39 | 40 | .yellow-btn { 41 | @include colorBtn($yellow) 42 | } 43 | 44 | .pan-btn { 45 | font-size: 14px; 46 | color: #fff; 47 | padding: 14px 36px; 48 | border-radius: 8px; 49 | border: none; 50 | outline: none; 51 | transition: 600ms ease all; 52 | position: relative; 53 | display: inline-block; 54 | 55 | &:hover { 56 | background: #fff; 57 | 58 | &:before, 59 | &:after { 60 | width: 100%; 61 | transition: 600ms ease all; 62 | } 63 | } 64 | 65 | &:before, 66 | &:after { 67 | content: ''; 68 | position: absolute; 69 | top: 0; 70 | right: 0; 71 | height: 2px; 72 | width: 0; 73 | transition: 400ms ease all; 74 | } 75 | 76 | &::after { 77 | right: inherit; 78 | top: inherit; 79 | left: 0; 80 | bottom: 0; 81 | } 82 | } 83 | 84 | .custom-button { 85 | display: inline-block; 86 | line-height: 1; 87 | white-space: nowrap; 88 | cursor: pointer; 89 | background: #fff; 90 | color: #fff; 91 | -webkit-appearance: none; 92 | text-align: center; 93 | box-sizing: border-box; 94 | outline: 0; 95 | margin: 0; 96 | padding: 10px 15px; 97 | font-size: 14px; 98 | border-radius: 4px; 99 | } 100 | -------------------------------------------------------------------------------- /src/assets/styles/element-ui.scss: -------------------------------------------------------------------------------- 1 | // cover some element-ui styles 2 | 3 | .el-breadcrumb__inner, 4 | .el-breadcrumb__inner a { 5 | font-weight: 400 !important; 6 | } 7 | 8 | .el-upload { 9 | input[type="file"] { 10 | display: none !important; 11 | } 12 | } 13 | 14 | .el-upload__input { 15 | display: none; 16 | } 17 | 18 | .cell { 19 | .el-tag { 20 | margin-right: 0px; 21 | } 22 | } 23 | 24 | .small-padding { 25 | .cell { 26 | padding-left: 5px; 27 | padding-right: 5px; 28 | } 29 | } 30 | 31 | .fixed-width { 32 | .el-button--mini { 33 | padding: 7px 10px; 34 | width: 60px; 35 | } 36 | } 37 | 38 | .status-col { 39 | .cell { 40 | padding: 0 10px; 41 | text-align: center; 42 | 43 | .el-tag { 44 | margin-right: 0px; 45 | } 46 | } 47 | } 48 | 49 | // to fixed https://github.com/ElemeFE/element/issues/2461 50 | .el-dialog { 51 | transform: none; 52 | left: 0; 53 | position: relative; 54 | margin: 0 auto; 55 | } 56 | 57 | // refine element ui upload 58 | .upload-container { 59 | .el-upload { 60 | width: 100%; 61 | 62 | .el-upload-dragger { 63 | width: 100%; 64 | height: 200px; 65 | } 66 | } 67 | } 68 | 69 | // dropdown 70 | .el-dropdown-menu { 71 | a { 72 | display: block 73 | } 74 | } 75 | 76 | // fix date-picker ui bug in filter-item 77 | .el-range-editor.el-input__inner { 78 | display: inline-flex !important; 79 | } 80 | 81 | // to fix el-date-picker css style 82 | .el-range-separator { 83 | box-sizing: content-box; 84 | } 85 | 86 | .el-menu--collapse 87 | > div 88 | > .el-submenu 89 | > .el-submenu__title 90 | .el-submenu__icon-arrow { 91 | display: none; 92 | } 93 | 94 | .el-dropdown .el-dropdown-link{ 95 | color: var(--el-color-primary) !important; 96 | } -------------------------------------------------------------------------------- /src/assets/styles/mixin.scss: -------------------------------------------------------------------------------- 1 | @mixin clearfix { 2 | &:after { 3 | content: ""; 4 | display: table; 5 | clear: both; 6 | } 7 | } 8 | 9 | @mixin scrollBar { 10 | &::-webkit-scrollbar-track-piece { 11 | background: #d3dce6; 12 | } 13 | 14 | &::-webkit-scrollbar { 15 | width: 6px; 16 | } 17 | 18 | &::-webkit-scrollbar-thumb { 19 | background: #99a9bf; 20 | border-radius: 20px; 21 | } 22 | } 23 | 24 | @mixin relative { 25 | position: relative; 26 | width: 100%; 27 | height: 100%; 28 | } 29 | 30 | @mixin pct($pct) { 31 | width: #{$pct}; 32 | position: relative; 33 | margin: 0 auto; 34 | } 35 | 36 | @mixin triangle($width, $height, $color, $direction) { 37 | $width: $width/2; 38 | $color-border-style: $height solid $color; 39 | $transparent-border-style: $width solid transparent; 40 | height: 0; 41 | width: 0; 42 | 43 | @if $direction==up { 44 | border-bottom: $color-border-style; 45 | border-left: $transparent-border-style; 46 | border-right: $transparent-border-style; 47 | } 48 | 49 | @else if $direction==right { 50 | border-left: $color-border-style; 51 | border-top: $transparent-border-style; 52 | border-bottom: $transparent-border-style; 53 | } 54 | 55 | @else if $direction==down { 56 | border-top: $color-border-style; 57 | border-left: $transparent-border-style; 58 | border-right: $transparent-border-style; 59 | } 60 | 61 | @else if $direction==left { 62 | border-right: $color-border-style; 63 | border-top: $transparent-border-style; 64 | border-bottom: $transparent-border-style; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/assets/styles/transition.scss: -------------------------------------------------------------------------------- 1 | // global transition css 2 | 3 | /* fade */ 4 | .fade-enter-active, 5 | .fade-leave-active { 6 | transition: opacity 0.28s; 7 | } 8 | 9 | .fade-enter, 10 | .fade-leave-active { 11 | opacity: 0; 12 | } 13 | 14 | /* fade-transform */ 15 | .fade-transform--move, 16 | .fade-transform-leave-active, 17 | .fade-transform-enter-active { 18 | transition: all .5s; 19 | } 20 | 21 | .fade-transform-enter { 22 | opacity: 0; 23 | transform: translateX(-30px); 24 | } 25 | 26 | .fade-transform-leave-to { 27 | opacity: 0; 28 | transform: translateX(30px); 29 | } 30 | 31 | /* breadcrumb transition */ 32 | .breadcrumb-enter-active, 33 | .breadcrumb-leave-active { 34 | transition: all .5s; 35 | } 36 | 37 | .breadcrumb-enter, 38 | .breadcrumb-leave-active { 39 | opacity: 0; 40 | transform: translateX(20px); 41 | } 42 | 43 | .breadcrumb-move { 44 | transition: all .5s; 45 | } 46 | 47 | .breadcrumb-leave-active { 48 | position: absolute; 49 | } 50 | -------------------------------------------------------------------------------- /src/assets/styles/variables.module.scss: -------------------------------------------------------------------------------- 1 | // base color 2 | $blue: #324157; 3 | $light-blue: #3A71A8; 4 | $red: #C03639; 5 | $pink: #E65D6E; 6 | $green: #30B08F; 7 | $tiffany: #4AB7BD; 8 | $yellow: #FEC171; 9 | $panGreen: #30B08F; 10 | 11 | // 默认菜单主题风格 12 | $base-menu-color: #bfcbd9; 13 | $base-menu-color-active: #f4f4f5; 14 | $base-menu-background: #304156; 15 | $base-logo-title-color: #ffffff; 16 | 17 | $base-menu-light-color: rgba(0, 0, 0, 0.7); 18 | $base-menu-light-background: #ffffff; 19 | $base-logo-light-title-color: #001529; 20 | 21 | $base-sub-menu-background: #1f2d3d; 22 | $base-sub-menu-hover: #001528; 23 | 24 | // 自定义暗色菜单风格 25 | /** 26 | $base-menu-color:hsla(0,0%,100%,.65); 27 | $base-menu-color-active:#fff; 28 | $base-menu-background:#001529; 29 | $base-logo-title-color: #ffffff; 30 | 31 | $base-menu-light-color:rgba(0,0,0,.70); 32 | $base-menu-light-background:#ffffff; 33 | $base-logo-light-title-color: #001529; 34 | 35 | $base-sub-menu-background:#000c17; 36 | $base-sub-menu-hover:#001528; 37 | */ 38 | 39 | $--color-primary: #409EFF; 40 | $--color-success: #67C23A; 41 | $--color-warning: #E6A23C; 42 | $--color-danger: #F56C6C; 43 | $--color-info: #909399; 44 | 45 | $base-sidebar-width: 200px; 46 | 47 | // the :export directive is the magic sauce for webpack 48 | // https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass 49 | :export { 50 | menuColor: $base-menu-color; 51 | menuLightColor: $base-menu-light-color; 52 | menuColorActive: $base-menu-color-active; 53 | menuBackground: $base-menu-background; 54 | menuLightBackground: $base-menu-light-background; 55 | subMenuBackground: $base-sub-menu-background; 56 | subMenuHover: $base-sub-menu-hover; 57 | sideBarWidth: $base-sidebar-width; 58 | logoTitleColor: $base-logo-title-color; 59 | logoLightTitleColor: $base-logo-light-title-color; 60 | primaryColor: $--color-primary; 61 | successColor: $--color-success; 62 | dangerColor: $--color-danger; 63 | infoColor: $--color-info; 64 | warningColor: $--color-warning; 65 | } 66 | -------------------------------------------------------------------------------- /src/components/Breadcrumb/index.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 53 | 54 | -------------------------------------------------------------------------------- /src/components/DictTag/index.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 77 | 78 | 83 | -------------------------------------------------------------------------------- /src/components/Hamburger/index.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 29 | 30 | 42 | -------------------------------------------------------------------------------- /src/components/IconSelect/requireIcons.js: -------------------------------------------------------------------------------- 1 | let icons = [] 2 | const modules = import.meta.glob('./../../assets/icons/svg/*.svg'); 3 | for (const path in modules) { 4 | const p = path.split('assets/icons/svg/')[1].split('.svg')[0]; 5 | icons.push(p); 6 | } 7 | 8 | export default icons -------------------------------------------------------------------------------- /src/components/ImagePreview/index.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 69 | 70 | 93 | -------------------------------------------------------------------------------- /src/components/Pagination/index.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 96 | 97 | -------------------------------------------------------------------------------- /src/components/ParentView/index.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /src/components/RuoYi/Doc/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /src/components/RuoYi/Git/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | -------------------------------------------------------------------------------- /src/components/Screenfull/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /src/components/SizeSelect/index.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 38 | 39 | -------------------------------------------------------------------------------- /src/components/SvgIcon/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 36 | 37 | 54 | -------------------------------------------------------------------------------- /src/components/SvgIcon/svgicon.js: -------------------------------------------------------------------------------- 1 | import * as components from '@element-plus/icons-vue' 2 | 3 | export default { 4 | install: (app) => { 5 | for (const key in components) { 6 | const componentConfig = components[key]; 7 | app.component(componentConfig.name, componentConfig); 8 | } 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /src/components/iFrame/index.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 25 | -------------------------------------------------------------------------------- /src/layout/components/Sidebar/Link.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 41 | -------------------------------------------------------------------------------- /src/layout/components/Sidebar/Logo.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 32 | 33 | -------------------------------------------------------------------------------- /src/layout/components/Sidebar/index.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 55 | -------------------------------------------------------------------------------- /src/layout/components/index.js: -------------------------------------------------------------------------------- 1 | export { default as AppMain } from './AppMain' 2 | export { default as Navbar } from './Navbar' 3 | export { default as Settings } from './Settings' 4 | export { default as TagsView } from './TagsView/index.vue' 5 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | 3 | import Cookies from 'js-cookie' 4 | 5 | import ElementPlus from 'element-plus' 6 | import 'element-plus/dist/index.css' 7 | import locale from 'element-plus/es/locale/lang/zh-cn' 8 | 9 | import '@/assets/styles/index.scss' // global css 10 | 11 | import App from './App' 12 | import store from './store' 13 | import router from './router' 14 | import directive from './directive' // directive 15 | 16 | // 注册指令 17 | import plugins from './plugins' // plugins 18 | import { download } from '@/utils/request' 19 | 20 | // svg图标 21 | import 'virtual:svg-icons-register' 22 | import SvgIcon from '@/components/SvgIcon' 23 | import elementIcons from '@/components/SvgIcon/svgicon' 24 | 25 | import './permission' // permission control 26 | 27 | import { useDict } from '@/utils/dict' 28 | import { parseTime, resetForm, addDateRange, handleTree, selectDictLabel, selectDictLabels } from '@/utils/ruoyi' 29 | 30 | // 分页组件 31 | import Pagination from '@/components/Pagination' 32 | // 自定义表格工具组件 33 | import RightToolbar from '@/components/RightToolbar' 34 | // 富文本组件 35 | import Editor from "@/components/Editor" 36 | // 文件上传组件 37 | import FileUpload from "@/components/FileUpload" 38 | // 图片上传组件 39 | import ImageUpload from "@/components/ImageUpload" 40 | // 图片预览组件 41 | import ImagePreview from "@/components/ImagePreview" 42 | // 自定义树选择组件 43 | import TreeSelect from '@/components/TreeSelect' 44 | // 字典标签组件 45 | import DictTag from '@/components/DictTag' 46 | 47 | const app = createApp(App) 48 | 49 | // 全局方法挂载 50 | app.config.globalProperties.useDict = useDict 51 | app.config.globalProperties.download = download 52 | app.config.globalProperties.parseTime = parseTime 53 | app.config.globalProperties.resetForm = resetForm 54 | app.config.globalProperties.handleTree = handleTree 55 | app.config.globalProperties.addDateRange = addDateRange 56 | app.config.globalProperties.selectDictLabel = selectDictLabel 57 | app.config.globalProperties.selectDictLabels = selectDictLabels 58 | 59 | // 全局组件挂载 60 | app.component('DictTag', DictTag) 61 | app.component('Pagination', Pagination) 62 | app.component('TreeSelect', TreeSelect) 63 | app.component('FileUpload', FileUpload) 64 | app.component('ImageUpload', ImageUpload) 65 | app.component('ImagePreview', ImagePreview) 66 | app.component('RightToolbar', RightToolbar) 67 | app.component('Editor', Editor) 68 | 69 | app.use(router) 70 | app.use(store) 71 | app.use(plugins) 72 | app.use(elementIcons) 73 | app.component('svg-icon', SvgIcon) 74 | 75 | directive(app) 76 | 77 | // 使用element-plus 并且设置全局的大小 78 | app.use(ElementPlus, { 79 | locale: locale, 80 | // 支持 large、default、small 81 | size: Cookies.get('size') || 'default' 82 | }) 83 | 84 | app.mount('#app') 85 | -------------------------------------------------------------------------------- /src/permission.js: -------------------------------------------------------------------------------- 1 | import router from './router' 2 | import { ElMessage } from 'element-plus' 3 | import NProgress from 'nprogress' 4 | import 'nprogress/nprogress.css' 5 | import { getToken } from '@/utils/auth' 6 | import { isHttp } from '@/utils/validate' 7 | import { isRelogin } from '@/utils/request' 8 | import useUserStore from '@/store/modules/user' 9 | import useSettingsStore from '@/store/modules/settings' 10 | import usePermissionStore from '@/store/modules/permission' 11 | 12 | NProgress.configure({ showSpinner: false }); 13 | 14 | const whiteList = ['/login', '/register']; 15 | 16 | router.beforeEach((to, from, next) => { 17 | NProgress.start() 18 | if (getToken()) { 19 | to.meta.title && useSettingsStore().setTitle(to.meta.title) 20 | /* has token*/ 21 | if (to.path === '/login') { 22 | next({ path: '/' }) 23 | NProgress.done() 24 | } else if (whiteList.indexOf(to.path) !== -1) { 25 | next() 26 | } else { 27 | if (useUserStore().roles.length === 0) { 28 | isRelogin.show = true 29 | // 判断当前用户是否已拉取完user_info信息 30 | useUserStore().getInfo().then(() => { 31 | isRelogin.show = false 32 | usePermissionStore().generateRoutes().then(accessRoutes => { 33 | // 根据roles权限生成可访问的路由表 34 | accessRoutes.forEach(route => { 35 | if (!isHttp(route.path)) { 36 | router.addRoute(route) // 动态添加可访问路由表 37 | } 38 | }) 39 | next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 40 | }) 41 | }).catch(err => { 42 | useUserStore().logOut().then(() => { 43 | ElMessage.error(err) 44 | next({ path: '/' }) 45 | }) 46 | }) 47 | } else { 48 | next() 49 | } 50 | } 51 | } else { 52 | // 没有token 53 | if (whiteList.indexOf(to.path) !== -1) { 54 | // 在免登录白名单,直接进入 55 | next() 56 | } else { 57 | next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页 58 | NProgress.done() 59 | } 60 | } 61 | }) 62 | 63 | router.afterEach(() => { 64 | NProgress.done() 65 | }) 66 | -------------------------------------------------------------------------------- /src/plugins/auth.js: -------------------------------------------------------------------------------- 1 | import useUserStore from '@/store/modules/user' 2 | 3 | function authPermission(permission) { 4 | const all_permission = "*:*:*"; 5 | const permissions = useUserStore().permissions 6 | if (permission && permission.length > 0) { 7 | return permissions.some(v => { 8 | return all_permission === v || v === permission 9 | }) 10 | } else { 11 | return false 12 | } 13 | } 14 | 15 | function authRole(role) { 16 | const super_admin = "admin"; 17 | const roles = useUserStore().roles 18 | if (role && role.length > 0) { 19 | return roles.some(v => { 20 | return super_admin === v || v === role 21 | }) 22 | } else { 23 | return false 24 | } 25 | } 26 | 27 | export default { 28 | // 验证用户是否具备某权限 29 | hasPermi(permission) { 30 | return authPermission(permission); 31 | }, 32 | // 验证用户是否含有指定权限,只需包含其中一个 33 | hasPermiOr(permissions) { 34 | return permissions.some(item => { 35 | return authPermission(item) 36 | }) 37 | }, 38 | // 验证用户是否含有指定权限,必须全部拥有 39 | hasPermiAnd(permissions) { 40 | return permissions.every(item => { 41 | return authPermission(item) 42 | }) 43 | }, 44 | // 验证用户是否具备某角色 45 | hasRole(role) { 46 | return authRole(role); 47 | }, 48 | // 验证用户是否含有指定角色,只需包含其中一个 49 | hasRoleOr(roles) { 50 | return roles.some(item => { 51 | return authRole(item) 52 | }) 53 | }, 54 | // 验证用户是否含有指定角色,必须全部拥有 55 | hasRoleAnd(roles) { 56 | return roles.every(item => { 57 | return authRole(item) 58 | }) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/plugins/cache.js: -------------------------------------------------------------------------------- 1 | const sessionCache = { 2 | set (key, value) { 3 | if (!sessionStorage) { 4 | return 5 | } 6 | if (key != null && value != null) { 7 | sessionStorage.setItem(key, value) 8 | } 9 | }, 10 | get (key) { 11 | if (!sessionStorage) { 12 | return null 13 | } 14 | if (key == null) { 15 | return null 16 | } 17 | return sessionStorage.getItem(key) 18 | }, 19 | setJSON (key, jsonValue) { 20 | if (jsonValue != null) { 21 | this.set(key, JSON.stringify(jsonValue)) 22 | } 23 | }, 24 | getJSON (key) { 25 | const value = this.get(key) 26 | if (value != null) { 27 | return JSON.parse(value) 28 | } 29 | }, 30 | remove (key) { 31 | sessionStorage.removeItem(key); 32 | } 33 | } 34 | const localCache = { 35 | set (key, value) { 36 | if (!localStorage) { 37 | return 38 | } 39 | if (key != null && value != null) { 40 | localStorage.setItem(key, value) 41 | } 42 | }, 43 | get (key) { 44 | if (!localStorage) { 45 | return null 46 | } 47 | if (key == null) { 48 | return null 49 | } 50 | return localStorage.getItem(key) 51 | }, 52 | setJSON (key, jsonValue) { 53 | if (jsonValue != null) { 54 | this.set(key, JSON.stringify(jsonValue)) 55 | } 56 | }, 57 | getJSON (key) { 58 | const value = this.get(key) 59 | if (value != null) { 60 | return JSON.parse(value) 61 | } 62 | }, 63 | remove (key) { 64 | localStorage.removeItem(key); 65 | } 66 | } 67 | 68 | export default { 69 | /** 70 | * 会话级缓存 71 | */ 72 | session: sessionCache, 73 | /** 74 | * 本地缓存 75 | */ 76 | local: localCache 77 | } 78 | -------------------------------------------------------------------------------- /src/plugins/index.js: -------------------------------------------------------------------------------- 1 | import tab from './tab' 2 | import auth from './auth' 3 | import cache from './cache' 4 | import modal from './modal' 5 | import download from './download' 6 | 7 | export default function installPlugins(app){ 8 | // 页签操作 9 | app.config.globalProperties.$tab = tab 10 | // 认证对象 11 | app.config.globalProperties.$auth = auth 12 | // 缓存对象 13 | app.config.globalProperties.$cache = cache 14 | // 模态框对象 15 | app.config.globalProperties.$modal = modal 16 | // 下载文件 17 | app.config.globalProperties.$download = download 18 | } 19 | -------------------------------------------------------------------------------- /src/plugins/modal.js: -------------------------------------------------------------------------------- 1 | import { ElMessage, ElMessageBox, ElNotification, ElLoading } from 'element-plus' 2 | 3 | let loadingInstance; 4 | 5 | export default { 6 | // 消息提示 7 | msg(content) { 8 | ElMessage.info(content) 9 | }, 10 | // 错误消息 11 | msgError(content) { 12 | ElMessage.error(content) 13 | }, 14 | // 成功消息 15 | msgSuccess(content) { 16 | ElMessage.success(content) 17 | }, 18 | // 警告消息 19 | msgWarning(content) { 20 | ElMessage.warning(content) 21 | }, 22 | // 弹出提示 23 | alert(content) { 24 | ElMessageBox.alert(content, "系统提示") 25 | }, 26 | // 错误提示 27 | alertError(content) { 28 | ElMessageBox.alert(content, "系统提示", { type: 'error' }) 29 | }, 30 | // 成功提示 31 | alertSuccess(content) { 32 | ElMessageBox.alert(content, "系统提示", { type: 'success' }) 33 | }, 34 | // 警告提示 35 | alertWarning(content) { 36 | ElMessageBox.alert(content, "系统提示", { type: 'warning' }) 37 | }, 38 | // 通知提示 39 | notify(content) { 40 | ElNotification.info(content) 41 | }, 42 | // 错误通知 43 | notifyError(content) { 44 | ElNotification.error(content); 45 | }, 46 | // 成功通知 47 | notifySuccess(content) { 48 | ElNotification.success(content) 49 | }, 50 | // 警告通知 51 | notifyWarning(content) { 52 | ElNotification.warning(content) 53 | }, 54 | // 确认窗体 55 | confirm(content) { 56 | return ElMessageBox.confirm(content, "系统提示", { 57 | confirmButtonText: '确定', 58 | cancelButtonText: '取消', 59 | type: "warning", 60 | }) 61 | }, 62 | // 提交内容 63 | prompt(content) { 64 | return ElMessageBox.prompt(content, "系统提示", { 65 | confirmButtonText: '确定', 66 | cancelButtonText: '取消', 67 | type: "warning", 68 | }) 69 | }, 70 | // 打开遮罩层 71 | loading(content) { 72 | loadingInstance = ElLoading.service({ 73 | lock: true, 74 | text: content, 75 | background: "rgba(0, 0, 0, 0.7)", 76 | }) 77 | }, 78 | // 关闭遮罩层 79 | closeLoading() { 80 | loadingInstance.close(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/plugins/tab.js: -------------------------------------------------------------------------------- 1 | import useTagsViewStore from '@/store/modules/tagsView' 2 | import router from '@/router' 3 | 4 | export default { 5 | // 刷新当前tab页签 6 | refreshPage(obj) { 7 | const { path, query, matched } = router.currentRoute.value; 8 | if (obj === undefined) { 9 | matched.forEach((m) => { 10 | if (m.components && m.components.default && m.components.default.name) { 11 | if (!['Layout', 'ParentView'].includes(m.components.default.name)) { 12 | obj = { name: m.components.default.name, path: path, query: query }; 13 | } 14 | } 15 | }); 16 | } 17 | return useTagsViewStore().delCachedView(obj).then(() => { 18 | const { path, query } = obj 19 | router.replace({ 20 | path: '/redirect' + path, 21 | query: query 22 | }) 23 | }) 24 | }, 25 | // 关闭当前tab页签,打开新页签 26 | closeOpenPage(obj) { 27 | useTagsViewStore().delView(router.currentRoute.value); 28 | if (obj !== undefined) { 29 | return router.push(obj); 30 | } 31 | }, 32 | // 关闭指定tab页签 33 | closePage(obj) { 34 | if (obj === undefined) { 35 | return useTagsViewStore().delView(router.currentRoute.value).then(({ visitedViews }) => { 36 | const latestView = visitedViews.slice(-1)[0] 37 | if (latestView) { 38 | return router.push(latestView.fullPath) 39 | } 40 | return router.push('/'); 41 | }); 42 | } 43 | return useTagsViewStore().delView(obj); 44 | }, 45 | // 关闭所有tab页签 46 | closeAllPage() { 47 | return useTagsViewStore().delAllViews(); 48 | }, 49 | // 关闭左侧tab页签 50 | closeLeftPage(obj) { 51 | return useTagsViewStore().delLeftTags(obj || router.currentRoute.value); 52 | }, 53 | // 关闭右侧tab页签 54 | closeRightPage(obj) { 55 | return useTagsViewStore().delRightTags(obj || router.currentRoute.value); 56 | }, 57 | // 关闭其他tab页签 58 | closeOtherPage(obj) { 59 | return useTagsViewStore().delOthersViews(obj || router.currentRoute.value); 60 | }, 61 | // 打开tab页签 62 | openPage(url) { 63 | return router.push(url); 64 | }, 65 | // 修改tab页签 66 | updatePage(obj) { 67 | return useTagsViewStore().updateVisitedView(obj); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/settings.js: -------------------------------------------------------------------------------- 1 | export default { 2 | /** 3 | * 网页标题 4 | */ 5 | title: import.meta.env.VITE_APP_TITLE, 6 | /** 7 | * 侧边栏主题 深色主题theme-dark,浅色主题theme-light 8 | */ 9 | sideTheme: 'theme-dark', 10 | /** 11 | * 是否系统布局配置 12 | */ 13 | showSettings: true, 14 | 15 | /** 16 | * 是否显示顶部导航 17 | */ 18 | topNav: false, 19 | 20 | /** 21 | * 是否显示 tagsView 22 | */ 23 | tagsView: true, 24 | 25 | /** 26 | * 是否固定头部 27 | */ 28 | fixedHeader: false, 29 | 30 | /** 31 | * 是否显示logo 32 | */ 33 | sidebarLogo: true, 34 | 35 | /** 36 | * 是否显示动态标题 37 | */ 38 | dynamicTitle: false, 39 | 40 | /** 41 | * @type {string | array} 'production' | ['production', 'development'] 42 | * @description Need show err logs component. 43 | * The default is only used in the production env 44 | * If you want to also use it in dev, you can pass ['production', 'development'] 45 | */ 46 | errorLog: 'production' 47 | } 48 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | const store = createPinia() 2 | 3 | export default store -------------------------------------------------------------------------------- /src/store/modules/app.js: -------------------------------------------------------------------------------- 1 | import Cookies from 'js-cookie' 2 | 3 | const useAppStore = defineStore( 4 | 'app', 5 | { 6 | state: () => ({ 7 | sidebar: { 8 | opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true, 9 | withoutAnimation: false, 10 | hide: false 11 | }, 12 | device: 'desktop', 13 | size: Cookies.get('size') || 'default' 14 | }), 15 | actions: { 16 | toggleSideBar(withoutAnimation) { 17 | if (this.sidebar.hide) { 18 | return false; 19 | } 20 | this.sidebar.opened = !this.sidebar.opened 21 | this.sidebar.withoutAnimation = withoutAnimation 22 | if (this.sidebar.opened) { 23 | Cookies.set('sidebarStatus', 1) 24 | } else { 25 | Cookies.set('sidebarStatus', 0) 26 | } 27 | }, 28 | closeSideBar({ withoutAnimation }) { 29 | Cookies.set('sidebarStatus', 0) 30 | this.sidebar.opened = false 31 | this.sidebar.withoutAnimation = withoutAnimation 32 | }, 33 | toggleDevice(device) { 34 | this.device = device 35 | }, 36 | setSize(size) { 37 | this.size = size; 38 | Cookies.set('size', size) 39 | }, 40 | toggleSideBarHide(status) { 41 | this.sidebar.hide = status 42 | } 43 | } 44 | }) 45 | 46 | export default useAppStore 47 | -------------------------------------------------------------------------------- /src/store/modules/dict.js: -------------------------------------------------------------------------------- 1 | const useDictStore = defineStore( 2 | 'dict', 3 | { 4 | state: () => ({ 5 | dict: new Array() 6 | }), 7 | actions: { 8 | // 获取字典 9 | getDict(_key) { 10 | if (_key == null && _key == "") { 11 | return null; 12 | } 13 | try { 14 | for (let i = 0; i < this.dict.length; i++) { 15 | if (this.dict[i].key == _key) { 16 | return this.dict[i].value; 17 | } 18 | } 19 | } catch (e) { 20 | return null; 21 | } 22 | }, 23 | // 设置字典 24 | setDict(_key, value) { 25 | if (_key !== null && _key !== "") { 26 | this.dict.push({ 27 | key: _key, 28 | value: value 29 | }); 30 | } 31 | }, 32 | // 删除字典 33 | removeDict(_key) { 34 | var bln = false; 35 | try { 36 | for (let i = 0; i < this.dict.length; i++) { 37 | if (this.dict[i].key == _key) { 38 | this.dict.splice(i, 1); 39 | return true; 40 | } 41 | } 42 | } catch (e) { 43 | bln = false; 44 | } 45 | return bln; 46 | }, 47 | // 清空字典 48 | cleanDict() { 49 | this.dict = new Array(); 50 | }, 51 | // 初始字典 52 | initDict() { 53 | } 54 | } 55 | }) 56 | 57 | export default useDictStore 58 | -------------------------------------------------------------------------------- /src/store/modules/settings.js: -------------------------------------------------------------------------------- 1 | import defaultSettings from '@/settings' 2 | import { useDynamicTitle } from '@/utils/dynamicTitle' 3 | 4 | const { sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle } = defaultSettings 5 | 6 | const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || '' 7 | 8 | const useSettingsStore = defineStore( 9 | 'settings', 10 | { 11 | state: () => ({ 12 | title: '', 13 | theme: storageSetting.theme || '#409EFF', 14 | sideTheme: storageSetting.sideTheme || sideTheme, 15 | showSettings: showSettings, 16 | topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav, 17 | tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView, 18 | fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader, 19 | sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo, 20 | dynamicTitle: storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle 21 | }), 22 | actions: { 23 | // 修改布局设置 24 | changeSetting(data) { 25 | const { key, value } = data 26 | if (this.hasOwnProperty(key)) { 27 | this[key] = value 28 | } 29 | }, 30 | // 设置网页标题 31 | setTitle(title) { 32 | this.title = title 33 | useDynamicTitle(); 34 | } 35 | } 36 | }) 37 | 38 | export default useSettingsStore 39 | -------------------------------------------------------------------------------- /src/store/modules/user.js: -------------------------------------------------------------------------------- 1 | import { login, logout, getInfo } from '@/api/login' 2 | import { getToken, setToken, removeToken } from '@/utils/auth' 3 | import defAva from '@/assets/images/profile.jpg' 4 | 5 | const useUserStore = defineStore( 6 | 'user', 7 | { 8 | state: () => ({ 9 | token: getToken(), 10 | id: '', 11 | name: '', 12 | avatar: '', 13 | roles: [], 14 | permissions: [] 15 | }), 16 | actions: { 17 | // 登录 18 | login(userInfo) { 19 | const username = userInfo.username.trim() 20 | const password = userInfo.password 21 | const code = userInfo.code 22 | const uuid = userInfo.uuid 23 | return new Promise((resolve, reject) => { 24 | login(username, password, code, uuid).then(res => { 25 | setToken(res.token) 26 | this.token = res.token 27 | resolve() 28 | }).catch(error => { 29 | reject(error) 30 | }) 31 | }) 32 | }, 33 | // 获取用户信息 34 | getInfo() { 35 | return new Promise((resolve, reject) => { 36 | getInfo().then(res => { 37 | const user = res.user 38 | const avatar = (user.avatar == "" || user.avatar == null) ? defAva : import.meta.env.VITE_APP_BASE_API + user.avatar; 39 | 40 | if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组 41 | this.roles = res.roles 42 | this.permissions = res.permissions 43 | } else { 44 | this.roles = ['ROLE_DEFAULT'] 45 | } 46 | this.id = user.userId 47 | this.name = user.userName 48 | this.avatar = avatar 49 | resolve(res) 50 | }).catch(error => { 51 | reject(error) 52 | }) 53 | }) 54 | }, 55 | // 退出系统 56 | logOut() { 57 | return new Promise((resolve, reject) => { 58 | logout(this.token).then(() => { 59 | this.token = '' 60 | this.roles = [] 61 | this.permissions = [] 62 | removeToken() 63 | resolve() 64 | }).catch(error => { 65 | reject(error) 66 | }) 67 | }) 68 | } 69 | } 70 | }) 71 | 72 | export default useUserStore 73 | -------------------------------------------------------------------------------- /src/utils/auth.js: -------------------------------------------------------------------------------- 1 | import Cookies from 'js-cookie' 2 | 3 | const TokenKey = 'Admin-Token' 4 | 5 | export function getToken() { 6 | return Cookies.get(TokenKey) 7 | } 8 | 9 | export function setToken(token) { 10 | return Cookies.set(TokenKey, token) 11 | } 12 | 13 | export function removeToken() { 14 | return Cookies.remove(TokenKey) 15 | } 16 | -------------------------------------------------------------------------------- /src/utils/dict.js: -------------------------------------------------------------------------------- 1 | import useDictStore from '@/store/modules/dict' 2 | import { getDicts } from '@/api/system/dict/data' 3 | 4 | /** 5 | * 获取字典数据 6 | */ 7 | export function useDict(...args) { 8 | const res = ref({}); 9 | return (() => { 10 | args.forEach((dictType, index) => { 11 | res.value[dictType] = []; 12 | const dicts = useDictStore().getDict(dictType); 13 | if (dicts) { 14 | res.value[dictType] = dicts; 15 | } else { 16 | getDicts(dictType).then(resp => { 17 | res.value[dictType] = resp.data.map(p => ({ label: p.dictLabel, value: p.dictValue, elTagType: p.listClass, elTagClass: p.cssClass })) 18 | useDictStore().setDict(dictType, res.value[dictType]); 19 | }) 20 | } 21 | }) 22 | return toRefs(res.value); 23 | })() 24 | } -------------------------------------------------------------------------------- /src/utils/dynamicTitle.js: -------------------------------------------------------------------------------- 1 | import store from '@/store' 2 | import defaultSettings from '@/settings' 3 | import useSettingsStore from '@/store/modules/settings' 4 | 5 | /** 6 | * 动态修改标题 7 | */ 8 | export function useDynamicTitle() { 9 | const settingsStore = useSettingsStore(); 10 | if (settingsStore.dynamicTitle) { 11 | document.title = settingsStore.title + ' - ' + defaultSettings.title; 12 | } else { 13 | document.title = defaultSettings.title; 14 | } 15 | } -------------------------------------------------------------------------------- /src/utils/errorCode.js: -------------------------------------------------------------------------------- 1 | export default { 2 | '401': '认证失败,无法访问系统资源', 3 | '403': '当前操作没有权限', 4 | '404': '访问资源不存在', 5 | 'default': '系统未知错误,请反馈给管理员' 6 | } 7 | -------------------------------------------------------------------------------- /src/utils/jsencrypt.js: -------------------------------------------------------------------------------- 1 | import JSEncrypt from 'jsencrypt/bin/jsencrypt.min' 2 | 3 | // 密钥对生成 http://web.chacuo.net/netrsakeypair 4 | 5 | const publicKey = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdH\n' + 6 | 'nzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==' 7 | 8 | const privateKey = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY\n' + 9 | '7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKN\n' + 10 | 'PuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gA\n' + 11 | 'kM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWow\n' + 12 | 'cSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99Ecv\n' + 13 | 'DQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthh\n' + 14 | 'YhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3\n' + 15 | 'UP8iWi1Qw0Y=' 16 | 17 | // 加密 18 | export function encrypt(txt) { 19 | const encryptor = new JSEncrypt() 20 | encryptor.setPublicKey(publicKey) // 设置公钥 21 | return encryptor.encrypt(txt) // 对数据进行加密 22 | } 23 | 24 | // 解密 25 | export function decrypt(txt) { 26 | const encryptor = new JSEncrypt() 27 | encryptor.setPrivateKey(privateKey) // 设置私钥 28 | return encryptor.decrypt(txt) // 对数据进行解密 29 | } 30 | 31 | -------------------------------------------------------------------------------- /src/utils/permission.js: -------------------------------------------------------------------------------- 1 | import useUserStore from '@/store/modules/user' 2 | 3 | /** 4 | * 字符权限校验 5 | * @param {Array} value 校验值 6 | * @returns {Boolean} 7 | */ 8 | export function checkPermi(value) { 9 | if (value && value instanceof Array && value.length > 0) { 10 | const permissions = useUserStore().permissions 11 | const permissionDatas = value 12 | const all_permission = "*:*:*"; 13 | 14 | const hasPermission = permissions.some(permission => { 15 | return all_permission === permission || permissionDatas.includes(permission) 16 | }) 17 | 18 | if (!hasPermission) { 19 | return false 20 | } 21 | return true 22 | } else { 23 | console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`) 24 | return false 25 | } 26 | } 27 | 28 | /** 29 | * 角色权限校验 30 | * @param {Array} value 校验值 31 | * @returns {Boolean} 32 | */ 33 | export function checkRole(value) { 34 | if (value && value instanceof Array && value.length > 0) { 35 | const roles = useUserStore().roles 36 | const permissionRoles = value 37 | const super_admin = "admin"; 38 | 39 | const hasRole = roles.some(role => { 40 | return super_admin === role || permissionRoles.includes(role) 41 | }) 42 | 43 | if (!hasRole) { 44 | return false 45 | } 46 | return true 47 | } else { 48 | console.error(`need roles! Like checkRole="['admin','editor']"`) 49 | return false 50 | } 51 | } -------------------------------------------------------------------------------- /src/utils/scroll-to.js: -------------------------------------------------------------------------------- 1 | Math.easeInOutQuad = function(t, b, c, d) { 2 | t /= d / 2 3 | if (t < 1) { 4 | return c / 2 * t * t + b 5 | } 6 | t-- 7 | return -c / 2 * (t * (t - 2) - 1) + b 8 | } 9 | 10 | // requestAnimationFrame for Smart Animating http://goo.gl/sx5sts 11 | var requestAnimFrame = (function() { 12 | return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) } 13 | })() 14 | 15 | /** 16 | * Because it's so fucking difficult to detect the scrolling element, just move them all 17 | * @param {number} amount 18 | */ 19 | function move(amount) { 20 | document.documentElement.scrollTop = amount 21 | document.body.parentNode.scrollTop = amount 22 | document.body.scrollTop = amount 23 | } 24 | 25 | function position() { 26 | return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop 27 | } 28 | 29 | /** 30 | * @param {number} to 31 | * @param {number} duration 32 | * @param {Function} callback 33 | */ 34 | export function scrollTo(to, duration, callback) { 35 | const start = position() 36 | const change = to - start 37 | const increment = 20 38 | let currentTime = 0 39 | duration = (typeof (duration) === 'undefined') ? 500 : duration 40 | var animateScroll = function() { 41 | // increment the time 42 | currentTime += increment 43 | // find the value with the quadratic in-out easing function 44 | var val = Math.easeInOutQuad(currentTime, start, change, duration) 45 | // move the document.body 46 | move(val) 47 | // do the animation unless its over 48 | if (currentTime < duration) { 49 | requestAnimFrame(animateScroll) 50 | } else { 51 | if (callback && typeof (callback) === 'function') { 52 | // the animation is done so lets callback 53 | callback() 54 | } 55 | } 56 | } 57 | animateScroll() 58 | } 59 | -------------------------------------------------------------------------------- /src/utils/theme.js: -------------------------------------------------------------------------------- 1 | // 处理主题样式 2 | export function handleThemeStyle(theme) { 3 | document.documentElement.style.setProperty('--el-color-primary', theme) 4 | for (let i = 1; i <= 9; i++) { 5 | document.documentElement.style.setProperty(`--el-color-primary-light-${i}`, `${getLightColor(theme, i / 10)}`) 6 | } 7 | for (let i = 1; i <= 9; i++) { 8 | document.documentElement.style.setProperty(`--el-color-primary-dark-${i}`, `${getDarkColor(theme, i / 10)}`) 9 | } 10 | } 11 | 12 | // hex颜色转rgb颜色 13 | export function hexToRgb(str) { 14 | str = str.replace('#', '') 15 | let hexs = str.match(/../g) 16 | for (let i = 0; i < 3; i++) { 17 | hexs[i] = parseInt(hexs[i], 16) 18 | } 19 | return hexs 20 | } 21 | 22 | // rgb颜色转Hex颜色 23 | export function rgbToHex(r, g, b) { 24 | let hexs = [r.toString(16), g.toString(16), b.toString(16)] 25 | for (let i = 0; i < 3; i++) { 26 | if (hexs[i].length == 1) { 27 | hexs[i] = `0${hexs[i]}` 28 | } 29 | } 30 | return `#${hexs.join('')}` 31 | } 32 | 33 | // 变浅颜色值 34 | export function getLightColor(color, level) { 35 | let rgb = hexToRgb(color) 36 | for (let i = 0; i < 3; i++) { 37 | rgb[i] = Math.floor((255 - rgb[i]) * level + rgb[i]) 38 | } 39 | return rgbToHex(rgb[0], rgb[1], rgb[2]) 40 | } 41 | 42 | // 变深颜色值 43 | export function getDarkColor(color, level) { 44 | let rgb = hexToRgb(color) 45 | for (let i = 0; i < 3; i++) { 46 | rgb[i] = Math.floor(rgb[i] * (1 - level)) 47 | } 48 | return rgbToHex(rgb[0], rgb[1], rgb[2]) 49 | } 50 | -------------------------------------------------------------------------------- /src/utils/validate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 判断url是否是http或https 3 | * @param {string} path 4 | * @returns {Boolean} 5 | */ 6 | export function isHttp(url) { 7 | return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1 8 | } 9 | 10 | /** 11 | * 判断path是否为外链 12 | * @param {string} path 13 | * @returns {Boolean} 14 | */ 15 | export function isExternal(path) { 16 | return /^(https?:|mailto:|tel:)/.test(path) 17 | } 18 | 19 | /** 20 | * @param {string} str 21 | * @returns {Boolean} 22 | */ 23 | export function validUsername(str) { 24 | const valid_map = ['admin', 'editor'] 25 | return valid_map.indexOf(str.trim()) >= 0 26 | } 27 | 28 | /** 29 | * @param {string} url 30 | * @returns {Boolean} 31 | */ 32 | export function validURL(url) { 33 | const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/ 34 | return reg.test(url) 35 | } 36 | 37 | /** 38 | * @param {string} str 39 | * @returns {Boolean} 40 | */ 41 | export function validLowerCase(str) { 42 | const reg = /^[a-z]+$/ 43 | return reg.test(str) 44 | } 45 | 46 | /** 47 | * @param {string} str 48 | * @returns {Boolean} 49 | */ 50 | export function validUpperCase(str) { 51 | const reg = /^[A-Z]+$/ 52 | return reg.test(str) 53 | } 54 | 55 | /** 56 | * @param {string} str 57 | * @returns {Boolean} 58 | */ 59 | export function validAlphabets(str) { 60 | const reg = /^[A-Za-z]+$/ 61 | return reg.test(str) 62 | } 63 | 64 | /** 65 | * @param {string} email 66 | * @returns {Boolean} 67 | */ 68 | export function validEmail(email) { 69 | const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ 70 | return reg.test(email) 71 | } 72 | 73 | /** 74 | * @param {string} str 75 | * @returns {Boolean} 76 | */ 77 | export function isString(str) { 78 | if (typeof str === 'string' || str instanceof String) { 79 | return true 80 | } 81 | return false 82 | } 83 | 84 | /** 85 | * @param {Array} arg 86 | * @returns {Boolean} 87 | */ 88 | export function isArray(arg) { 89 | if (typeof Array.isArray === 'undefined') { 90 | return Object.prototype.toString.call(arg) === '[object Array]' 91 | } 92 | return Array.isArray(arg) 93 | } 94 | -------------------------------------------------------------------------------- /src/views/error/401.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 43 | 44 | 83 | -------------------------------------------------------------------------------- /src/views/monitor/druid/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | -------------------------------------------------------------------------------- /src/views/redirect/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /src/views/system/user/profile/resetPwd.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 58 | -------------------------------------------------------------------------------- /src/views/system/user/profile/userInfo.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 68 | -------------------------------------------------------------------------------- /src/views/tool/build/index.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/tool/gen/basicInfoForm.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 49 | -------------------------------------------------------------------------------- /src/views/tool/gen/createTable.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 47 | -------------------------------------------------------------------------------- /src/views/tool/swagger/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig, loadEnv } from 'vite' 2 | import path from 'path' 3 | import createVitePlugins from './vite/plugins' 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig(({ mode, command }) => { 7 | const env = loadEnv(mode, process.cwd()) 8 | const { VITE_APP_ENV } = env 9 | return { 10 | // 部署生产环境和开发环境下的URL。 11 | // 默认情况下,vite 会假设你的应用是被部署在一个域名的根路径上 12 | // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。 13 | base: VITE_APP_ENV === 'production' ? '/' : '/', 14 | plugins: createVitePlugins(env, command === 'build'), 15 | resolve: { 16 | // https://cn.vitejs.dev/config/#resolve-alias 17 | alias: { 18 | // 设置路径 19 | '~': path.resolve(__dirname, './'), 20 | // 设置别名 21 | '@': path.resolve(__dirname, './src') 22 | }, 23 | // https://cn.vitejs.dev/config/#resolve-extensions 24 | extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'] 25 | }, 26 | // vite 相关配置 27 | server: { 28 | port: 80, 29 | host: true, 30 | open: true, 31 | proxy: { 32 | // https://cn.vitejs.dev/config/#server-proxy 33 | '/dev-api': { 34 | target: 'http://localhost:8080', 35 | changeOrigin: true, 36 | rewrite: (p) => p.replace(/^\/dev-api/, '') 37 | } 38 | } 39 | }, 40 | //fix:error:stdin>:7356:1: warning: "@charset" must be the first rule in the file 41 | css: { 42 | postcss: { 43 | plugins: [ 44 | { 45 | postcssPlugin: 'internal:charset-removal', 46 | AtRule: { 47 | charset: (atRule) => { 48 | if (atRule.name === 'charset') { 49 | atRule.remove(); 50 | } 51 | } 52 | } 53 | } 54 | ] 55 | } 56 | } 57 | } 58 | }) 59 | -------------------------------------------------------------------------------- /vite/plugins/auto-import.js: -------------------------------------------------------------------------------- 1 | import autoImport from 'unplugin-auto-import/vite' 2 | 3 | export default function createAutoImport() { 4 | return autoImport({ 5 | imports: [ 6 | 'vue', 7 | 'vue-router', 8 | 'pinia' 9 | ], 10 | dts: false 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /vite/plugins/compression.js: -------------------------------------------------------------------------------- 1 | import compression from 'vite-plugin-compression' 2 | 3 | export default function createCompression(env) { 4 | const { VITE_BUILD_COMPRESS } = env 5 | const plugin = [] 6 | if (VITE_BUILD_COMPRESS) { 7 | const compressList = VITE_BUILD_COMPRESS.split(',') 8 | if (compressList.includes('gzip')) { 9 | // http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件 10 | plugin.push( 11 | compression({ 12 | ext: '.gz', 13 | deleteOriginFile: false 14 | }) 15 | ) 16 | } 17 | if (compressList.includes('brotli')) { 18 | plugin.push( 19 | compression({ 20 | ext: '.br', 21 | algorithm: 'brotliCompress', 22 | deleteOriginFile: false 23 | }) 24 | ) 25 | } 26 | } 27 | return plugin 28 | } 29 | -------------------------------------------------------------------------------- /vite/plugins/index.js: -------------------------------------------------------------------------------- 1 | import vue from '@vitejs/plugin-vue' 2 | 3 | import createAutoImport from './auto-import' 4 | import createSvgIcon from './svg-icon' 5 | import createCompression from './compression' 6 | import createSetupExtend from './setup-extend' 7 | 8 | export default function createVitePlugins(viteEnv, isBuild = false) { 9 | const vitePlugins = [vue()] 10 | vitePlugins.push(createAutoImport()) 11 | vitePlugins.push(createSetupExtend()) 12 | vitePlugins.push(createSvgIcon(isBuild)) 13 | isBuild && vitePlugins.push(...createCompression(viteEnv)) 14 | return vitePlugins 15 | } 16 | -------------------------------------------------------------------------------- /vite/plugins/setup-extend.js: -------------------------------------------------------------------------------- 1 | import setupExtend from 'unplugin-vue-setup-extend-plus/vite' 2 | 3 | export default function createSetupExtend() { 4 | return setupExtend({}) 5 | } 6 | -------------------------------------------------------------------------------- /vite/plugins/svg-icon.js: -------------------------------------------------------------------------------- 1 | import { createSvgIconsPlugin } from 'vite-plugin-svg-icons' 2 | import path from 'path' 3 | 4 | export default function createSvgIcon(isBuild) { 5 | return createSvgIconsPlugin({ 6 | iconDirs: [path.resolve(process.cwd(), 'src/assets/icons/svg')], 7 | symbolId: 'icon-[dir]-[name]', 8 | svgoOptions: isBuild 9 | }) 10 | } 11 | --------------------------------------------------------------------------------