diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..e7989ed --- /dev/null +++ b/.env.development @@ -0,0 +1 @@ +VITE_BASE_URL= 'https://vue3.go-admin.dev' \ No newline at end of file diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..e69de29 diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..83cf0e3 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,15 @@ +module.exports = { + extends: [ + // add more generic rulesets here, such as: + // 'eslint:recommended', + 'plugin:vue/base', + 'plugin:vue/vue3-essential', + // 'plugin:vue/vue3-strongly-recommended' + //'plugin:vue/vue3-recommended', + // 'plugin:vue/recommended' // Use this if you are using Vue.js 2.x. + ], + rules: { + // override/add rules settings here, such as: + // 'vue/no-unused-vars': 'error' + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index a19f004..0a81269 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,31 @@ -# ---> Vue -# gitignore template for Vue.js projects -# -# Recommended template: Node.gitignore +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* -# TODO: where does this rule come from? -docs/_book +yarn.lock -# TODO: where does this rule come from? -test/ +node_modules +dist +dist-ssr +*.local +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# node_modules +node_modules +package-lock.json +package-lock.json diff --git a/README.md b/README.md index 0b08572..78c7330 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,318 @@ -# hospital-admin +# Vue 3 + Vite -互联网医院 -前端 \ No newline at end of file +This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 ` + + diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..709c3f8 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES6", + "module": "commonjs", + "allowSyntheticDefaultImports": true, + "baseUrl": "./", + "paths": { + "@/*": ["src/*"] + } + }, + "exclude": [ + "node_modules" + ] +} diff --git a/mock/index.js b/mock/index.js new file mode 100644 index 0000000..5059834 --- /dev/null +++ b/mock/index.js @@ -0,0 +1,4 @@ +import user from './sys_post' +export default [ + user, +] \ No newline at end of file diff --git a/mock/sys_post.js b/mock/sys_post.js new file mode 100644 index 0000000..46e0a1f --- /dev/null +++ b/mock/sys_post.js @@ -0,0 +1,36 @@ +import Mock from 'mockjs' + +const mock = { + 'list|10': [ + { + 'roleId|+1': 1, + 'roleName|1': [ + '系统管理员', + '福州系统运维', + '产品管理', + '前端开发', + '后端开发' + ], + 'roleKey': 'admin', + 'roleSort|+1': 0, + 'status|0-1': 0, + 'createAt': `${Mock.Random.date()} ${Mock.Random.time()}` + } + ], +} + +const login = { + url: '/api/admin/post', + method: 'get', + timeout: 500, + statusCode: 200, + response: { + code: 200, + message: '登陆成功', + data: Mock.toJSONSchema(mock).template + } +} + +export default [ + login, +] \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..68b71a7 --- /dev/null +++ b/package.json @@ -0,0 +1,40 @@ +{ + "name": "quark_arco", + "private": true, + "version": "0.0.0", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "@ant-design/icons": "^5.0.1", + "@codemirror/lang-html": "^6.4.3", + "@codemirror/lang-javascript": "^6.1.7", + "@codemirror/lang-json": "^6.0.1", + "@codemirror/theme-one-dark": "^6.1.2", + "@vueuse/core": "^10.1.2", + "axios": "^1.4.0", + "codemirror": "^6.0.1", + "cropperjs": "^1.5.13", + "i": "^0.3.7", + "js-cookie": "^3.0.5", + "npm": "^9.6.6", + "pinia": "^2.0.36", + "vue": "^3.2.47", + "vue-codemirror": "^6.1.1", + "vue-router": "^4.1.6" + }, + "devDependencies": { + "@arco-design/web-vue": "^2.45.3", + "@vitejs/plugin-vue": "^4.2.1", + "unplugin-vue-components": "^0.24.1", + "eslint": "^8.40.0", + "eslint-plugin-vue": "^9.12.0", + "mockjs": "^1.1.0", + "sass": "^1.62.1", + "vite": "^4.3.5", + "vite-plugin-mock": "^3.0.0", + "vite-svg-loader": "^4.0.0" + } +} diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 0000000..64e784f --- /dev/null +++ b/prettier.config.js @@ -0,0 +1,19 @@ +module.exports = { + "arrowParens": "always", + "bracketSameLine": false, + "bracketSpacing": true, + "embeddedLanguageFormatting": "auto", + "htmlWhitespaceSensitivity": "css", + "insertPragma": false, + "jsxSingleQuote": false, + "printWidth": 80, + "proseWrap": "preserve", + "quoteProps": "as-needed", + "requirePragma": false, + "semi": true, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "useTabs": false, + "vueIndentScriptAndStyle": false +} \ No newline at end of file diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..7abef30 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/login_left_bg.jpg b/public/login_left_bg.jpg new file mode 100644 index 0000000..19ed2cc Binary files /dev/null and b/public/login_left_bg.jpg differ diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..ba32c22 --- /dev/null +++ b/src/App.vue @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/src/api/admin/login.js b/src/api/admin/login.js new file mode 100644 index 0000000..52230d1 --- /dev/null +++ b/src/api/admin/login.js @@ -0,0 +1,30 @@ +import request from '../../utils/request'; +export function login(data) { + return request({ + url:'/api/v1/login', + method: 'post', + data + }) +} + +export function getCaptcha() { + return request({ + url:'/api/v1/captcha', + method: 'get' + }) +} + +export function getAppConfig() { + return request({ + url:'/api/v1/app-config', + method: 'get' + }) +} + +// 根据角色获取菜单 +export function getUserMenuRole() { + return request({ + url:'/api/v1/menurole', + method: 'get' + }) +} \ No newline at end of file diff --git a/src/api/admin/menu.js b/src/api/admin/menu.js new file mode 100644 index 0000000..5e4595f --- /dev/null +++ b/src/api/admin/menu.js @@ -0,0 +1,48 @@ +import request from '../../utils/request' + +const url = '/api/v1/menu'; + +export function getMenu(params) { + return request({ + url, + method: 'get', + params + }) +} + +export function getMenuDetails(menuId) { + return request({ + url: `${url}/${menuId}`, + method: 'get' + }) +} + +export function addMenu(data) { + return request({ + url, + method: 'post', + data + }) +} + +export function removeMenu(data) { + return request({ + url, + method: 'delete', + data + }) +} + +/** + * 修改菜单 + * @param {Object} data + * @param {Number} id + * @returns + */ +export function updateMenu(data, id) { + return request({ + url: `${url}/${id}`, + method: 'put', + data + }) +} \ No newline at end of file diff --git a/src/api/admin/post.js b/src/api/admin/post.js new file mode 100644 index 0000000..aafdc82 --- /dev/null +++ b/src/api/admin/post.js @@ -0,0 +1,35 @@ +import request from '../../utils/request' + +const url = '/api/v1/post'; + +export function getPost(params) { + return request({ + url, + method: 'get', + params + }) +} + +export function addPost(data) { + return request({ + url, + method: 'post', + data + }) +} + +export function removePost(data) { + return request({ + url, + method: 'delete', + data + }) +} + +export function updatePost(data, id) { + return request({ + url: `${url}/${id}`, + method: 'put', + data + }) +} \ No newline at end of file diff --git a/src/api/admin/role.js b/src/api/admin/role.js new file mode 100644 index 0000000..ec478f5 --- /dev/null +++ b/src/api/admin/role.js @@ -0,0 +1,50 @@ +import request from '../../utils/request'; + +const url = '/api/v1/role'; +export function getRole(params) { + return request({ + url, + method: 'get', + params + }) +} + +export function addRole(data) { + return request({ + url, + method: 'post', + data + }) +} + +export function removeRole(data) { + return request({ + url, + method: 'delete', + data + }) +} + +export function updateRole(data, id) { + return request({ + url: `${url}/${id}`, + method: 'put', + data, + }) +} + +export function updateRoleScoped(data) { + return request({ + url:'/api/v1/roledatascope', + method: 'put', + data + }) +} + +export function getRoleMenuTree(params, roleId) { + return request({ + url:`/api/v1/roleMenuTreeselect/${roleId}`, + method: 'get', + params + }) +} \ No newline at end of file diff --git a/src/api/admin/sys-api.js b/src/api/admin/sys-api.js new file mode 100644 index 0000000..ea12824 --- /dev/null +++ b/src/api/admin/sys-api.js @@ -0,0 +1,35 @@ +import request from '../../utils/request'; + +const url = '/api/v1/sys-api'; + +export function getSysApi(params) { + return request({ + url, + method: 'get', + params + }) +} + +export function addSysApi(data) { + return request({ + url, + method: 'post', + data + }) +} + +export function removeSysApi(data) { + return request({ + url, + method: 'delete', + data + }) +} + +export function updateSysApi(data, id) { + return request({ + url: `${url}/${id}`, + method: 'put', + data, + }) +} \ No newline at end of file diff --git a/src/api/admin/sys-config.js b/src/api/admin/sys-config.js new file mode 100644 index 0000000..01a15f4 --- /dev/null +++ b/src/api/admin/sys-config.js @@ -0,0 +1,35 @@ +import request from '../../utils/request'; + +const url = '/api/v1/config'; + +export function getSysConfig(params) { + return request({ + url, + method: 'get', + params + }) +} + +export function addSysConfig(data) { + return request({ + url, + method: 'post', + data + }) +} + +export function removeSysConfig(data) { + return request({ + url, + method: 'delete', + data + }) +} + +export function updateSysConfig(data, id) { + return request({ + url: `${url}/${id}`, + method: 'put', + data, + }) +} \ No newline at end of file diff --git a/src/api/admin/sys-dept.js b/src/api/admin/sys-dept.js new file mode 100644 index 0000000..1d8a8ea --- /dev/null +++ b/src/api/admin/sys-dept.js @@ -0,0 +1,35 @@ +import request from '../../utils/request'; + +const url = '/api/v1/dept'; + +export function getDept(params) { + return request({ + url, + method: 'get', + params + }) +} + +export function addDept(data) { + return request({ + url, + method: 'post', + data + }) +} + +export function removeDept(data) { + return request({ + url, + method: 'delete', + data + }) +} + +export function updateDept(data, id) { + return request({ + url: `${url}/${id}`, + method: 'put', + data, + }) +} \ No newline at end of file diff --git a/src/api/admin/sys-dict-data.js b/src/api/admin/sys-dict-data.js new file mode 100644 index 0000000..0097b50 --- /dev/null +++ b/src/api/admin/sys-dict-data.js @@ -0,0 +1,35 @@ +import request from '@/utils/request'; + +const url = '/api/v1/dict/data'; + +export function getDictData(params) { + return request({ + url, + method: 'get', + params + }) +} + +export function addDictData(data) { + return request({ + url, + method: 'post', + data + }) +} + +export function updateDictData(data, dictCode) { + return request({ + url: `${url}/${dictCode}`, + method: 'put', + data + }) +} + +export function deleteDictData(data) { + return request({ + url, + method: 'delete', + data + }) +} diff --git a/src/api/admin/sys-dict.js b/src/api/admin/sys-dict.js new file mode 100644 index 0000000..e9200f7 --- /dev/null +++ b/src/api/admin/sys-dict.js @@ -0,0 +1,43 @@ +import request from '../../utils/request'; + +const url = '/api/v1/dict/type'; + +export function getDictType(params) { + return request({ + url, + method: 'get', + params + }) +} + +export function addDictType(data) { + return request({ + url, + method: 'post', + data + }) +} + +export function removeDictType(data) { + return request({ + url, + method: 'delete', + data + }) +} + +export function updateDictType(data, id) { + return request({ + url: `${url}/${id}`, + method: 'put', + data, + }) +} + +// 获取字典选择框列表 +export function optionselect() { + return request({ + url: '/api/v1/dict/type-option-select', + method: 'get' + }) +} diff --git a/src/api/admin/sys-login-log.js b/src/api/admin/sys-login-log.js new file mode 100644 index 0000000..2d3a40f --- /dev/null +++ b/src/api/admin/sys-login-log.js @@ -0,0 +1,19 @@ +import request from '../../utils/request'; + +const url = '/api/v1/sys-login-log'; + +export function getSysLoginLog(params) { + return request({ + url, + method: 'GET', + params + }) +} + +export function removeSysLoginLog(data) { + return request({ + url, + method: 'DELETE', + data + }) +} \ No newline at end of file diff --git a/src/api/admin/sys-opera-log.js b/src/api/admin/sys-opera-log.js new file mode 100644 index 0000000..5e4a014 --- /dev/null +++ b/src/api/admin/sys-opera-log.js @@ -0,0 +1,19 @@ +import request from '../../utils/request'; + +const url = '/api/v1/sys-opera-log'; + +export function getSysOperaLog(params) { + return request({ + url, + method: 'get', + params, + }); +} + +export function removeSysOperaLog(data) { + return request({ + url, + method: 'delete', + data, + }); +} diff --git a/src/api/admin/sys-user.js b/src/api/admin/sys-user.js new file mode 100644 index 0000000..3da6f7f --- /dev/null +++ b/src/api/admin/sys-user.js @@ -0,0 +1,67 @@ +import request from '../../utils/request'; + +const url = '/api/v1/sys-user'; + + +export function getUser(params) { + return request({ + url, + method: 'get', + params + }) +} + +export function getInfo() { + return request({ + url:'/api/v1/getinfo', + method: 'get' + }) +} + +export function addUser(data) { + return request({ + url, + method: 'post', + data + }) +} + +export function removeUser(data) { + return request({ + url, + method: 'delete', + data + }) +} + +export function updateUser(data) { + return request({ + url, + method: 'put', + data, + }) +} + +export function updateUserStatus(data) { + return request({ + url: '/api/v1/user/status', + method: 'put', + data + }) +} + +export function resetUserPwd(data) { + return request({ + url:'/api/v1/user/pwd/reset', + method: 'put', + data + }) +} + +// 获取当前登录用户信息 +export function getCurrentUser(uid) { + return request({ + url: `${url}/${uid}`, + method: 'get' + }) +} \ No newline at end of file diff --git a/src/api/profile/profile.js b/src/api/profile/profile.js new file mode 100644 index 0000000..868e348 --- /dev/null +++ b/src/api/profile/profile.js @@ -0,0 +1,18 @@ +import request from '../../utils/request'; + +// 获取用户信息 +export function getUserProfile() { + return request({ + url: '/api/v1/user/profile', + method: 'get' + }) +} + +// 修改用户密码 +export function putUserPwd(data) { + return request({ + url: '/api/v1/user/pwd/set', + method: 'put', + data + }) +} \ No newline at end of file diff --git a/src/api/sys-job.js b/src/api/sys-job.js new file mode 100644 index 0000000..83e5b5c --- /dev/null +++ b/src/api/sys-job.js @@ -0,0 +1,62 @@ +import request from '@/utils/request' + +// 查询SysJob列表 +export function listSysJob(query) { + return request({ + url: '/api/v1/sysjob', + method: 'get', + params: query + }) +} + +// 查询SysJob详细 +export function getSysJob(jobId) { + return request({ + url: '/api/v1/sysjob/' + jobId, + method: 'get' + }) +} + +// 新增SysJob +export function addSysJob(data) { + return request({ + url: '/api/v1/sysjob', + method: 'post', + data: data + }) +} + +// 修改SysJob +export function updateSysJob(data) { + return request({ + url: '/api/v1/sysjob', + method: 'put', + data: data + }) +} + +// 删除SysJob +export function delSysJob(data) { + return request({ + url: '/api/v1/sysjob', + method: 'delete', + data: data + }) +} + +// 移除SysJob +export function removeJob(jobId) { + return request({ + url: '/api/v1/job/remove/' + jobId, + method: 'get' + }) +} + +// 启动SysJob +export function startJob(jobId) { + return request({ + url: '/api/v1/job/start/' + jobId, + method: 'get' + }) +} + diff --git a/src/api/sys-tools/monitor.js b/src/api/sys-tools/monitor.js new file mode 100644 index 0000000..d3f6f46 --- /dev/null +++ b/src/api/sys-tools/monitor.js @@ -0,0 +1,10 @@ +import request from '../../utils/request' + +const url = '/api/v1/server-monitor'; + +export function getServerMonitor() { + return request({ + url, + method: 'GET', + }) +} \ No newline at end of file diff --git a/src/api/tools/gen.js b/src/api/tools/gen.js new file mode 100644 index 0000000..cc4846c --- /dev/null +++ b/src/api/tools/gen.js @@ -0,0 +1,103 @@ +import request from '@/utils/request' + +// 查询生成表数据 +export function listTable(query) { + return request({ + url: '/api/v1/sys/tables/page', + method: 'get', + params: query + }) +} +// 查询db数据库列表 +export function listDbTable(query) { + return request({ + url: '/api/v1/db/tables/page', + method: 'get', + params: query + }) +} + +// 查询表详细信息 +export function getGenTable(tableId) { + return request({ + url: '/api/v1/sys/tables/info/' + tableId, + method: 'get' + }) +} + +export function getGenTableInfo(tablename) { + return request({ + url: '/api/v1/sys/tables?tableName=' + tablename, + method: 'get' + }) +} + +// 修改代码生成信息 +export function updateGenTable(data) { + return request({ + url: '/api/v1/sys/tables/info', + method: 'put', + data: data + }) +} + +// 导入表 +export function importTable(data) { + return request({ + url: '/api/v1/sys/tables/info', + method: 'post', + params: data + }) +} +// 预览生成代码 +export function previewTable(tableId) { + return request({ + url: '/api/v1/gen/preview/' + tableId, + method: 'get' + }) +} +// 删除表数据 +export function delTable(tableId) { + return request({ + url: '/api/v1/sys/tables/info/' + tableId, + method: 'delete' + }) +} + +// 生成代码到项目 +export function toProjectTable(tableId) { + return request({ + url: '/api/v1/gen/toproject/' + tableId, + method: 'get' + }) +} + +// 生成接口数据到迁移脚本 +export function apiToFile(tableId) { + return request({ + url: '/api/v1/gen/apitofile/' + tableId, + method: 'get' + }) +} + +export function toProjectTableCheckRole(tableId, ischeckrole) { + return request({ + url: '/api/v1/gen/toproject/' + tableId + '?ischeckrole=' + ischeckrole, + method: 'get' + }) +} + +// 生成菜单到数据库 +export function toDBTable(tableId) { + return request({ + url: '/api/v1/gen/todb/' + tableId, + method: 'get' + }) +} + +export function getTableTree() { + return request({ + url: '/api/v1/gen/tabletree', + method: 'get' + }) +} diff --git a/src/components/DeleteModal.vue b/src/components/DeleteModal.vue new file mode 100644 index 0000000..b3d5338 --- /dev/null +++ b/src/components/DeleteModal.vue @@ -0,0 +1,104 @@ + + + + + \ No newline at end of file diff --git a/src/directive/permission/permission.js b/src/directive/permission/permission.js new file mode 100644 index 0000000..59c185d --- /dev/null +++ b/src/directive/permission/permission.js @@ -0,0 +1,22 @@ +import { useUserStore } from '@/store/userInfo'; + +export default { + checkPermission(el, binding) { + const store = useUserStore(); + const { value } = binding; + const all_permission = '*:*:*' + const permissions = store.userInfo && store.userInfo.permissions; + + if (typeof value === 'string') { + const hasPermission = permissions.some((permission) => { + return all_permission === permission || value === permission; + }) + + if (!hasPermission) { + el.parentNode && el.parentNode.removeChild(el); + } + } else { + throw new Error(`请设置操作权限标签值`) + } + } +} \ No newline at end of file diff --git a/src/icons/index.js b/src/icons/index.js new file mode 100644 index 0000000..e69de29 diff --git a/src/icons/svg/api-management.svg b/src/icons/svg/api-management.svg new file mode 100644 index 0000000..7a80c94 --- /dev/null +++ b/src/icons/svg/api-management.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/layout/components/AppMain.vue b/src/layout/components/AppMain.vue new file mode 100644 index 0000000..5541196 --- /dev/null +++ b/src/layout/components/AppMain.vue @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/src/layout/components/Avatar/index.vue b/src/layout/components/Avatar/index.vue new file mode 100644 index 0000000..b4d26e4 --- /dev/null +++ b/src/layout/components/Avatar/index.vue @@ -0,0 +1,76 @@ + + + + + \ No newline at end of file diff --git a/src/layout/components/Menu/Menu.vue b/src/layout/components/Menu/Menu.vue new file mode 100644 index 0000000..1b1cec9 --- /dev/null +++ b/src/layout/components/Menu/Menu.vue @@ -0,0 +1,95 @@ + + + + + + + diff --git a/src/layout/components/Menu/SubMenu.vue b/src/layout/components/Menu/SubMenu.vue new file mode 100644 index 0000000..891977f --- /dev/null +++ b/src/layout/components/Menu/SubMenu.vue @@ -0,0 +1,37 @@ + + + diff --git a/src/layout/components/Navbar.vue b/src/layout/components/Navbar.vue new file mode 100644 index 0000000..255a139 --- /dev/null +++ b/src/layout/components/Navbar.vue @@ -0,0 +1,93 @@ + + + + + \ No newline at end of file diff --git a/src/layout/components/index.js b/src/layout/components/index.js new file mode 100644 index 0000000..8d0b6b7 --- /dev/null +++ b/src/layout/components/index.js @@ -0,0 +1,2 @@ +export { default as AppMain } from './AppMain.vue'; +export { default as Navbar } from './Navbar.vue'; \ No newline at end of file diff --git a/src/layout/index.vue b/src/layout/index.vue new file mode 100644 index 0000000..80c89c6 --- /dev/null +++ b/src/layout/index.vue @@ -0,0 +1,37 @@ + + + + + \ No newline at end of file diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..5b5a400 --- /dev/null +++ b/src/main.js @@ -0,0 +1,39 @@ +import { createApp } from 'vue'; +import { createPinia } from 'pinia'; +import App from './App.vue'; +import ArcoVue from '@arco-design/web-vue'; +import { Message, Modal, Notification } from '@arco-design/web-vue'; +import '@arco-design/web-vue/dist/arco.css'; +import router from './router/'; +import { parseTime } from '@/utils/parseTime'; + +// Directive +import permission from '@/directive/permission/permission'; + +// 引入 Arco 图标库 +import * as ArcoIconModules from '@arco-design/web-vue/es/icon'; + +console.log(import.meta.env); + +// Initialize the Pinia instance +const pinia = createPinia(); +const app = createApp(App); + +app.directive('has', permission.checkPermission); + +// 挂载全局变量 +app.config.globalProperties.message = Message; +app.config.globalProperties.modal = Modal; +app.config.globalProperties.notification = Notification; +app.config.globalProperties.parseTime = parseTime; + +// 挂载全局图标 +for(const name in ArcoIconModules){ + app.component(name,ArcoIconModules[name]) +} + +app.use(ArcoVue); +app.use(router); +app.use(pinia); +app.mount('#app'); + diff --git a/src/router/index.js b/src/router/index.js new file mode 100644 index 0000000..0eaf70e --- /dev/null +++ b/src/router/index.js @@ -0,0 +1,115 @@ +import { createWebHashHistory, createRouter, createWebHistory } from 'vue-router'; +import Layout from '../layout/index.vue'; +import { useUserStore } from '../store/userInfo'; +import { usePermissionStore } from '../store/permission'; +import Watermark from '@/utils/watermark.js'; + +const routes = [ + { + path: '/', + name: '/', + redirect: 'admin', + component: Layout, + children: [ + { + path: '/profile', + name: 'profile', + component: () => import('../views/profile/index.vue'), + meta: { + title: '个人设置', + }, + }, + { + path: '/403', + name: '403', + component: () => import('../views/error-page/403.vue'), + meta: { + title: '找不到页面', + }, + }, + { + hide: true, + path: '/:catchAll(.*)', + component: () => import('../views/error-page/404.vue'), + meta: { + title: '找不到页面', + }, + }, + { + path: '/500', + name: '500', + component: () => import('../views/error-page/500.vue'), + meta: { + title: '找不到页面', + }, + }, + ] + }, + { + path: '/login', + name: 'login', + component: () => import('../views/login/index.vue'), + }, +]; + +const router = createRouter({ + // createWebHashHistory URL 带井号 + // createWebHistory URL 去井号 + history: createWebHistory(), + routes: routes, +}); + +// beforeEach router +router.beforeEach(async (to, from, next) => { + const store = useUserStore(); + + const permissionStore = usePermissionStore(); + + // 获取系统配置信息 + await store.getSysConfig(); + + // 判断用户Token是否获取 + if (to.name !== 'login' && !store.token) { + next({ name: 'login' }); + } else { + // 判断判断权限有无获取 + if (store.token && store.roles.length === 0) { + store.getUserInfo(); + await permissionStore.getMenuRole(); + + permissionStore.addRouters.forEach((route) => { + router.addRoute('/', route); + }); + // next(to.fullPath); + // 如果 addRoute 并未完成,路由守卫会一层一层的执行执行,直到 addRoute 完成,找到对应的路由 + next({ ...to, replace: true }) + } else { + next(); + } + + } +}); + +// afterEach Router +router.afterEach((to) => { + const store = useUserStore(); + + // 修改网页标题 + if (to.name !== 'login') { + document.title = `${to.meta.title} - ${store.sysConfig.sys_app_name}`; + } else { + document.title = store.sysConfig.sys_app_name; + } + + // Vincent 2023004 修复加载水印的bug + if (store.userInfo != undefined){ + if ( store.userInfo.name != undefined ) { + Watermark.set(store.userInfo.name) + } else { + Watermark.out() // 清除水印 + } + } else{ + Watermark.out() // 清除水印 + } +}); +export default router; diff --git a/src/store/permission.js b/src/store/permission.js new file mode 100644 index 0000000..afe7ce8 --- /dev/null +++ b/src/store/permission.js @@ -0,0 +1,60 @@ +import { defineStore } from 'pinia'; +import { getUserMenuRole } from '@/api/admin/login'; + + +const modules = import.meta.glob('../views/**/*.vue'); + +export const usePermissionStore = defineStore('permisson', { + state: () => { + return { + addRouters: [], + menuList: [], + }; + }, + getters: { + getRoutes: (state) => state.addRouters, + }, + actions: { + setMenuList(menus) { + this.menuList = menus; + }, + GenerateRoutes(routeList) { + const routes = []; + + routeList.forEach((item) => { + const route = {}; + // if (item.visible == 0) { + if (item.menuType === 'M' || item.menuType === 'C') { + route.path = item.path; + route.name = item.menuName; + if (item.menuType === 'M') { + route.component = modules[`../views/index.vue`]; + } else if (item.menuType === 'C') { + route.component = modules[`../views${item.component}.vue`] || modules['../views/error-page/888.vue']; + } + route.meta = { + title: item.title, + permission: item.permission, + }; + } + + if (item.children) { + route.children = this.GenerateRoutes(item.children); + } + routes.push(route); + // } + }); + + return routes; + }, + async getMenuRole() { + const res = await getUserMenuRole(); + console.log(res.data); + this.setMenuList(res.data); + this.addRouters = await this.GenerateRoutes(res.data); + }, + ClearMenuList() { + this.menuList = []; + } + }, +}); diff --git a/src/store/userInfo.js b/src/store/userInfo.js new file mode 100644 index 0000000..3c07123 --- /dev/null +++ b/src/store/userInfo.js @@ -0,0 +1,48 @@ +import { defineStore } from 'pinia'; +import { setLocalStorage, getLocalStorage } from '@/utils/storage'; +import { getInfo } from '@/api/admin/sys-user'; +import { getAppConfig } from '@/api/admin/login'; + +export const useUserStore = defineStore('user', { + state: () => { + return { + token: window.sessionStorage.getItem('token') || '', + uid: window.sessionStorage.getItem('uid') || '', + sysConfig: getLocalStorage('sysConfig'), + userInfo: '', + } + }, + getters: { + roles: (state) => state.userInfo.roles || [], + }, + actions: { + setToken(token) { + this.token = token; + + window.sessionStorage.setItem('token', token); + }, + async getUserInfo() { + try { + const res = await getInfo(); + // window.sessionStorage.setItem('uid', res.data.userId); + window.localStorage.setItem('uid', res.data.userId); + this.userInfo = res.data; + } catch (err) { + console.error(err); + } + }, + async getSysConfig() { + try { + const res = await getAppConfig(); + setLocalStorage('sysConfig', res.data); + this.sysConfig = res.data; + } catch (err) { + console.error(err); + } + } + }, + userLogout() { + this.token = null; + this.userInfo = null; + } +}) diff --git a/src/style/dark-theme.scss b/src/style/dark-theme.scss new file mode 100644 index 0000000..d8010dc --- /dev/null +++ b/src/style/dark-theme.scss @@ -0,0 +1,34 @@ +// Dark Theme + +$dark-bg-1: #17171A; +$color-bg-2: #393A3C; +$color-bg-3: #2a2a2b; +$color-bg-4: #313132; +$color-bg-5: #373739; + +$--color-text-1: rgba(255, 255, 255, 0.9); +$--color-text-2: rgba(255, 255, 255, 0.7); +$--color-text-3: rgba(255, 255, 255, 0.5); +$--color-text-4: rgba(255, 255, 255, 0.3); + +body[arco-theme='dark'] { + .navbar { + background-color: $dark-bg-1; + } + .arco-layout-content { + background-color: $color-bg-2 + } + .app-container { + background-color: $color-bg-3; + } + .navbar { + border-bottom: 1px solid $--color-text-4; + .left-side { + // background-color: $color-bg-2; + color: $--color-text-1; + &:hover { + background-color: $color-bg-5; + } + } + } +} \ No newline at end of file diff --git a/src/style/index.scss b/src/style/index.scss new file mode 100644 index 0000000..b091ce6 --- /dev/null +++ b/src/style/index.scss @@ -0,0 +1,88 @@ +body { + // Akiraka 20230508 光标样式 + cursor: -webkit-image-set(url(data:image/png;base64,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) 2x,url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAAEEfUpiAAAAAXNSR0IArs4c6QAAArtJREFUWAntV01rGlEUHWuibcU2TVPTRonJpiL2a1FbaEtpAvobanGnIK4qKQjuhP4GseDWjYuii9CNiyJCN134segiJGlAcKELQWJDFZmeM+0TDRM/ppVuvHCceXfuPXPvfe/dN0qSmmxvb8vn9cvnFWPGFouF/pcHJjIEA/1AoXoTjUZpdfGbyFssFuVAIDDKP0Q34R1DlppuN/D+t+M87Qyy0Wh8VjO6RKVer5cymcyrXq/XUjPahPIxQOMlNQOdmvLf6wxI9SloNVdUKYXb7ZYPDg4+gMgwbYwiQRKcCCedTicdHh4emc3mB9D9EPpxVyWCVqvVgNET4CHwHHADJmCirMDiHnB1ouXCQLUCunq9/gZPrqg+nUK5zN7Rbre7sOVsiLUxhetvEwMJuCmPj4/ZNdYAZR9OyzAgIEmhUJB3d3fts5CMEJAklUrJ8Xicm3zi5hrpAHCUut2uVCqVpEgk8nV9ff1FOBz+AiKmdqEoEfh8PtnpdL6G1X2Ae+AlwFQmikKQTqeTsBQFZOiMbmIKZF8yGo13cbUBM1WfzkL4Js3OgmRx1ViB4XnmLvxvM8FAVrCpe/1+/zSfz7O/XAO4GGduD/CZWXiQbYq2srOzw/O+Xy6X30O/CvALZq6BMAC7CIAdhXC5XHKlUpFrtdrHra2t27AxAnOZJtUARCA2m03OZrMyDt5SMBh0Igi2/+H1g6E2mSobtshQKCQ5HI5H+Jb9dnZ2dpRIJNjteOr/VSBiXlmBO5iCE/RgJZVYLCZ5vd5KMpncR5u9brVa1/7I6g2IyWQy5HK5d36//xMcToGxPVshHfMzmAKPxyM3m82fOAj2YM/efhNgpmaAhyZbNqO8BVA3cqhgrEm4yjc6nc73arW6j/tnHANzW3TgVkRMAdcCM+H/DOr4iUD0gYUsKrCowFwr8AukF+p8blYsTwAAAABJRU5ErkJggg==) 1x) 4 4,auto !important; +} +a,button { + // Akiraka 20230508 光标选择样式 + cursor: -webkit-image-set(url(data:image/png;base64,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) 2x,url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAAEEfUpiAAAAAXNSR0IArs4c6QAAA9xJREFUWAntV8tLVFEYnzvvpzTazIijprZRpqRFhFLUooUglSFDs2vXInAxuBaX9RcEbVNBsHAlYtbGRUK4CnMhLoxQQ8lkZGZ0Xvf2+13m3O6dmYujhAT2wcc95zvf45zvdc61WEzABbpVW1PKAEJIECWHw5HERBIE4/fw8FDRU2w6HRY7VkqSJD3Sc9Q99lN3OBxWotHoR0j92SdV2Gy2h8IWvyBdIv08oaWlpQT33Kq0adjp7Ozs54GBgXxjY2OfgbG1tXVhaWlJO0Rvb++xYFA1bG1tPZ6fny8J4sHBgTbWhyOCPSRKAFmW34J5Twic/1dCvEZxsDRMe85i3kefMvB2u30ACtxAG1B/3pp6paampufIlAIVaD4tD46OjhTsqgBJn15aHyhpf3//E5JV2t7e1tNVfrfbbfF4PMwygwK9MjEO+ny+F8lkspjJZBRiKpVS4vF4HikbB5NTMPJrdi7SeW5HmYeWi2U0FBxoFx7oqEpwIw/SCNtONpv9gsXTOQ0hvM/cYfuBsL9Se+W8KmEgqyWK1+sNQIDdsIpPKKpcYPy13Jibm9sZHBzMIoW/d3R0vMcaG7cpOJubm4s4/yaPoIfJyUmlUCgofr9/GNKVRjWF0UQiUTg+PtbLGsaBQGAU3DxSTfDDgS83NjYMQvoJFDyDpKkCnr2jra1tSy8kxsvLy4zKbaDpEbCmFtBN9ITc+vq6WomsxpWVFaW9vf0n1jvJpAfN4zoiy/U6Svea1WoNkg4H/sJnFfiVU6AGtRRwkdukIrFd9nGWs9bPMf4P/4gHzIJYuT0GU4rFYmr7WVtbkzEXWMn71+d29LYrrPPFxUVlenqa91sGV1QUltgc6j3EmTeGruZ9IC5b8VTDrX0PGvkSE6l+JgOmfUGnjSes6vxo2B9wh1uKxeIrPIcyGJdyudwb3ME/wM+aEyE63Y1QNsxTOSKRSGcwGLwDdz8RHuATo7u7W4YxtU319PTIu7u7attBmOTx8XFlbGyshJ62B8+1UA/wVGGi8caurq5vExMTSjqdVoaGhvLob1XvHdEoa335zGxoaBihLmCVB0EzBTJHnE7nMJ94U1NTci0DJ9G4gfL9EYa+ekJt2BAFKHg3FAot9Pf354XLTzLMdfIiR2SXyzUIHZeBp/IA+FVgKHjBx6BoBN7IzczM1GOfIStgA+8ge6OswzQHTBcgKIBJxDhexUb68I/xFOMY/gWq3IobOY37bxXP3NdY59W1CTwEmt5C9WwA8moW06AXyNrnc4cvd8oTWWosO/7fpIEpYBYoyhHD2lDvBmpLG8vrTPVupvji0H8DAsFwgXvDpDQAAAAASUVORK5CYII=) 1x) 9 9,auto !important +} +input,textarea { + // Akiraka 20230508 光标输入样式 + cursor: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAAEEfUpiAAAAAXNSR0IArs4c6QAAAupJREFUWAntl89vElEQx0EopAl6ESm2KgmcTLwoPWBjYojEpHeS3jnwH3jg5r/jwRN/gQd+hDsXLiWNgm0QSAUbEFjns77d7MKubCMYD0wymTcz35333sy8x8Pnc6NsNqvZfM1m024Q71sbwqZcXl4CT1qNpnJHWZ+LPLQiPI/3VXzzAyOkbigWiw9arRbjgIn4t4MkCVxepG0JyrlvNdp20ev18D10AwQGg4FPtjqzAvwWhdQ+E74r/NFi3/LQugTrVBHZ8fdwOPwB42QyOTs4OGBpIyvoT+OIOF+0220NZiyMbYWCK5bfBmY6H4/HhvtcBo6zuwXQP4xGo0YAV+kW4CgWi30ulUr6hzLuX11dPRLly3IktyTSzwRfqA/oGBpgrvSdWJOBwGKx6I9Go+tyufwKiS7feL4owtPp9LpWq2mZTEZDokuA8JqJTTczPU6lUmdSfw2JLux5BUSiP54SAKl0Ed4pMJvNhgRAymeus9vuJEv8oCRO9ynp1vI+twCzUCj0hoBK2u4xy0SOAdh/UO6BdwCVZAVu5waYjfY0oXg8rnU6HV2iC2LPhlKKU1SAL4W5DL4J3xfmwq4J/xS2kVMAfQuCIj8cXyrAsSYPrGRH/1kGnIrotERwFNVgMBSWoho+w4bd8GHbCNGah/Qz55seLxQKWrfb1SU6dgicsGPP/81KCHgk/DqRSBQqlcqnarWqT8p9iY4dv8JtfAGkmfPEpczBPOa1xa7Vq+tY2fGD81pa/bdX8GuJ1HKoqe0PYfPNIWMIHftUGKxn8rxSFZHUxqXUF/LaMieRLPj8fv8TMXwVXrmuTOAGBiyAn7fTpRKcKvuta8+xug1Rhv7JyYm8p7mf5ZYWiY5dGP9WiMaKzOfzATuv1+taLpfT0um0xn8DdOz4wQmD3yjR3UmeJ0w0HA5vGo1GLZ/Pv0eiY1fPl6RgwXsir03IjviDc09JOn0iTMNRdyYk1o0wbyjk1sohsXe0uQz8AtSlOGRROrZeAAAAAElFTkSuQmCC) !important +} +*::before { + margin: 0; + padding: 0; +} +*, *::before, *::after { + box-sizing: border-box; +} +img { + vertical-align: middle; +} +ul { + padding: 0px 0px 0px 16px; +} +// li { +// list-style: none; +// } + +// main-container 全局样式 +.app-container { + flex: 1; + padding: 20px 20px 12px 20px; + background-color: #fff; + border-radius: 5px; +} + +// 表格操作栏样式 +.arco-table-th:last-child .arco-table-th-item-title { + margin-left: 16px; +} + +// 数字输入框样式 +.arco-input-number .arco-input { + text-align: center; +} + +// Table 操作栏样式覆盖 +// .arco-table-th:last-child .arco-table-cell { +// margin-left: 15px; +// } + +// 滚动条整体部分 +::-webkit-scrollbar { + width: 6px; + height: 6px; + background-color: transparent; +} + +// 滚动条外层轨道 +::-webkit-scrollbar-track { + border-radius: 10px; +} + +// 滚动条滑块 +::-webkit-scrollbar-thumb { + border-radius: 5px; + background-color: rgba(157, 165, 183, 0.4); +} + +::-webkit-scrollbar-thumb:hover { + background-color: rgba(157, 165, 183, 0.7); +} + +// 链接标签样式 +a { + text-decoration: none; + color: #165DFF; +} + +a:hover { + color: #4080FF; +} + +// 表格操作栏样式 +.action { + margin-bottom: 16px; +} \ No newline at end of file diff --git a/src/style/transition.scss b/src/style/transition.scss new file mode 100644 index 0000000..4f1a847 --- /dev/null +++ b/src/style/transition.scss @@ -0,0 +1,28 @@ +// global transition css + +/* fade */ +.fade-enter-active, +.fade-leave-active { + transition: opacity 0.28s; +} + +.fade-enter, +.fade-leave-active { + opacity: 0; +} + +/* fade-transform */ +.fade-transform-leave-active, +.fade-transform-enter-active { + transition: all .5s; +} + +.fade-transform-enter-from { + opacity: 0; + transform: translateX(-30px); +} + +.fade-transform-leave-to { + opacity: 0; + transform: translateX(30px); +} \ No newline at end of file diff --git a/src/style/variables.scss b/src/style/variables.scss new file mode 100644 index 0000000..54116a3 --- /dev/null +++ b/src/style/variables.scss @@ -0,0 +1,3 @@ +// base color +$primary-font-color: #1d2129; +$secondary-font-color: #86909c; \ No newline at end of file diff --git a/src/utils/parseTime.js b/src/utils/parseTime.js new file mode 100644 index 0000000..662297f --- /dev/null +++ b/src/utils/parseTime.js @@ -0,0 +1,41 @@ +// 日期格式化 +export function parseTime(time, pattern) { + if (arguments.length === 0 || !time) { + return null + } + if (time.indexOf('01-01-01') > -1) { + return '-' + } + const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}' + let date + if (typeof time === 'object') { + date = time + } else { + if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) { + time = parseInt(time) + } + if ((typeof time === 'number') && (time.toString().length === 10)) { + time = time * 1000 + } + date = new Date(time) + } + const formatObj = { + y: date.getFullYear(), + m: date.getMonth() + 1, + d: date.getDate(), + h: date.getHours(), + i: date.getMinutes(), + s: date.getSeconds(), + a: date.getDay() + } + const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { + let value = formatObj[key] + // Note: getDay() returns 0 on Sunday + if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] } + if (result.length > 0 && value < 10) { + value = '0' + value + } + return value || 0 + }) + return time_str +} \ No newline at end of file diff --git a/src/utils/request.js b/src/utils/request.js new file mode 100644 index 0000000..0cf2e4a --- /dev/null +++ b/src/utils/request.js @@ -0,0 +1,58 @@ +import axios from 'axios'; +import { Message } from '@arco-design/web-vue'; +import { useUserStore } from '../store/userInfo' + +// create an axios instance +console.log("________"+import.meta.env.VITE_BASE_URL) +const service = axios.create({ + baseURL:import.meta.env.VITE_BASE_URL, + timeout: 8000, +}); + +// request interceptor +service.interceptors.request.use( + (config) => { + // Store 必须在拦截器内部导入,在外部导入会显示 Pinia 未初始化 + const store = useUserStore(); + // 设置请求头部 Authorization + if (store.token) { + config.headers['Authorization'] = 'Bearer ' + store.token; + config.headers['Content-Type'] = 'application/json' + } + return config; + }, + (error) => { + console.error(error); + return Promise.reject(error); + } +); + +// response interceptor +service.interceptors.response.use( + (response) => { + return response.data; + }, + (error) => { + const store = useUserStore(); + const { code, msg } = error.response.data; + // 如果过期则退出登录 + if (code === 401) { + Message.error({ + content: 'Token 已过期, 请重新登陆', + duration: 3000 + }); + // 重定向路由到登陆页面 + store.userLogout(); + // Akiraka 20230410 重定向到登录页面 + return router.push('/login'); + } else { + Message.error({ + content: error.message, + duration: 3000 + }) + return Promise.reject(msg); + } + } +); + +export default service; \ No newline at end of file diff --git a/src/utils/storage.js b/src/utils/storage.js new file mode 100644 index 0000000..14f22cb --- /dev/null +++ b/src/utils/storage.js @@ -0,0 +1,41 @@ +// LocalStorage + +/** + * 存储LocalStorage + * @param {string, Object} name + * @param {*} value + */ +export const setLocalStorage = (name, value) => { + if (!name) throw new Error('name must be specified'); + if (typeof value !== 'string') { + value = JSON.stringify(value); + } + window.localStorage.setItem(name, value); +} + +/** + * 获取LocalStorage + * @param {string, Object} name + * @returns + */ +export const getLocalStorage = (name) => { + if(!name) throw new Error('name must be specified'); + const value = window.localStorage.getItem(name); + return JSON.parse(value); +} + +/** + * 移除指定name + * @param {*} name + */ +export const removeLocalStorage = (name) => { + if (!name) throw new Error('name must be specified'); + window.localStorage.removeItem(name); +} + +/** + * 清空所有LocalStorage + */ +export const clearLocalStorage = () => { + window.localStorage.clear(); +} \ No newline at end of file diff --git a/src/utils/watermark.js b/src/utils/watermark.js new file mode 100644 index 0000000..6f07922 --- /dev/null +++ b/src/utils/watermark.js @@ -0,0 +1,60 @@ +let watermark = {} + +let setWatermark = (str) => { + let id = '1.23452384164.123412415' + + if (document.getElementById(id) !== null) { + document.body.removeChild(document.getElementById(id)) + } + + let can = document.createElement('canvas') + can.width = 200 + can.height = 120 + + let cans = can.getContext('2d') + cans.rotate(-15 * Math.PI / 150) + cans.font = '18px Vedana' + cans.fillStyle = 'rgba(200, 200, 200, 0.20)' + cans.textAlign = 'left' + cans.textBaseline = 'Middle' + cans.fillText(str, can.width / 8, can.height / 2) + + let div = document.createElement('div') + div.id = id + div.style.pointerEvents = 'none' + div.style.top = '35px' + div.style.left = '200px' + div.style.position = 'fixed' + div.style.zIndex = '100000' + div.style.width = document.documentElement.clientWidth + 'px' + div.style.height = document.documentElement.clientHeight + 'px' + div.style.background = 'url(' + can.toDataURL('image/png') + ') left top repeat' + document.body.appendChild(div) + return id +} + +// 该方法只允许调用一次 +watermark.set = (str) => { + let id = setWatermark(str) + setInterval(() => { + if (document.getElementById(id) === null) { + id = setWatermark(str) + } + }, 500) + window.onresize = () => { + setWatermark(str) + } +} + +const outWatermark = (id) => { + if (document.getElementById(id) !== null) { + const div = document.getElementById(id) + div.style.display = 'none' + } +} +watermark.out = () => { + const str = '1.23452384164.123412415' + outWatermark(str) +} + +export default watermark \ No newline at end of file diff --git a/src/views/admin/dict/data.vue b/src/views/admin/dict/data.vue new file mode 100644 index 0000000..5a4dbef --- /dev/null +++ b/src/views/admin/dict/data.vue @@ -0,0 +1,253 @@ + + + + + diff --git a/src/views/admin/dict/index.vue b/src/views/admin/dict/index.vue new file mode 100644 index 0000000..5a07a07 --- /dev/null +++ b/src/views/admin/dict/index.vue @@ -0,0 +1,268 @@ + + + + + diff --git a/src/views/admin/sys-api/index.vue b/src/views/admin/sys-api/index.vue new file mode 100644 index 0000000..7032a2e --- /dev/null +++ b/src/views/admin/sys-api/index.vue @@ -0,0 +1,254 @@ + + + + + diff --git a/src/views/admin/sys-config/index.vue b/src/views/admin/sys-config/index.vue new file mode 100644 index 0000000..5f6a8bf --- /dev/null +++ b/src/views/admin/sys-config/index.vue @@ -0,0 +1,328 @@ + + + + + diff --git a/src/views/admin/sys-dept/index.vue b/src/views/admin/sys-dept/index.vue new file mode 100644 index 0000000..1e067a0 --- /dev/null +++ b/src/views/admin/sys-dept/index.vue @@ -0,0 +1,266 @@ + + + + + diff --git a/src/views/admin/sys-login-log/index.vue b/src/views/admin/sys-login-log/index.vue new file mode 100644 index 0000000..4477657 --- /dev/null +++ b/src/views/admin/sys-login-log/index.vue @@ -0,0 +1,169 @@ + + + + + diff --git a/src/views/admin/sys-menu/index.vue b/src/views/admin/sys-menu/index.vue new file mode 100644 index 0000000..ba3e350 --- /dev/null +++ b/src/views/admin/sys-menu/index.vue @@ -0,0 +1,350 @@ + + + + + diff --git a/src/views/admin/sys-oper-log/index.vue b/src/views/admin/sys-oper-log/index.vue new file mode 100644 index 0000000..8aed65c --- /dev/null +++ b/src/views/admin/sys-oper-log/index.vue @@ -0,0 +1,185 @@ + + + + + diff --git a/src/views/admin/sys-post/index.vue b/src/views/admin/sys-post/index.vue new file mode 100644 index 0000000..e0b6184 --- /dev/null +++ b/src/views/admin/sys-post/index.vue @@ -0,0 +1,289 @@ + + + + + diff --git a/src/views/admin/sys-role/index.vue b/src/views/admin/sys-role/index.vue new file mode 100644 index 0000000..f27fed9 --- /dev/null +++ b/src/views/admin/sys-role/index.vue @@ -0,0 +1,382 @@ + + + + + diff --git a/src/views/admin/sys-set/index.vue b/src/views/admin/sys-set/index.vue new file mode 100644 index 0000000..5840b41 --- /dev/null +++ b/src/views/admin/sys-set/index.vue @@ -0,0 +1,77 @@ + + + + + diff --git a/src/views/admin/sys-user/components/TreeDept.vue b/src/views/admin/sys-user/components/TreeDept.vue new file mode 100644 index 0000000..433c25f --- /dev/null +++ b/src/views/admin/sys-user/components/TreeDept.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/src/views/admin/sys-user/index.vue b/src/views/admin/sys-user/index.vue new file mode 100644 index 0000000..61145f3 --- /dev/null +++ b/src/views/admin/sys-user/index.vue @@ -0,0 +1,621 @@ + + + + + diff --git a/src/views/dev-tools/gen/editTable.vue b/src/views/dev-tools/gen/editTable.vue new file mode 100644 index 0000000..c5cc52d --- /dev/null +++ b/src/views/dev-tools/gen/editTable.vue @@ -0,0 +1,410 @@ + + + + + diff --git a/src/views/dev-tools/gen/importTable.vue b/src/views/dev-tools/gen/importTable.vue new file mode 100644 index 0000000..d592fc8 --- /dev/null +++ b/src/views/dev-tools/gen/importTable.vue @@ -0,0 +1,145 @@ + + + \ No newline at end of file diff --git a/src/views/dev-tools/gen/index.vue b/src/views/dev-tools/gen/index.vue new file mode 100644 index 0000000..1b57cb5 --- /dev/null +++ b/src/views/dev-tools/gen/index.vue @@ -0,0 +1,270 @@ + + + + + diff --git a/src/views/dev-tools/swagger/index.vue b/src/views/dev-tools/swagger/index.vue new file mode 100644 index 0000000..2cbea54 --- /dev/null +++ b/src/views/dev-tools/swagger/index.vue @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/src/views/error-page/403.vue b/src/views/error-page/403.vue new file mode 100644 index 0000000..7f291e2 --- /dev/null +++ b/src/views/error-page/403.vue @@ -0,0 +1,25 @@ + + + \ No newline at end of file diff --git a/src/views/error-page/404.vue b/src/views/error-page/404.vue new file mode 100644 index 0000000..cc894f2 --- /dev/null +++ b/src/views/error-page/404.vue @@ -0,0 +1,25 @@ + + + \ No newline at end of file diff --git a/src/views/error-page/500.vue b/src/views/error-page/500.vue new file mode 100644 index 0000000..038a276 --- /dev/null +++ b/src/views/error-page/500.vue @@ -0,0 +1,25 @@ + + + \ No newline at end of file diff --git a/src/views/error-page/888.vue b/src/views/error-page/888.vue new file mode 100644 index 0000000..9b9f6bb --- /dev/null +++ b/src/views/error-page/888.vue @@ -0,0 +1,19 @@ + + + \ No newline at end of file diff --git a/src/views/index.vue b/src/views/index.vue new file mode 100644 index 0000000..ba32c22 --- /dev/null +++ b/src/views/index.vue @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/src/views/login/index.vue b/src/views/login/index.vue new file mode 100644 index 0000000..41ddfb1 --- /dev/null +++ b/src/views/login/index.vue @@ -0,0 +1,290 @@ + + + + + diff --git a/src/views/profile/api-management.svg b/src/views/profile/api-management.svg new file mode 100644 index 0000000..7a80c94 --- /dev/null +++ b/src/views/profile/api-management.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/views/profile/index.vue b/src/views/profile/index.vue new file mode 100644 index 0000000..b2810cb --- /dev/null +++ b/src/views/profile/index.vue @@ -0,0 +1,234 @@ + + + + + diff --git a/src/views/schedule/index.vue b/src/views/schedule/index.vue new file mode 100644 index 0000000..fd84683 --- /dev/null +++ b/src/views/schedule/index.vue @@ -0,0 +1,277 @@ + + + + + diff --git a/src/views/sys-tools/monitor/index.vue b/src/views/sys-tools/monitor/index.vue new file mode 100644 index 0000000..eadedf1 --- /dev/null +++ b/src/views/sys-tools/monitor/index.vue @@ -0,0 +1,160 @@ + + + + + diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..9b45697 --- /dev/null +++ b/vite.config.js @@ -0,0 +1,51 @@ +import { join } from 'path' +import { defineConfig } from 'vite'; +import { viteMockServe } from 'vite-plugin-mock'; +import vue from '@vitejs/plugin-vue'; +import svgLoader from 'vite-svg-loader'; +import { VuetifyResolver } from 'unplugin-vue-components/resolvers'; +import Components from 'unplugin-vue-components/vite'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + viteMockServe({ + mockPath: '/mock', + }), + svgLoader(), + viteMockServe({ + mockPath: '/mock', + }), + Components({ + resolvers: [VuetifyResolver()], + include: [/\.vue$/, /\.vue\?vue/, /\.md$/], + }), + ], + resolve: { + alias: { + '@': join(__dirname, 'src'), + } + }, + server: { + host: true, + port: 1798, + //secure: false, + proxy: { + '/api': { + target: 'https://vue3.go-admin.dev', + changeOrigin: true, //开启跨域 + rewrite: (path) => path.replace(/^\/api/, '') + } + } + }, + // 引入全局scss变量 + css: { + preprocessorOptions: { + scss: { + additionalData: `@import "@/style/variables.scss";` + } + } + }, + publicDir: '/public' +});