├── .gitignore
├── LICENSE
├── README.md
├── index.html
├── package.json
├── public
└── favicon.ico
├── src
├── App.vue
├── api
│ ├── common
│ │ └── upload_file.js
│ ├── data-dictionary
│ │ └── province_city.js
│ ├── report-api
│ │ └── report.js
│ └── system-setting
│ │ ├── auth.js
│ │ ├── button.js
│ │ ├── captcha.js
│ │ ├── org_post_members.js
│ │ ├── organization.js
│ │ ├── system_menu.js
│ │ └── user.js
├── assets
│ ├── images
│ │ ├── bg1.png
│ │ ├── bg2.png
│ │ ├── bg3.png
│ │ ├── full-icon-0.png
│ │ ├── full-icon-1.png
│ │ ├── logo-min.jpg
│ │ ├── logo.png
│ │ ├── split_flag.png
│ │ └── system_logo.png
│ └── logo.png
├── auto-imports.d.ts
├── components.d.ts
├── components
│ ├── common
│ │ ├── children_table.vue
│ │ ├── children_table_plus.vue
│ │ ├── delete_data_dialog.vue
│ │ ├── group_panel.vue
│ │ ├── iframe.vue
│ │ ├── image.vue
│ │ ├── paging.vue
│ │ ├── seekbar_for_drawer.vue
│ │ ├── select_button.vue
│ │ ├── select_org_post.vue
│ │ ├── select_province_city.vue
│ │ ├── select_sys_menu.vue
│ │ ├── select_user.vue
│ │ ├── split.vue
│ │ ├── table_header1.vue
│ │ ├── table_header2.vue
│ │ ├── tags2.vue
│ │ └── upload_file.vue
│ ├── data-dictionary
│ │ └── province-city
│ │ │ ├── create_edit.vue
│ │ │ └── index.vue
│ ├── report
│ │ └── demo
│ │ │ ├── employees_index.vue
│ │ │ └── train_timetable.vue
│ └── system-setting
│ │ ├── auth-analysis
│ │ └── index.vue
│ │ ├── auth-assignment
│ │ └── index.vue
│ │ ├── button
│ │ ├── create_edit.vue
│ │ └── index.vue
│ │ ├── layout
│ │ ├── header_banner.vue
│ │ ├── left_menu.vue
│ │ └── tabs.vue
│ │ ├── login-form
│ │ ├── carouse.vue
│ │ ├── copy_right.vue
│ │ ├── form.vue
│ │ └── title.vue
│ │ ├── organization-members
│ │ ├── create_edit.vue
│ │ └── index.vue
│ │ ├── organization
│ │ ├── create_edit.vue
│ │ └── index.vue
│ │ ├── system-menu
│ │ ├── create_edit.vue
│ │ └── index.vue
│ │ └── user
│ │ ├── create_edit.vue
│ │ ├── index.vue
│ │ └── profile.vue
├── config
│ └── index.js
├── index.css
├── libs
│ ├── api_request.js
│ ├── axios.js
│ ├── common_func.js
│ └── util.js
├── main.js
├── router
│ └── index.js
├── store
│ └── system-setting
│ │ ├── header_banner.js
│ │ ├── index.js
│ │ ├── layout.js
│ │ ├── menu.js
│ │ ├── reload.js
│ │ ├── route.js
│ │ ├── tabs.js
│ │ └── user.js
└── views
│ ├── data-dictionary
│ └── province_city.vue
│ ├── home
│ └── index.vue
│ ├── layout
│ └── main.vue
│ ├── statistical-report
│ ├── employees.vue
│ └── train_timetable.vue
│ └── system-setting
│ ├── auth_analysis.vue
│ ├── auth_assignment.vue
│ ├── blank_page.vue
│ ├── button_cn_en.vue
│ ├── login.vue
│ ├── org_members.vue
│ ├── organization.vue
│ ├── sys_menu.vue
│ └── user.vue
└── vite.config.mjs
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | /tests/e2e/videos/
6 | /tests/e2e/screenshots/
7 |
8 | /src/auto-imports.d.ts
9 | /src/components.d.ts
10 | src/auto-imports.d.ts
11 | src/components.d.ts
12 | ./package-lock.json
13 | # local env files
14 | .env.local
15 | .env.*.local
16 |
17 | # Log files
18 | npm-debug.log*
19 | yarn-debug.log*
20 | yarn-error.log*
21 |
22 | # Editor directories and files
23 | .idea
24 | .vscode
25 | *.suo
26 | *.ntvs*
27 | *.njsproj
28 | *.sln
29 | *.sw*
30 |
31 | build/env.js
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 张奇峰
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, 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,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### GinSkeleton-Admin2 (前端部分)
2 | > 基于 vue3.x + vite5.x+ javascript + elementPlus + pinia + vue-router4.x + axios 等最新技术栈构建的全新后台管理系统.
3 |
4 |
5 | ### [在线文档](https://www.yuque.com/xiaofensinixidaouxiang/qmanaq/qmucb4)
6 | > 文档包含了最主要的使用功能说明、界面效果图、演示地址等.
7 |
8 |
9 | #### 更新日志
10 | **v2.1.00 2024-12-28**
11 | - 1.界面中相关的树形组件样式改进,增加垂直节点之间的连接接线显示.
12 | - 2.前端缓存启用 cookie 存储,改为 localStorage 存储, 避免安全扫描软件容易获取 cookie 的问题.
13 | - 3.项目依赖包更细至最新版.
14 | - 4.本版本需要搭配 **[gin-skeleton-admin2-backend](https://gitee.com/daitougege/gin-skeleton-admin2-backend)** ≥ v2.1.00 .
15 |
16 |
17 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ginskeleton-admin2-frontend",
3 | "version": "v2.0.00",
4 | "type": "module",
5 | "scripts": {
6 | "dev": "vite --mode dev",
7 | "build": "vite build --mode pro",
8 | "build:dev": "vite build --mode dev"
9 | },
10 | "dependencies": {
11 | "@element-plus/icons-vue": "^2.3.1",
12 | "axios": "^1.7.9",
13 | "default-passive-events": "^2.0.0",
14 | "element-plus": "^2.9.1",
15 | "element-tree-line": "^0.2.1",
16 | "pinia": "^2.3.0",
17 | "pinia-plugin-persist": "^1.0.0",
18 | "qs": "^6.13.1",
19 | "screenfull": "^6.0.2",
20 | "unplugin-icons": "^0.22.0",
21 | "vue": "^3.5.13",
22 | "vue-router": "^4.5.0"
23 | },
24 | "devDependencies": {
25 | "@babel/cli": "^7.26.4",
26 | "@babel/core": "^7.26.0",
27 | "@babel/runtime": "^7.26.0",
28 | "@vitejs/plugin-vue": "^5.2.1",
29 | "@vue/compiler-sfc": "^3.5.13",
30 | "babel-plugin-import": "^1.13.8",
31 | "unplugin-auto-import": "^0.19.0",
32 | "unplugin-vue-components": "^0.28.0",
33 | "vite": "5.4.11",
34 | "vite-plugin-imp": "^2.4.0",
35 | "vite-plugin-inspect": "^0.8.9"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qifengzhang007/ginskeleton-admin2-frontend/e6ea14c8da25479e7a097eed14948e9b4e7d6e6e/public/favicon.ico
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
25 |
26 |
--------------------------------------------------------------------------------
/src/api/common/upload_file.js:
--------------------------------------------------------------------------------
1 | import axios from '@/libs/api_request'
2 |
3 | export const uploadFiles = (data) => {
4 | return axios.post('/upload/files', data)
5 | }
--------------------------------------------------------------------------------
/src/api/data-dictionary/province_city.js:
--------------------------------------------------------------------------------
1 | import axios from '@/libs/api_request'
2 |
3 | export const list = (params) => {
4 | return axios.get('/province_city/list',params)
5 | }
6 |
7 | export const create = (data) => {
8 | return axios.post('/province_city/create',data)
9 | }
10 |
11 | export const edit = (data) => {
12 | return axios.post('/province_city/edit',data)
13 | }
14 |
15 | export const destroy = (id) => {
16 | return axios.post('/province_city/destroy',{id: parseInt(id)})
17 | }
18 |
19 | // 左侧数据获取接口(传递fid查询子级数据)
20 | export const getSubListByFid = (fid) => {
21 | return axios.get('/province_city/get_sublist',{fid:fid})
22 | }
23 |
--------------------------------------------------------------------------------
/src/api/report-api/report.js:
--------------------------------------------------------------------------------
1 | import commonFunc from '@/libs/common_func'
2 |
3 |
4 | // 集成的地方三方报表对应的接口可以全部设置在这里
5 | // 一个系统的报表数量总体来讲是有限可控的,因此可以集中、一次性管理
6 | // 关于报表连接安全性问题,提供以下两种方式供参考
7 | // 1.前端可以访问本系统后端的路由地址(加载token校验中间件),然后代理访问对应的报表真实地址
8 | // 2.直接访问报表系统,token鉴权认证等都通过报表系统和前端对接完成
9 |
10 | export default {
11 | name: 'ReportSet',
12 |
13 | // 列车时刻表
14 | trainTimetable: {
15 | reportId: "reportTrainTrainTimetable", //每个需要使用iframe渲染的报表必须设置唯一的报表id
16 | reportUrl: commonFunc.getReportServerIp() + "/jmreport/view/737519583182499840"
17 | },
18 |
19 | // 员工基本信息表
20 | employees: {
21 | reportId: "reportEmployees", //每个需要使用iframe渲染的报表必须设置唯一的报表id
22 | reportUrl: commonFunc.getReportServerIp() + "/jmreport/view/737128175057547264"
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/api/system-setting/auth.js:
--------------------------------------------------------------------------------
1 | import axios from '@/libs/api_request'
2 |
3 | // 权限分析界面,带岗位用户列表查询
4 | export const user_list_with_post = (params) => {
5 | return axios.get('/auth_analysis/user_list_with_post', params)
6 | }
7 |
8 | // 权限分析界面,根据用户id查询已拥有的所有权限
9 | export const has_auth_list = (id) => {
10 | return axios.get('/auth_analysis/has_auth_list', {id: id})
11 | }
12 |
13 | // 查询打开的菜单对应的页面具有的按钮列表
14 | export const view_button_list = (menuId) => {
15 | return axios.get('/users/has_view_button_list', {menu_id: menuId})
16 | }
17 |
18 | // 根据接口查询拥有的按钮元素权限与页面定义的按钮对比,最终显示拥有权限的按钮元素
19 | export const show_button = (hasButtonList, curButtonList) => {
20 | for (const key in curButtonList) {
21 | curButtonList[key] = hasButtonList.some((value, index) => {
22 | return value.en_name === curButtonList[key];
23 | })
24 | }
25 | }
26 |
27 |
28 |
29 | /* ↓↓↓↓↓ 权限分配、分析界面相关的接口 ↓↓↓↓↓ */
30 |
31 | // 为组织机构(部门、岗位)分配菜单、按钮权限
32 | export const assignMenuToOrg = (data) => {
33 | return axios.post_raw('/system_menu/assgin_to_org', data)
34 | }
35 |
36 | // 删除已分配权限给组织机构的菜单、按钮权限
37 | export const delMenuAuthFromOrg = (data) => {
38 | return axios.post('/system_menu/del_auth_from_org', data)
39 | }
40 |
41 | // 待分配权限列表(全部可被用于分配的权限列表)
42 | export const getAllSystemMenuTree = () => {
43 | return axios.get('/system_menu/all_list', {})
44 | }
45 | // 已分配给部门、岗位的菜单、按钮权限列表
46 | export const getAssignedSystemMenuTree = (orgPostId) => {
47 | return axios.get('/system_menu/assgined_list', {org_post_id: orgPostId})
48 | }
49 |
--------------------------------------------------------------------------------
/src/api/system-setting/button.js:
--------------------------------------------------------------------------------
1 | import axios from '@/libs/api_request'
2 |
3 | // 查询
4 | export const list = (params) => {
5 | return axios.get('/button/list', params)
6 | }
7 |
8 | // 新增
9 | export const create = (data) => {
10 | return axios.post('/button/create', data)
11 | }
12 |
13 | // 修改
14 | export const edit = (data) => {
15 | return axios.post('/button/edit', data)
16 | }
17 |
18 | // 删除
19 | export const destroy = (id) => {
20 | return axios.post('/button/destroy', {id: id})
21 | }
22 |
--------------------------------------------------------------------------------
/src/api/system-setting/captcha.js:
--------------------------------------------------------------------------------
1 | import axios from '@/libs/api_request'
2 |
3 | // 获取验证码ID和图片地址
4 | export const getCaptchaInfo = () => {
5 | return axios.captchaGet('/captcha/')
6 | }
7 |
8 | export const getCaptchaServerPre = () => {
9 | return axios.captchaGet('/captcha/')
10 | }
11 |
12 | //根据 获取验证码ID获取图片地址
13 | export const getCaptchaImg = (img) => {
14 | return axios.captchaImgGet(img)
15 | }
16 |
17 | // 校验验证码
18 | export const checkCaptcha = (url) => {
19 | return axios.captchaGet(url)
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/src/api/system-setting/org_post_members.js:
--------------------------------------------------------------------------------
1 | import axios from '@/libs/api_request'
2 |
3 | // 根据组织机构、岗位 ID,查询成员列表
4 | export const getMembersByOrgPostId = (params) => {
5 | return axios.get('/post_members/list',params)
6 | }
7 |
8 | //新增
9 | export const create = (data) => {
10 | return axios.post('/post_members/create',data)
11 | }
12 |
13 | // 编辑、修改
14 | export const edit = (data) => {
15 | return axios.post('/post_members/edit',data)
16 | }
17 |
18 | // 删除
19 | export const destroy = (id) => {
20 | return axios.post('/post_members/destroy',{id:id})
21 | }
22 |
--------------------------------------------------------------------------------
/src/api/system-setting/organization.js:
--------------------------------------------------------------------------------
1 | import axios from '@/libs/api_request'
2 |
3 | export const list = (params) => {
4 | return axios.get('/organization/list', params)
5 | }
6 |
7 | export const create = (data) => {
8 | return axios.post('/organization/create', data)
9 | }
10 |
11 | export const edit = (data) => {
12 | return axios.post('/organization/edit', data)
13 | }
14 |
15 | export const destroy = (id) => {
16 | return axios.post('/organization/destroy', {id: parseInt(id)})
17 | }
18 |
19 | // 左侧数据获取接口
20 | export const getSubListByFid = (id) => {
21 | return axios.get('/organization/get_by_fid', {fid: id})
22 | }
23 |
--------------------------------------------------------------------------------
/src/api/system-setting/system_menu.js:
--------------------------------------------------------------------------------
1 | import axios from '@/libs/api_request'
2 |
3 | // 左侧数据获取接口
4 | export const getSubListByFid = (id) => {
5 | return axios.get('/system_menu/get_by_fid',{fid:id})
6 | }
7 | // 右侧list
8 | export const list = (params) => {
9 | return axios.get('/system_menu/list',params)
10 | }
11 | //新增
12 | export const createByJson = (json) => {
13 | return axios.post_raw('/system_menu/create',json)
14 | }
15 |
16 | //修改
17 | export const editByJson = (json) => {
18 | return axios.post_raw('/system_menu/edit',json)
19 | }
20 |
21 | //删除
22 | export const destroy = (id) => {
23 | return axios.post('/system_menu/destroy',{id: parseInt(id)})
24 | }
25 |
26 | //系统菜单挂接的按钮列表(可被分配的按钮数据源列表)
27 | export const menu_mount_auth_button = (menuId) => {
28 | return axios.get('/system_menu/mount_auth_button',{fr_auth_system_menu_id:menuId})
29 | }
30 |
--------------------------------------------------------------------------------
/src/api/system-setting/user.js:
--------------------------------------------------------------------------------
1 | import axios from '@/libs/api_request'
2 |
3 | // 查询
4 | export const list = (params) => {
5 | return axios.get('/users/list', params)
6 | }
7 |
8 | // 新增
9 | export const create = (data) => {
10 | return axios.post('/users/create', data)
11 | }
12 |
13 | // 修改
14 | export const edit = (data) => {
15 | return axios.post('/users/edit', data)
16 | }
17 |
18 | // 删除
19 | export const destroy = (id) => {
20 | return axios.post('/users/destroy', {id: id})
21 | }
22 |
23 | // =================== ↓↓↓ 扩展接口 ↓↓↓ ==================
24 | // 获取info
25 | export const getUserInfo = () => {
26 | return axios.get('/users/info')
27 | }
28 |
29 | // 获取个人基本信息
30 | export const personalInfo = () => {
31 | return axios.get('/users/personal_info')
32 | }
33 |
34 | // 编辑个人基本信息
35 | export const personalEdit = (params) => {
36 | return axios.post('/users/personal_edit', params)
37 | }
38 |
39 | // 用户登录系统
40 | export const login = ({ user_name, pass,captcha_id,captcha_value }) => {
41 | let data = {
42 | user_name: user_name,
43 | pass: pass,
44 | captcha_id: captcha_id,
45 | captcha_value: captcha_value
46 | }
47 | return axios.post('users/login', data)
48 | }
--------------------------------------------------------------------------------
/src/assets/images/bg1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qifengzhang007/ginskeleton-admin2-frontend/e6ea14c8da25479e7a097eed14948e9b4e7d6e6e/src/assets/images/bg1.png
--------------------------------------------------------------------------------
/src/assets/images/bg2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qifengzhang007/ginskeleton-admin2-frontend/e6ea14c8da25479e7a097eed14948e9b4e7d6e6e/src/assets/images/bg2.png
--------------------------------------------------------------------------------
/src/assets/images/bg3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qifengzhang007/ginskeleton-admin2-frontend/e6ea14c8da25479e7a097eed14948e9b4e7d6e6e/src/assets/images/bg3.png
--------------------------------------------------------------------------------
/src/assets/images/full-icon-0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qifengzhang007/ginskeleton-admin2-frontend/e6ea14c8da25479e7a097eed14948e9b4e7d6e6e/src/assets/images/full-icon-0.png
--------------------------------------------------------------------------------
/src/assets/images/full-icon-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qifengzhang007/ginskeleton-admin2-frontend/e6ea14c8da25479e7a097eed14948e9b4e7d6e6e/src/assets/images/full-icon-1.png
--------------------------------------------------------------------------------
/src/assets/images/logo-min.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qifengzhang007/ginskeleton-admin2-frontend/e6ea14c8da25479e7a097eed14948e9b4e7d6e6e/src/assets/images/logo-min.jpg
--------------------------------------------------------------------------------
/src/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qifengzhang007/ginskeleton-admin2-frontend/e6ea14c8da25479e7a097eed14948e9b4e7d6e6e/src/assets/images/logo.png
--------------------------------------------------------------------------------
/src/assets/images/split_flag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qifengzhang007/ginskeleton-admin2-frontend/e6ea14c8da25479e7a097eed14948e9b4e7d6e6e/src/assets/images/split_flag.png
--------------------------------------------------------------------------------
/src/assets/images/system_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qifengzhang007/ginskeleton-admin2-frontend/e6ea14c8da25479e7a097eed14948e9b4e7d6e6e/src/assets/images/system_logo.png
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qifengzhang007/ginskeleton-admin2-frontend/e6ea14c8da25479e7a097eed14948e9b4e7d6e6e/src/assets/logo.png
--------------------------------------------------------------------------------
/src/auto-imports.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* prettier-ignore */
3 | // @ts-nocheck
4 | // noinspection JSUnusedGlobalSymbols
5 | // Generated by unplugin-auto-import
6 | // biome-ignore lint: disable
7 | export {}
8 | declare global {
9 | const ElMessage: typeof import('element-plus/es')['ElMessage']
10 | const ElNotification: typeof import('element-plus/es')['ElNotification']
11 | }
12 |
--------------------------------------------------------------------------------
/src/components.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | // @ts-nocheck
3 | // Generated by unplugin-vue-components
4 | // Read more: https://github.com/vuejs/core/pull/3399
5 | export {}
6 |
7 | /* prettier-ignore */
8 | declare module 'vue' {
9 | export interface GlobalComponents {
10 | CommonChildren_table: typeof import('./components/common/children_table.vue')['default']
11 | CommonChildren_table_plus: typeof import('./components/common/children_table_plus.vue')['default']
12 | CommonDelete_data_dialog: typeof import('./components/common/delete_data_dialog.vue')['default']
13 | CommonGroup_panel: typeof import('./components/common/group_panel.vue')['default']
14 | CommonIframe: typeof import('./components/common/iframe.vue')['default']
15 | CommonImage: typeof import('./components/common/image.vue')['default']
16 | CommonPaging: typeof import('./components/common/paging.vue')['default']
17 | CommonSeekbar_for_drawer: typeof import('./components/common/seekbar_for_drawer.vue')['default']
18 | CommonSelect_button: typeof import('./components/common/select_button.vue')['default']
19 | CommonSelect_org_post: typeof import('./components/common/select_org_post.vue')['default']
20 | CommonSelect_province_city: typeof import('./components/common/select_province_city.vue')['default']
21 | CommonSelect_sys_menu: typeof import('./components/common/select_sys_menu.vue')['default']
22 | CommonSelect_user: typeof import('./components/common/select_user.vue')['default']
23 | CommonSplit: typeof import('./components/common/split.vue')['default']
24 | CommonTable_header1: typeof import('./components/common/table_header1.vue')['default']
25 | CommonTable_header2: typeof import('./components/common/table_header2.vue')['default']
26 | CommonTags2: typeof import('./components/common/tags2.vue')['default']
27 | CommonUpload_file: typeof import('./components/common/upload_file.vue')['default']
28 | DataDictionaryProvinceCity: typeof import('./components/data-dictionary/province-city/index.vue')['default']
29 | DataDictionaryProvinceCityCreate_edit: typeof import('./components/data-dictionary/province-city/create_edit.vue')['default']
30 | ElAside: typeof import('element-plus/es')['ElAside']
31 | ElAvatar: typeof import('element-plus/es')['ElAvatar']
32 | ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
33 | ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
34 | ElButton: typeof import('element-plus/es')['ElButton']
35 | ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
36 | ElCarousel: typeof import('element-plus/es')['ElCarousel']
37 | ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem']
38 | ElCol: typeof import('element-plus/es')['ElCol']
39 | ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
40 | ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
41 | ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
42 | ElDialog: typeof import('element-plus/es')['ElDialog']
43 | ElDrawer: typeof import('element-plus/es')['ElDrawer']
44 | ElDropdown: typeof import('element-plus/es')['ElDropdown']
45 | ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
46 | ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
47 | ElForm: typeof import('element-plus/es')['ElForm']
48 | ElFormItem: typeof import('element-plus/es')['ElFormItem']
49 | ElIcon: typeof import('element-plus/es')['ElIcon']
50 | ElImage: typeof import('element-plus/es')['ElImage']
51 | ElInput: typeof import('element-plus/es')['ElInput']
52 | ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
53 | ElLink: typeof import('element-plus/es')['ElLink']
54 | ElMenu: typeof import('element-plus/es')['ElMenu']
55 | ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
56 | ElOption: typeof import('element-plus/es')['ElOption']
57 | ElPagination: typeof import('element-plus/es')['ElPagination']
58 | ElResult: typeof import('element-plus/es')['ElResult']
59 | ElRow: typeof import('element-plus/es')['ElRow']
60 | ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
61 | ElSelect: typeof import('element-plus/es')['ElSelect']
62 | ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
63 | ElTable: typeof import('element-plus/es')['ElTable']
64 | ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
65 | ElTag: typeof import('element-plus/es')['ElTag']
66 | ElTree: typeof import('element-plus/es')['ElTree']
67 | ElUpload: typeof import('element-plus/es')['ElUpload']
68 | ReportDemoEmployees_index: typeof import('./components/report/demo/employees_index.vue')['default']
69 | ReportDemoTrain_timetable: typeof import('./components/report/demo/train_timetable.vue')['default']
70 | RouterLink: typeof import('vue-router')['RouterLink']
71 | RouterView: typeof import('vue-router')['RouterView']
72 | SystemSettingAuthAnalysis: typeof import('./components/system-setting/auth-analysis/index.vue')['default']
73 | SystemSettingAuthAssignment: typeof import('./components/system-setting/auth-assignment/index.vue')['default']
74 | SystemSettingButton: typeof import('./components/system-setting/button/index.vue')['default']
75 | SystemSettingButtonCreate_edit: typeof import('./components/system-setting/button/create_edit.vue')['default']
76 | SystemSettingLayoutHeader_banner: typeof import('./components/system-setting/layout/header_banner.vue')['default']
77 | SystemSettingLayoutLeft_menu: typeof import('./components/system-setting/layout/left_menu.vue')['default']
78 | SystemSettingLayoutTabs: typeof import('./components/system-setting/layout/tabs.vue')['default']
79 | SystemSettingLoginFormCarouse: typeof import('./components/system-setting/login-form/carouse.vue')['default']
80 | SystemSettingLoginFormCopy_right: typeof import('./components/system-setting/login-form/copy_right.vue')['default']
81 | SystemSettingLoginFormForm: typeof import('./components/system-setting/login-form/form.vue')['default']
82 | SystemSettingLoginFormTitle: typeof import('./components/system-setting/login-form/title.vue')['default']
83 | SystemSettingOrganization: typeof import('./components/system-setting/organization/index.vue')['default']
84 | SystemSettingOrganizationCreate_edit: typeof import('./components/system-setting/organization/create_edit.vue')['default']
85 | SystemSettingOrganizationMembers: typeof import('./components/system-setting/organization-members/index.vue')['default']
86 | SystemSettingOrganizationMembersCreate_edit: typeof import('./components/system-setting/organization-members/create_edit.vue')['default']
87 | SystemSettingSystemMenu: typeof import('./components/system-setting/system-menu/index.vue')['default']
88 | SystemSettingSystemMenuCreate_edit: typeof import('./components/system-setting/system-menu/create_edit.vue')['default']
89 | SystemSettingUser: typeof import('./components/system-setting/user/index.vue')['default']
90 | SystemSettingUserCreate_edit: typeof import('./components/system-setting/user/create_edit.vue')['default']
91 | SystemSettingUserProfile: typeof import('./components/system-setting/user/profile.vue')['default']
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/components/common/delete_data_dialog.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {{ propDelete.actionName }}
9 |
10 |
11 |
12 | 本次将删除 {{ propDelete.delCounts }} 条数据, 确认删除吗 ?
13 |
14 |
15 | 删除结果:失败 , {{ propDelete.serverResMsg }}
16 |
17 |
18 |
19 |
20 |
21 | 删除操作出错:{{ propDelete.serverResMsg }}
22 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
33 |
75 |
76 |
92 |
--------------------------------------------------------------------------------
/src/components/common/group_panel.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
{{ title }}
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
53 |
54 |
88 |
--------------------------------------------------------------------------------
/src/components/common/iframe.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
44 |
45 |
58 |
--------------------------------------------------------------------------------
/src/components/common/image.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
10 |
11 |
46 |
47 |
--------------------------------------------------------------------------------
/src/components/common/paging.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
55 |
56 |
--------------------------------------------------------------------------------
/src/components/common/seekbar_for_drawer.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
42 |
43 |
--------------------------------------------------------------------------------
/src/components/common/select_button.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {{ propSelect.title.length > 1 ? propSelect.title : '选择按钮' }}
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 |
37 |
38 |
39 |
40 |
44 |
45 |
46 |
47 |
48 |
152 |
153 |
167 |
168 |
--------------------------------------------------------------------------------
/src/components/common/select_org_post.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {{ propSelect.title }}
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
105 |
106 |
--------------------------------------------------------------------------------
/src/components/common/select_province_city.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {{ propSelect.title }}
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
105 |
106 |
--------------------------------------------------------------------------------
/src/components/common/select_sys_menu.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | {{ propSelect.title }}
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
24 |
106 |
107 |
--------------------------------------------------------------------------------
/src/components/common/select_user.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {{ propSelect.title.length > 1 ? propSelect.title : '选择用户' }}
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 |
36 |
37 |
38 |
39 |
43 |
44 |
45 |
46 |
47 |
157 |
158 |
172 |
173 |
--------------------------------------------------------------------------------
/src/components/common/split.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
101 |
102 |
124 |
--------------------------------------------------------------------------------
/src/components/common/table_header1.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
11 |
--------------------------------------------------------------------------------
/src/components/common/table_header2.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
--------------------------------------------------------------------------------
/src/components/common/tags2.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ tag.name }}
5 |
6 |
7 |
8 |
9 |
42 |
43 |
44 |
59 |
--------------------------------------------------------------------------------
/src/components/common/upload_file.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
72 |
73 |
81 |
82 |
102 |
--------------------------------------------------------------------------------
/src/components/data-dictionary/province-city/create_edit.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
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 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
179 |
180 |
--------------------------------------------------------------------------------
/src/components/report/demo/employees_index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 姓名:
6 |
7 | 入职时间:
8 |
9 | -
10 |
11 |
12 | 查询
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
98 |
99 |
108 |
--------------------------------------------------------------------------------
/src/components/report/demo/train_timetable.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 始发地:
6 |
7 |
8 |
9 | 查询
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
85 |
86 |
95 |
--------------------------------------------------------------------------------
/src/components/system-setting/auth-analysis/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 用户姓名:
8 |
9 |
10 | 查询
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | {{ scope.row.real_name }}
21 | {{ scope.row.post_name }}
22 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | 已分配权限列表
37 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | {{ node.label }}
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
184 |
185 |
215 |
--------------------------------------------------------------------------------
/src/components/system-setting/button/create_edit.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
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 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
169 |
170 |
182 |
--------------------------------------------------------------------------------
/src/components/system-setting/button/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
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 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
222 |
223 |
232 |
--------------------------------------------------------------------------------
/src/components/system-setting/layout/header_banner.vue:
--------------------------------------------------------------------------------
1 |
2 |
40 |
41 |
42 |
136 |
137 |
--------------------------------------------------------------------------------
/src/components/system-setting/layout/left_menu.vue:
--------------------------------------------------------------------------------
1 |
2 |
76 |
77 |
78 |
105 |
106 |
138 |
--------------------------------------------------------------------------------
/src/components/system-setting/layout/tabs.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
27 |
28 |
29 |
30 |
31 |
32 | X
33 |
34 |
35 |
36 | 关闭其它
37 | 关闭所有
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
113 |
114 |
261 |
262 |
263 |
268 |
--------------------------------------------------------------------------------
/src/components/system-setting/login-form/carouse.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
17 |
18 |
50 |
--------------------------------------------------------------------------------
/src/components/system-setting/login-form/copy_right.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ copyright }}
3 |
4 |
5 |
22 |
23 |
35 |
--------------------------------------------------------------------------------
/src/components/system-setting/login-form/form.vue:
--------------------------------------------------------------------------------
1 |
2 |
46 |
47 |
48 |
164 |
165 |
182 |
--------------------------------------------------------------------------------
/src/components/system-setting/login-form/title.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
{{ title }}
5 |
6 |
7 |
8 |
24 |
25 |
49 |
--------------------------------------------------------------------------------
/src/components/system-setting/organization-members/create_edit.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
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 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
200 |
201 |
208 |
--------------------------------------------------------------------------------
/src/components/system-setting/organization/create_edit.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
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 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
167 |
168 |
180 |
--------------------------------------------------------------------------------
/src/components/system-setting/user/create_edit.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
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 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
179 |
180 |
187 |
--------------------------------------------------------------------------------
/src/components/system-setting/user/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
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 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
228 |
229 |
238 |
--------------------------------------------------------------------------------
/src/components/system-setting/user/profile.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
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 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
172 |
173 |
--------------------------------------------------------------------------------
/src/config/index.js:
--------------------------------------------------------------------------------
1 | export default {
2 |
3 | /*
4 | * @description 配置显示在浏览器标签的title
5 | */
6 | loginTitle: '企业项目开发骨架', // 登陆背景显示的标题
7 | cmsTitle: '后台管理系统', // 登录后显示的标题
8 | copyRight: 'Copyright © 2022 www.ginskeleton.com, All rights reserved.',
9 | loginParams: {
10 | userName: 'admin',
11 | pass: 'ginskeleton'
12 | },
13 |
14 | /*
15 | * npm run dev ;
16 | * npm run build:dev 开发调试、以及打包开发环境时有效
17 | */
18 | dev:{
19 | serverIp: 'http://127.0.0.1:22001', // 服务器ip
20 | apiPre: 'http://127.0.0.1:22001/admin', // 接口前缀
21 | reportServerIp:'http://114.115.223.249:22004', //报表系统的ip地址
22 | },
23 |
24 | /*
25 | * npm run build 生产环境有效
26 | */
27 | pro:{
28 | serverIp: 'http://139.196.101.31:22001',
29 | apiPre: 'http://139.196.101.31:22001/admin',
30 | reportServerIp:'http://114.115.223.249:22004', //报表系统的ip地址
31 | },
32 | // ==============↓↓↓ 后面的设置基本上无需改动 ↓↓↓======
33 |
34 | /*
35 | 所有的api接口请求超时时间,单位:毫秒
36 | */
37 | requestTimeout: 5000,
38 |
39 | /*
40 | * @description 本地数据存储相关的设置
41 | */
42 | dataStore: {
43 | // 存储cookie、localStorage 时,key 的前缀,
44 | keyPre: "K1_", // 建议不同的项目使用项目编号作为前缀
45 | userTokenKey: "UserToken", // 用户登录后token存储在cookie的键
46 | },
47 |
48 | /*
49 | * @description 出错设置
50 | */
51 | errorSetting: {
52 | serverNotStartTips: '可能是服务端未启动,请联系管理员',
53 | noAuthTips: 'Casbin 鉴权未通过,请在后台检查 casbin 设置参数', // 接口没有授权时的错误提示,需要和后台casbin未通过时的提示一致,否则会显示2条信息,
54 | tokenExpiredTips: '页面token授权已过期,请重新登陆.',
55 | },
56 |
57 | /*
58 | * @description 默认路由设置
59 | */
60 | defaultRoute: {
61 | notLoginDefaultRouterName: 'login',
62 | loginDefaultRouterName: '/',
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | /*elementPlus 需要全局重写的样式可以在这里统一定义覆盖*/
2 | body, * {
3 | padding: 0;
4 | margin: 0;
5 | box-sizing: border-box;
6 | /*overflow: hidden;*/
7 | font-size: 12px;
8 | font-family: 'Microsoft YaHei', system-ui, sans-serif;
9 | }
10 |
11 | .el-menu {
12 | border-right: none !important;
13 | }
14 |
15 | /*各个子菜单之间的分割线颜色*/
16 | .el-sub-menu:not(.menu-level2) {
17 | border-top: 1px solid #404141;
18 | }
19 |
20 | .el-sub-menu:last-child:not(.menu-level2) {
21 | border-bottom: 1px solid #404141;
22 | }
23 |
24 | .el-sub-menu .el-sub-menu__icon-arrow {
25 | right: -90px !important;
26 | }
27 |
28 | /*菜单标题的样式*/
29 | .el-sub-menu__title {
30 | font-size: 13px !important;
31 | width: 225px !important;
32 | height: 40px !important;
33 | line-height: 40px !important;
34 | vertical-align: middle !important;
35 | color: #f3f6fb !important;
36 | }
37 |
38 | /*菜单item的样式:最底层可被点击打开的菜单样式*/
39 | li.el-menu-item:not(.menu-level1) {
40 | font-size: 12px;
41 | height: 34px !important;
42 | line-height: 34px !important;
43 | vertical-align: middle !important;
44 | background-color: #292a2d;
45 | }
46 |
47 | /*菜单item的样式: 当只有一级菜单时在最外层的样式*/
48 | li.el-menu-item.menu-level1 {
49 | font-size: 13px !important;;
50 | height: 40px !important;
51 | line-height: 40px !important;
52 | vertical-align: middle !important;
53 | background-color: #1d1e23;
54 | border-top: solid 1px #404141;
55 | }
56 |
57 | .el-sub-menu [class^="el-icon-"] {
58 | vertical-align: -1px !important;
59 | }
60 |
61 | /*二级子菜单的背景样式*/
62 | li.el-sub-menu.menu-level2 div {
63 | background-color: #232427 !important;
64 | }
65 |
66 | /*二级背景鼠标热点样式*/
67 | div.el-sub-menu__title:hover {
68 | background-color: #20242a !important;
69 | color: #d0d0d6 !important;
70 | }
71 |
72 | /*一级背景鼠标热点样式*/
73 | li.el-sub-menu.menu-level2 div:hover {
74 | background-color: #20242a !important;
75 | }
76 |
77 | li.el-sub-menu.menu-level2 div {
78 | border-top: #404141 solid 1px;
79 | }
80 |
81 | /*菜单选中样式*/
82 | li .is-active {
83 | background-color: #2d8cf0 !important;
84 | color: white;
85 | }
86 |
87 | /*菜单热点背景颜色 */
88 | li.el-menu-item:hover {
89 | background-color: #38404a;
90 | }
91 |
92 |
93 | /*所有的table表头统一加一个淡淡的灰色背景*/
94 | table.el-table__header > thead > tr > th.el-table__cell {
95 | background-color: #f8f8f9 !important;
96 | }
97 |
98 | /*对话框的标题全局统一修改为 14px */
99 | span.el-dialog__title {
100 | font-size: 14px;
101 | }
102 |
103 | /*消息提示样式统一规定在右侧展示*/
104 | .elMessageStyle {
105 | left: calc(100% - 120px);
106 | min-width: 240px;
107 | text-align: center;
108 | }
109 |
110 | div.elMessageStyle.el-message--success {
111 | border: solid 1px rgba(66, 160, 66, 0.5);
112 | }
113 |
114 | div.elMessageStyle.el-message--error {
115 | border: solid 1px rgba(231, 18, 18, 0.5);
116 | }
117 |
118 | /*drawer 抽屉组件头高度统一减小*/
119 | header.el-drawer__header {
120 | margin: 4px 20px;
121 | display: flex;
122 | align-items: center;
123 | padding: 4px 0 12px 0;
124 | border-bottom: solid 1px #f1f1f1;
125 | height: 40px;
126 | }
127 |
128 | /*抽屉标题样式字体*/
129 | header.el-drawer__header * {
130 | font-size: 13px;
131 | }
132 |
133 | /*抽屉内容区域*/
134 | div.el-drawer__body {
135 | margin: 0 20px;
136 | padding: 0;
137 | }
138 |
139 | div.el-drawer__body * {
140 | font-size: 12px;
141 | vertical-align: middle;
142 | }
143 |
144 | /*抽屉footer区域填充样式*/
145 | div.el-drawer__footer {
146 | margin: 0 20px;
147 | border-top: solid 1px #f1f1f1;
148 | padding: 10px 0;
149 | }
150 |
151 | label.el-form-item__label:after {
152 | content: ":";
153 | }
154 |
155 | div.el-select {
156 | width: 100%;
157 | }
158 |
159 | /*树形列表字体设置*/
160 | span.el-tree-node__label {
161 | font-size: 12px;
162 | }
163 |
164 | /*对话框紧凑化*/
165 | header.el-dialog__header {
166 | padding: 6px 6px
167 | }
168 |
169 | div.el-dialog__body {
170 | padding: 6px 10px;
171 | font-size: 13px;
172 | }
173 |
174 | /*table表格查询按钮层样式*/
175 | .tableList-area {
176 | padding-left: 4px;
177 | }
178 |
179 | .toolBanner {
180 | display: flex;
181 | align-items: center;
182 | padding: 2px 0 6px 2px;
183 | }
184 |
185 | /*分页样式全部底部居中*/
186 | .paging-area {
187 | margin: 6px 0 2px 0;
188 | text-align: center;
189 | vertical-align: middle;
190 | }
191 |
192 | /*权限分析、分配界面自定义图标样式*/
193 | .tree-node {
194 | display: inline-block;
195 | height: 25px;
196 | line-height: 25px;
197 | vertical-align: middle;
198 | }
199 |
200 | span.tree-node * {
201 | vertical-align: middle;
202 | }
203 |
204 | .tree-node-title {
205 | padding-left: 6px;
206 | }
207 |
208 | span.el-tree__empty-text {
209 | font-size: 12px;
210 | }
211 |
212 | /*表单尾部追加的图标确保均匀分布*/
213 | div.el-input-group__append, div.el-input-group__prepend {
214 | display: flex;
215 | justify-content: space-around;
216 | padding: 0 10px;
217 | }
218 |
219 | .el-button--small {
220 | padding: 4px 4px;
221 | }
222 |
223 | a {
224 | text-decoration: none;
225 | }
226 |
227 | .auth-list-title {
228 | width: 99%;
229 | border-bottom: 1px solid #f1f1f1;
230 | margin: 5px 7px;
231 | padding-bottom: 4px;
232 | }
233 |
234 | /*抽屉界面横向滚动条隐藏*/
235 | div.el-drawer div.el-drawer__body {
236 | overflow-x: hidden;
237 | }
238 |
239 | .el-input-number {
240 | width: 98% !important;
241 | }
242 | input.el-input__inner{
243 | text-align: left !important;
244 | }
--------------------------------------------------------------------------------
/src/libs/api_request.js:
--------------------------------------------------------------------------------
1 | import HttpRequest from '@/libs/axios'
2 | import commonFunc from '@/libs/common_func'
3 | import Qs from 'qs'
4 | import config from '@/config/index'
5 |
6 | const httpClient = new HttpRequest(commonFunc.getApiUrlPre())
7 | const captchaClient = new HttpRequest(commonFunc.getServerIp())
8 |
9 | export default {
10 | name: "axios",
11 |
12 | /*
13 | *get方式提交数据
14 | * @request_uri 请求的短地址
15 | * @form_data 参数
16 | */
17 | get(request_uri, params) {
18 | return httpClient.request({
19 | url: request_uri,
20 | method: 'get',
21 | params: params,
22 | timeout: config.requestTimeout || 5000
23 | })
24 | },
25 |
26 | /*
27 | * post form 表单方式提交数据
28 | * @request_uri 请求的短地址
29 | * @form_data 参数
30 | */
31 | post(request_uri, form_data) {
32 | return httpClient.request({
33 | url: request_uri,
34 | method: 'post',
35 | data: Qs.stringify(form_data),
36 | timeout: config.requestTimeout || 5000
37 | })
38 | },
39 |
40 | /*
41 | * 提交原生 json 格式数据,以 post 方式提交数据(服务端需要允许post方式提交的raw json )
42 | * @request_uri 请求的短地址
43 | * @json 参数
44 | */
45 | post_raw(request_uri, json) {
46 | return httpClient.request({
47 | //baseURL: '', // 将前缀设置为空,request_uri 参数可以指定任何站点的完整地址
48 | url: request_uri,
49 | method: 'post',
50 | data: json,
51 | headers: {
52 | "Content-Type": "application/json"
53 | },
54 | timeout: config.requestTimeout || 5000
55 | })
56 | },
57 |
58 | //验证码
59 | captchaGet(request_uri, params) {
60 | return captchaClient.request({
61 | url: request_uri,
62 | method: 'get',
63 | params: params
64 | })
65 | },
66 |
67 | captchaImgGet(request_uri, params) {
68 | return captchaClient.request({
69 | url: request_uri,
70 | method: 'get',
71 | params: params,
72 | responseType: 'arraybuffer'
73 | })
74 | },
75 | // 更多请求方式请自行封装即可
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/src/libs/axios.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import {clearLocalStorageAll, getToken} from '@/libs/util'
3 | import config from '@/config/index'
4 | import router from '@/router/index'
5 | import commonFunc from "./common_func";
6 |
7 | class HttpRequest {
8 | constructor(baseUrl = '') {
9 | this.baseUrl = baseUrl
10 | }
11 |
12 | getInsideConfig() {
13 | return {
14 | baseURL: this.baseUrl,
15 | headers: {
16 | 'Content-Type': 'application/x-www-form-urlencoded',
17 | 'Accept': 'application/json'
18 | }
19 | }
20 | }
21 |
22 | /*
23 | 请求拦截器
24 | @instance axios 对象实例
25 | @url 请求的url
26 | */
27 | interceptors(instance, url) {
28 | instance.interceptors.request.use(config => {
29 | // 接口请求增加token
30 | config.headers.Authorization = 'Bearer ' + getToken()
31 | return config
32 | }, error => {
33 | return Promise.reject(error)
34 | })
35 |
36 | /*
37 | 响应拦截器
38 | */
39 | instance.interceptors.response.use(res => {
40 | const {data, status} = res
41 | return {data, status}
42 | }, error => {
43 | switch (error.response.status) {
44 | case 0:
45 | ElNotification({
46 | title: '网络通讯错误',
47 | message: config.errorSetting.serverNotStartTips,
48 | type: 'error',
49 | })
50 | break
51 | case 401:
52 | clearLocalStorageAll()
53 | ElNotification({
54 | title: '页面授权过期',
55 | message: config.errorSetting.tokenExpiredTips,
56 | type: 'error',
57 | })
58 | setTimeout(() => {
59 | router.push({name: config.defaultRoute.notLoginDefaultRouterName})
60 | }, 1000);
61 | break
62 | case 405:
63 | commonFunc.Curd.FailTips(config.errorSetting.noAuthTips)
64 | break
65 | }
66 | return Promise.reject(error)
67 | })
68 | }
69 |
70 | /*
71 | 封装axios的post请求
72 | @options axios接受的配置参数
73 | */
74 | request(options) {
75 | const instance = axios.create()
76 | options = Object.assign(this.getInsideConfig(), options)
77 | this.interceptors(instance, options.url)
78 | return instance(options)
79 | }
80 | }
81 |
82 | export default HttpRequest
83 |
--------------------------------------------------------------------------------
/src/libs/util.js:
--------------------------------------------------------------------------------
1 | import config from '@/config/index'
2 |
3 | /*
4 | 这里主要封装一些框架使用的基础功能函数
5 | */
6 |
7 |
8 | /*
9 | 设置 token
10 | */
11 | export const setToken = (token) => {
12 | localStorage.setItem(config.dataStore.keyPre + config.dataStore.userTokenKey, token)
13 | }
14 |
15 | /*
16 | 获取 token
17 | */
18 | export const getToken = () => {
19 | const token = localStorage.getItem(config.dataStore.keyPre + config.dataStore.userTokenKey);
20 | if (token) return token
21 | else return false
22 | }
23 |
24 |
25 | /*
26 | 清除所有 localStorage
27 | */
28 | export const clearLocalStorageAll = () => {
29 | window.localStorage.clear()
30 | }
31 |
32 | /*
33 | 清除所有cookies
34 | */
35 | export const clearCookie = () => {
36 | const keys = document.cookie.match(/[^ =;]+(?==)/g);
37 | if (keys) {
38 | for (let i = keys.length; i--;) {
39 | document.cookie = keys[i] + '=0;path=/;expires=' + new Date(0).toUTCString();
40 | document.cookie = keys[i] + '=0;path=/;domain=' + document.domain + ';expires=' + new Date(0).toUTCString();
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import {createApp,h} from 'vue'
2 | import App from './App.vue'
3 | import router from './router/index'
4 | import * as ElementPlusIconsVue from '@element-plus/icons-vue'
5 | import './index.css'
6 | import store from "./store/system-setting/index";
7 | import ElementPlus from 'element-plus'
8 | import zhCn from 'element-plus/es/locale/lang/zh-cn'
9 | import 'default-passive-events'
10 | import { getElementLabelLine } from 'element-tree-line';
11 | import 'element-tree-line/dist/style.css';
12 |
13 | const app = createApp(App)
14 |
15 | // 全局注册 elementPlus 的图标, 这样就可以在后台配置动态图标
16 | for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
17 | app.component(key, component)
18 | }
19 | // 全局注册ElementLabelLine
20 | const ElementLabelLine = getElementLabelLine(h);
21 | app.component(ElementLabelLine.name, ElementLabelLine);
22 |
23 | app.use(store)
24 | app.use(router)
25 | app.use(ElementPlus, {
26 | locale: zhCn,
27 | })
28 |
29 | app.mount('#app')
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import {createRouter, createWebHashHistory,createWebHistory} from 'vue-router'
2 |
3 | const router = createRouter({
4 | // history: createWebHashHistory(),
5 | history: createWebHistory(),
6 | routes: [
7 | {
8 | path: '/login',
9 | name: 'login',
10 | components: {
11 | login: () => import(/* webpackChunkName: "login" */ '@/views/system-setting/login.vue'),
12 | },
13 | meta: {
14 | icon: "",
15 | id: -1,
16 | title: "登录入口"
17 | }
18 | },
19 | {
20 | path: '/:pathMatch(.*)*',
21 | name: 'blank_page',
22 | component: () => import(/* webpackChunkName: "blank_page" */ '@/views/system-setting/blank_page.vue'),
23 | meta: {
24 | icon: "",
25 | id: -2,
26 | title: ''
27 | }
28 | }
29 |
30 | ]
31 | })
32 | export default router
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/store/system-setting/header_banner.js:
--------------------------------------------------------------------------------
1 | import {defineStore} from 'pinia'
2 |
3 | export const useHeaderBannerStore = defineStore(
4 | {
5 | id: 'useHeaderBannerStore',
6 | state: () => {
7 | return {
8 | headerBanner: {
9 | navPathName: '',
10 | },
11 | }
12 | },
13 | getters: {
14 | getNavPathName() {
15 | return this.headerBanner.navPathName
16 | },
17 | },
18 | actions: {
19 | /*
20 | *菜单点击时设置
21 | */
22 | setHeaderBannerNav(navPathName) {
23 | this.headerBanner.navPathName = navPathName
24 | },
25 |
26 | }
27 | }
28 | )
--------------------------------------------------------------------------------
/src/store/system-setting/index.js:
--------------------------------------------------------------------------------
1 | import {createPinia} from 'pinia'
2 | import piniaPluginPersist from 'pinia-plugin-persist'
3 |
4 | // 使用 pinia 对全局变量进行状态管理,代替 vuex
5 | const store = createPinia()
6 | store.use(piniaPluginPersist)
7 |
8 | export default store
--------------------------------------------------------------------------------
/src/store/system-setting/layout.js:
--------------------------------------------------------------------------------
1 | import {defineStore} from 'pinia'
2 | import config from '@/config/index'
3 |
4 | export const useLayoutStore = defineStore(
5 | {
6 | id: 'useLayoutStore',
7 | persist: {
8 | enabled: true,
9 | strategies: [
10 | {
11 | key: config.dataStore.keyPre + 'useLayoutStore',
12 | storage: localStorage,
13 | paths: ['layout']
14 | }
15 | ]
16 | },
17 | state: () => {
18 | return {
19 | layout: {
20 | leftMenuDefaultWidth: 225,
21 | leftMenuIsShow: true,
22 | leftMenuWidth: 225,
23 | },
24 | }
25 | },
26 | getters: {
27 | getLeftMenuWidth() {
28 | return this.layout.leftMenuWidth
29 | },
30 | },
31 | actions: {
32 | /*
33 | 设置左侧宽度尺寸
34 | @width 左侧菜单宽度, 单位:数字型
35 | */
36 | setLeftMenuWidth(width) {
37 | this.layout.leftMenuWidth = width
38 | },
39 |
40 | /*
41 | 收缩、展开左侧菜单
42 | */
43 | collapseExpandLeftMenu() {
44 | this.layout.leftMenuIsShow = !this.layout.leftMenuIsShow
45 | this.layout.leftMenuWidth = this.layout.leftMenuIsShow ? this.layout.leftMenuDefaultWidth : 0
46 | },
47 |
48 | }
49 | }
50 | )
--------------------------------------------------------------------------------
/src/store/system-setting/menu.js:
--------------------------------------------------------------------------------
1 | import {defineStore} from 'pinia'
2 |
3 |
4 | export const useMenuStore = defineStore({
5 | id: 'useMenuStore',
6 | state: () => {
7 | return {
8 | menu: {
9 | defaultActive: '/',
10 | // 当前菜单,该值为默认值
11 | currentMenu: {
12 | id: '', // 最新打开的菜单id
13 | },
14 | list: [], // 后台返回的菜单列表原始数据
15 | menuNavPathList: new Map(),
16 | menuNavPathListArray: [],
17 | tmpPath: ''
18 | }
19 | }
20 | },
21 | // 通过函数形式定义属性
22 | getters: {
23 | /*
24 | 根据userId 查询属于该用户的菜单
25 | @userId 用户id
26 | */
27 | getMenuList() {
28 | return this.menu.list
29 | },
30 | },
31 | // 定义函数
32 | actions: {
33 | /*
34 | * 设置(初始化)菜单列表
35 | @menuList 后台返回的菜单列表
36 | */
37 | initMenuList(menuList) {
38 | this.menu.list = menuList
39 | },
40 |
41 | /*
42 | * 设置默认激活的菜单index,也就是路由 path
43 | * 菜单最大计算到三级深度即可,
44 | */
45 | setDefaultActiveMenuIndex(menuList = [], defaultPath = '') {
46 | let tmpPath = '/'
47 | if (menuList.length > 0) {
48 | tmpPath += menuList[0].name + '/'
49 | if (menuList[0].children.length > 0) {
50 | tmpPath += menuList[0].children[0].name + '/'
51 | if (menuList[0].children[0].children.length > 0) {
52 | tmpPath += menuList[0].children[0].children[0].name + '/'
53 | }
54 | }
55 | }
56 | this.menu.defaultActive = tmpPath.substring(0, tmpPath.length - 1)
57 | },
58 | /*
59 | 独立初始化 menuNavPathListArray
60 | */
61 | setMenuNavPathListArrayEmpty() {
62 | this.tmpPath = ''
63 | this.menu.menuNavPathListArray = []
64 | },
65 |
66 | /*
67 | 递归获取菜单导航路径链条
68 | @menuId 菜单id
69 | */
70 | getMenuNavPathListRecursive(id, menuList = this.menu.list) {
71 | for (let item of menuList) {
72 | if (item.id === id) {
73 | this.tmpPath = item.path;
74 | this.menu.menuNavPathListArray.push(Object.assign({}, item))
75 | return this.menu.menuNavPathListArray
76 | } else {
77 | this.tmpPath = ''
78 | }
79 |
80 | if (item.children.length > 0) {
81 | this.getMenuNavPathListRecursive(id, item.children)
82 | if (this.tmpPath !== '') {
83 | this.menu.menuNavPathListArray.push(Object.assign({}, item))
84 | }
85 | }
86 | }
87 | return this.menu.menuNavPathListArray
88 | },
89 |
90 | /*
91 | 设置菜单导航路径
92 | @menuId 菜单id
93 | @menuNavPathName 菜单导航路径名称
94 | */
95 | setMenuNavPathList(menuId) {
96 | if (menuId <= 0) return
97 | this.menu.currentMenu.id = menuId
98 | if (this.menu.menuNavPathList.get(menuId)) {
99 | return
100 | }
101 | this.setMenuNavPathListArrayEmpty()
102 | const result = this.getMenuNavPathListRecursive(menuId)
103 | if (result) {
104 | this.menu.menuNavPathList.set(menuId, result.reverse())
105 | }
106 | },
107 |
108 | /*
109 | 获取菜单导航路径
110 | @menuId 菜单id
111 | @menuNavPathName 菜单导航路径名称
112 | */
113 | getMenuNavPathList(menuId) {
114 | this.setMenuNavPathList(menuId)
115 | return this.menu.menuNavPathList.get(menuId)
116 | },
117 |
118 | }
119 | })
--------------------------------------------------------------------------------
/src/store/system-setting/reload.js:
--------------------------------------------------------------------------------
1 | import {defineStore} from 'pinia'
2 | import {getUserInfo} from '@/api/system-setting/user'
3 | import {useUserStore} from "@/store/system-setting/user";
4 | import {useMenuStore} from "@/store/system-setting/menu";
5 | import {getToken} from '@/libs/util'
6 | import {useRouteStore} from "@/store/system-setting/route";
7 | import router from '@/router/index'
8 |
9 | /*
10 | 在需要的页面,重载路由列表和菜单列表
11 | */
12 |
13 | export const useReloadStore = defineStore(
14 | {
15 | id: 'useReloadStore',
16 | state: () => {
17 | return {
18 | user: {
19 | Info: {
20 | id: 0,
21 | user_name: '',
22 | real_name: '',
23 | avatar: '',
24 | login_times: 0,
25 | phone: '',
26 | },
27 | token: {
28 | isValid: false,
29 | val: "",
30 | }
31 | },
32 | }
33 | },
34 | getters: {},
35 | actions: {
36 | /*
37 | description: 当页面刷新时,重载路由和菜单信息
38 | @userId 用户id
39 | */
40 | reloadRouterMenu(userId) {
41 | return new Promise((resolver, reject) => {
42 | const userStore = useUserStore();
43 | const routerStore = useRouteStore();
44 | const menuStore = useMenuStore();
45 | getUserInfo(userId).then(res => {
46 | if (res && res.data.code === 200) {
47 | // // 1.初始化用户信息
48 | userStore.setUserInfo(Object.assign({token: getToken()}, res.data.data))
49 | //2.后端menu转为前端需要的路由列表
50 | const routeList = routerStore.initRouteList(res.data.data.menus)
51 | //3.初始化菜单列表
52 | menuStore.initMenuList(res.data.data.menus)
53 | if (window.location.href.indexOf("blank_page") !== -1) {
54 | menuStore.setDefaultActiveMenuIndex()
55 | }
56 | router.addRoute(routerStore.homeRouter)
57 | routeList.map(item => {
58 | router.addRoute(item)
59 | return true
60 | })
61 | return resolver(true)
62 | }
63 | }).catch(err => {
64 | return reject(err)
65 | })
66 | })
67 | },
68 | }
69 | }
70 | )
--------------------------------------------------------------------------------
/src/store/system-setting/route.js:
--------------------------------------------------------------------------------
1 | import {defineStore} from 'pinia'
2 | import defaultRouter from '@/router/index'
3 |
4 | export const useRouteStore = defineStore({
5 | id: 'useRouteStore',
6 | state: () => {
7 | return {
8 | // 全局路由对象
9 | route: {},
10 | // 全局路由列表,从后端接口转换而来
11 | routeList: [],
12 | routeViews: {},
13 | //定义首页默认打开的页面(默认就是后台返回的第一个页面)
14 | homeRouter: {
15 | path: '/',
16 | redirect: {name: ''}
17 | },
18 | }
19 | },
20 | // 通过函数形式定义属性
21 | getters: {
22 | /*
23 | 获取全局路由
24 | */
25 | getRoute() {
26 | return this.route
27 | },
28 |
29 | /*
30 | 获取全部路由列表,包括默认路由
31 | */
32 | getAllRouteList() {
33 | return defaultRouter.getRoutes().concat(this.routeList)
34 | },
35 | /*
36 | 获取全部路由列表
37 | */
38 | getRouteList() {
39 | return this.routeList
40 | },
41 | },
42 | // 定义函数
43 | actions: {
44 | /*
45 | 在项目初始化时,使用全局变量接受vue router
46 | @route vue router对象
47 | */
48 | setRoute(route) {
49 | this.route = route
50 | },
51 |
52 | getViewComponent(keyName) {
53 | return this.routeViews[`/src/${keyName}`]
54 | },
55 | /*
56 | * description 最大支持到三级菜单即可,对于后台系统足够满足需求,性能也好,避免采用递归无穷遍历可能带来性能问题。
57 | * */
58 | menuListConvertRouteList(menuList) {
59 | let routes = []
60 | const addRouter = (itemRouter, routerName = '', routerPath = '') => {
61 | let tmpRouter = {
62 | name: '',
63 | path: '',
64 | component: {},
65 | meta: {
66 | isOutPage: false,
67 | icon: '',
68 | title: '',
69 | viewComponentPath: '',
70 | id: 0
71 | }
72 | }
73 | tmpRouter.name = routerName === '' ? itemRouter.name : routerName
74 | tmpRouter.path = routerPath === '' ? '/' + itemRouter.name : routerPath
75 | tmpRouter.component = this.routeViews[`/src/${itemRouter.component.endsWith('.vue') ? itemRouter.component : itemRouter.component + ".vue"}`]
76 | tmpRouter.meta.icon = itemRouter.icon
77 | tmpRouter.meta.title = itemRouter.title
78 | tmpRouter.meta.id = itemRouter.id
79 | tmpRouter.meta.isOutPage = itemRouter.is_out_page === 1
80 | tmpRouter.meta.viewComponentPath = itemRouter.component
81 | routes.push(tmpRouter)
82 | }
83 | if (menuList && menuList.length > 0) {
84 | menuList.map((item, index) => {
85 | if (item.has_sub_node) {
86 | item.children.map(item2 => {
87 | if (item2.has_sub_node) {
88 | item2.children.map(item3 => {
89 | addRouter(item3, item.name + '_' + item2.name + '_' + item3.name, '/' + item.name + '/' + item2.name + '/' + item3.name)
90 | return true
91 | })
92 | } else {
93 | addRouter(item2, item.name + '_' + item2.name, '/' + item.name + '/' + item2.name)
94 | }
95 | return true
96 | })
97 | } else {
98 | addRouter(item)
99 | }
100 | return true
101 | })
102 | }
103 |
104 | return routes
105 | },
106 | /*
107 | 初始化路由列表
108 | */
109 | initRouteList(menuList) {
110 | // layout/main.vue 是框架本身依赖的组件,不需要后台配置组件路径动态加载,因此在静态导入时排除
111 | this.routeViews = import.meta.glob(["@/views/**/*.vue", '!**/layout/main.vue'])
112 | this.routeList = this.menuListConvertRouteList(menuList)
113 | // 初始化默认打开的第一页面
114 | if (this.routeList.length > 0) {
115 | this.homeRouter.redirect.name = this.routeList[0].name
116 | }
117 | return this.routeList
118 | }
119 | }
120 | })
121 |
--------------------------------------------------------------------------------
/src/store/system-setting/tabs.js:
--------------------------------------------------------------------------------
1 | import {defineStore} from 'pinia'
2 | import {useRouteStore} from "@/store/system-setting/route";
3 | import {useMenuStore} from "@/store/system-setting/menu";
4 | import commonFunc from '@/libs/common_func'
5 |
6 | //点击 菜单时 与 tabs 实现联动
7 |
8 | export const useTabStore = defineStore({
9 | id: 'useTabStore',
10 | state: () => {
11 | return {
12 | tabs: {
13 | // list 数组的空白数据结构
14 | item: {
15 | name: '', // 菜单的 name 字段
16 | isActive: false,
17 | relaMenuId: -1, // tab 对应的菜单 id, 该值是唯一的
18 | icon: '',
19 | path: '', // tab 对应的路由路径
20 | viewComponentPath:'',
21 | isOutPage:0
22 | },
23 | curMenuItem: {
24 | name: '',
25 | isActive: true,
26 | relaMenuId: 0,
27 | icon: '',
28 | path: '',
29 | viewComponentPath: '',
30 | isOutPage:0
31 | },
32 | curPath: '',
33 | list: [],
34 | }
35 | }
36 | },
37 | getters: {
38 | /*
39 | * 获取所有的tabList
40 | * */
41 | getTabList(userId) {
42 | return this.tabs.list
43 | },
44 |
45 | },
46 | actions: {
47 | /* 点击菜单时, 添加 tab 导航按钮
48 | @menuName 菜单名称
49 | @menuId 菜单id
50 | @menuIcon 菜单图标英文单词
51 | @menuPath 菜单对应的路由路径
52 | @viewRoute路径信息
53 | @actionFrom 调用tab-add方法事件来源
54 | */
55 | add(menuName, menuId, menuIcon, menuPath,viewComponentPath,isOutPage, actionFrom = 'menu') {
56 | if (this.tabs.curMenuItem.path === menuPath || menuName === '') return
57 |
58 | // tepItem 变量用于后面的数组方法:push,不能直接使用this.tabs.curMenuItem ,否则永远只会添加成功最一条
59 | const tepItem = Object.assign({}, this.tabs.item)
60 | tepItem.name = menuName
61 | tepItem.isActive = true
62 | tepItem.relaMenuId = menuId
63 | tepItem.icon = menuIcon
64 | tepItem.path = menuPath
65 | // 以下两个参数主要标记被加载的页面是否为外部页面,决定个后续渲染组件究竟时使用 view-router 或者 iframe
66 | tepItem.viewComponentPath = viewComponentPath
67 | tepItem.isOutPage = isOutPage
68 |
69 | this.tabs.curMenuItem = Object.assign({}, tepItem)
70 |
71 | const exists = this.tabs.list.some(item => {
72 | return item.relaMenuId === menuId
73 | })
74 | // 如果菜单对应的tab不存在,则添加
75 | if (!exists) {
76 | this.tabs.list.push(tepItem)
77 | // 如果菜单对应的tab存在,则激活
78 | }
79 |
80 | this.syncChangeRouter(menuPath, actionFrom)
81 | this.activeTab(menuId)
82 |
83 | const menuStore = useMenuStore()
84 | menuStore.setMenuNavPathList(menuId)
85 | menuStore.menu.defaultActive = menuPath
86 | },
87 |
88 | /* 删除 tab 导航按钮
89 | @item tab单条数据
90 | @curTabIsActive 被删除的tab是否处于激活状态
91 | */
92 | remove(relaMenuId, curTabIsActive) {
93 | let tabIndex = this.indexOf(relaMenuId)
94 | let nextTabName = ''
95 | let nextTabIndex = -1 // 下一个需要激活的 tab 页签的索引
96 | this.tabs.list.splice(tabIndex, 1)
97 | if (!curTabIsActive) {
98 | return
99 | }
100 | if (this.tabs.list.length > 0 && this.tabs.list.length === tabIndex) {
101 | nextTabIndex = tabIndex - 1
102 | this.tabs.list[nextTabIndex].isActive = true
103 | } else if (this.tabs.list.length > 1) {
104 | nextTabIndex = tabIndex
105 | this.tabs.list[nextTabIndex].isActive = true
106 | }
107 | if (this.tabs.list.length > 0) {
108 | this.tabs.curMenuItem.relaMenuId = this.tabs.list[nextTabIndex].relaMenuId
109 | this.tabs.curMenuItem.path = this.tabs.list[nextTabIndex].path
110 | this.tabs.curMenuItem.viewComponentPath = this.tabs.list[nextTabIndex].viewComponentPath
111 | this.tabs.curMenuItem.isOutPage = this.tabs.list[nextTabIndex].isOutPage
112 | this.syncChangeRouter(this.tabs.curMenuItem.path, 'tab')
113 | } else {
114 | //关闭最后一个tab页签,直接调用全部关闭方法即可
115 | this.closeAllTabs()
116 | }
117 | },
118 |
119 | /* 寻找数组中的某个元素的索引
120 | @item tab单条数据
121 | */
122 | indexOf(relaMenuId) {
123 | for (let i = 0; i < this.tabs.list.length; i++) {
124 | if (this.tabs.list[i].relaMenuId === relaMenuId) return i;
125 | }
126 | return -1;
127 | },
128 |
129 | /* 激活选中的tab页签,同时设置其他tab页签为未激活
130 | @item tab单条数据
131 | */
132 | activeTab(menuId) {
133 | const needActiveTabIndex = this.indexOf(menuId)
134 | this.tabs.list.forEach((item, index) => this.tabs.list[index].isActive = index === needActiveTabIndex)
135 | },
136 |
137 | /*
138 | 点击 tab 页签时与路由联动
139 | */
140 | syncChangeRouter(path, actionFrom) {
141 | const routerStore = useRouteStore()
142 | if (actionFrom !== 'menu' && path !== routerStore.getRoute.currentRoute.path) {
143 | routerStore.getRoute.push(path)
144 | }
145 | },
146 |
147 | /*
148 | 关闭非选中的其它tab页签
149 | */
150 | closeOtherTabs() {
151 | if (this.tabs.list.length === 0) return
152 | this.tabs.list[0] = this.tabs.curMenuItem
153 | this.tabs.list.splice(1, this.tabs.list.length - 1)
154 | },
155 | /*
156 | 关闭所有tab页签
157 | */
158 | closeAllTabs() {
159 | this.tabs.list = []
160 | useMenuStore().menu.defaultActive = ''
161 | commonFunc.objInit(this.tabs.curMenuItem)
162 | this.syncChangeRouter('/blank_page', 'tab')
163 | },
164 |
165 | /*
166 | 退出时, 销毁本对象
167 | */
168 | destroy() {
169 | commonFunc.objInit(this.tabs)
170 | },
171 |
172 | /*
173 | * 获取当前路由path
174 | * */
175 | getCurMenuItem() {
176 | return this.tabs.curMenuItem
177 | },
178 |
179 | }
180 |
181 |
182 | })
183 |
--------------------------------------------------------------------------------
/src/store/system-setting/user.js:
--------------------------------------------------------------------------------
1 | import {defineStore} from 'pinia'
2 | import commonFunc from '@/libs/common_func'
3 | import {clearCookie, clearLocalStorageAll} from '@/libs/util'
4 | import {useTabStore} from '@/store/system-setting/tabs'
5 | import config from '@/config/index'
6 |
7 | export const useUserStore = defineStore(
8 | {
9 | id: 'useUserStore',
10 | persist: {
11 | enabled: true,
12 | strategies: [
13 | {
14 | key: config.dataStore.keyPre + 'useUserStore',
15 | storage: localStorage,
16 | paths: ['user'] // 设置需要持久存储的键名
17 | }
18 | ]
19 | },
20 | state: () => {
21 | return {
22 | user: {
23 | info: {
24 | id: 0,
25 | user_name: '',
26 | real_name: '',
27 | avatar: '',
28 | fullAvatarUrl: '',
29 | login_times: 0,
30 | phone: '',
31 | },
32 | token: {
33 | isValid: false,
34 | val: "",
35 | }
36 | },
37 | }
38 | },
39 | getters: {
40 | getUserInfo() {
41 | return this.user.info
42 | },
43 | },
44 | actions: {
45 | /*
46 | 登陆成功初始化一下用户最基本信息
47 | */
48 | setUserBaseInfo(userId, token) {
49 | this.user.info.id = userId
50 | this.user.token.val = token
51 | this.user.token.isValid = true
52 | },
53 |
54 | /**
55 | * 设置用户的完整信息
56 | * @param userInfo
57 | */
58 | setUserInfo(userInfo) {
59 | this.user.info.id = userInfo.id
60 | this.user.info.user_name = userInfo.user_name
61 | this.user.info.real_name = userInfo.real_name
62 | this.user.info.avatar = userInfo.avatar
63 | this.user.info.fullAvatarUrl = commonFunc.getServerIp() + userInfo.avatar
64 | this.user.info.phone = userInfo.phone
65 | this.user.info.login_times = userInfo.login_times
66 | this.user.token.isValid = true
67 | this.user.token.val = userInfo.token
68 | },
69 |
70 | /*
71 | 退出登陆时需要销毁的对象,可以全部集群在这里调用去销毁
72 | */
73 | destroyUserInfo() {
74 | clearCookie()
75 | clearLocalStorageAll()
76 | commonFunc.objInit(this.user)
77 | useTabStore().destroy()
78 | }
79 | }
80 | }
81 | )
--------------------------------------------------------------------------------
/src/views/data-dictionary/province_city.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
--------------------------------------------------------------------------------
/src/views/home/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Admin2 系统基于 GinSkeleton(v1.5.xx + javascript + elementPlus + Vite3.x +Vue3.x + vue-router4.x + pinia 等最新技术开发
5 |
6 |
7 |
8 |
9 |
10 |
11 |
14 |
15 |
--------------------------------------------------------------------------------
/src/views/layout/main.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
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 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
198 |
199 |
217 |
--------------------------------------------------------------------------------
/src/views/statistical-report/employees.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
12 |
--------------------------------------------------------------------------------
/src/views/statistical-report/train_timetable.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/src/views/system-setting/auth_analysis.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/src/views/system-setting/auth_assignment.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/src/views/system-setting/blank_page.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/src/views/system-setting/button_cn_en.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/src/views/system-setting/login.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
20 |
21 |
40 |
--------------------------------------------------------------------------------
/src/views/system-setting/org_members.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/src/views/system-setting/organization.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/src/views/system-setting/sys_menu.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/src/views/system-setting/user.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/vite.config.mjs:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import {defineConfig} from 'vite'
3 | import vue from '@vitejs/plugin-vue'
4 | import AutoImport from 'unplugin-auto-import/vite'
5 | import Components from 'unplugin-vue-components/vite'
6 | import {ElementPlusResolver} from 'unplugin-vue-components/resolvers'
7 | import Inspect from 'vite-plugin-inspect'
8 |
9 | const baseUrl = {
10 | development: './',
11 | release: './'
12 | }
13 |
14 | const pathSrc = path.resolve(__dirname, 'src')
15 | export default ({mode}) => defineConfig({
16 | base: baseUrl[mode],
17 | server: {
18 | host: '0.0.0.0'
19 | },
20 | resolve: {
21 | alias: {
22 | '@': pathSrc,
23 | '_c': path.resolve(__dirname, 'src/components'),
24 | }
25 | },
26 | plugins: [
27 | vue(),
28 | AutoImport({
29 | resolvers: [
30 | ElementPlusResolver(),
31 | ],
32 | dts: path.resolve(pathSrc, 'auto-imports.d.ts'),
33 | }),
34 | Components({
35 | directoryAsNamespace: true,
36 | resolvers: [
37 | ElementPlusResolver(),
38 | ],
39 | dts: path.resolve(pathSrc, 'components.d.ts'),
40 | }),
41 | Inspect(),
42 | ],
43 | build: {
44 | chunkSizeWarningLimit: 5000
45 | }
46 | })
47 |
--------------------------------------------------------------------------------