├── mock
├── modules
│ ├── comm.json
│ ├── adminUser.json
│ ├── bannerIndex.json
│ ├── login.json
│ └── logAdminopr.json
└── index.ts
├── public
├── logo.png
├── favicon.ico
├── logo-mini.png
├── images
│ ├── avatar.jpeg
│ ├── figure-1.png
│ ├── figure-2.png
│ ├── plant-1.png
│ ├── plant-2.png
│ ├── 21ac2b09aa79bd2244d244fff4d76447.jpg
│ ├── 4e558470e518f2d2950149a807ac0fef.jpeg
│ ├── ad35dddcf60f2f00dba3b2fa8883bfcb.jpeg
│ ├── b2553ba0e33d8203503477b46a0029ff.jpeg
│ ├── e29d994ec3d5d2424ce5448d816d9e20.jpeg
│ ├── eed68c68672f38f2933951d6910069c8.jpg
│ └── f8c1fb49d1da365a80ee8d430e1e22a6.jpeg
├── assets
│ ├── images
│ │ ├── null.jpg
│ │ ├── logo
│ │ │ ├── qq.png
│ │ │ ├── baidu.png
│ │ │ ├── douyin.png
│ │ │ ├── email.png
│ │ │ ├── google.png
│ │ │ ├── taobao.png
│ │ │ ├── weixin.png
│ │ │ ├── xigua.png
│ │ │ ├── bilibili.png
│ │ │ ├── facebook.png
│ │ │ ├── jingdong.png
│ │ │ ├── kuaishou.png
│ │ │ ├── toutiao.png
│ │ │ ├── twitter.png
│ │ │ ├── youtube.png
│ │ │ └── zhifubao.png
│ │ └── login_avatar.jpg
│ └── css
│ │ └── custom.css
└── index.html
├── babel.config.js
├── src
├── assets
│ └── images
│ │ └── bg1.jpg
├── config
│ ├── index.ts
│ ├── modules
│ │ ├── base.ts
│ │ ├── HUrl.ts
│ │ ├── global.ts
│ │ └── cdn.ts
│ └── config.ts
├── store
│ ├── index.ts
│ ├── init.ts
│ └── modules
│ │ └── setting.ts
├── utils
│ ├── index.ts
│ └── modules
│ │ ├── cache.ts
│ │ ├── comm.ts
│ │ └── setting.ts
├── main.ts
├── App.vue
├── shims-vue.d.ts
├── views
│ ├── layout
│ │ ├── components
│ │ │ ├── main.vue
│ │ │ ├── setting
│ │ │ │ ├── affix.vue
│ │ │ │ ├── alert-message.vue
│ │ │ │ └── drawer.vue
│ │ │ ├── header
│ │ │ │ ├── collapse.vue
│ │ │ │ ├── logo.vue
│ │ │ │ ├── toolbar.vue
│ │ │ │ ├── breadcrumb.vue
│ │ │ │ ├── index.vue
│ │ │ │ └── profile.vue
│ │ │ ├── index.ts
│ │ │ └── aside
│ │ │ │ ├── submenu.vue
│ │ │ │ └── index.vue
│ │ └── index.vue
│ ├── dashboard
│ │ ├── index.vue
│ │ └── readme.en.vue
│ ├── error
│ │ └── 404.vue
│ ├── form
│ │ ├── image.vue
│ │ ├── index.vue
│ │ └── other.vue
│ ├── log
│ │ └── admin
│ │ │ └── operate.vue
│ ├── auth
│ │ └── login.vue
│ ├── banner
│ │ └── index
│ │ │ └── index.vue
│ └── admin
│ │ └── user
│ │ └── index.vue
├── service
│ ├── index.ts
│ ├── modules
│ │ ├── banner
│ │ │ └── index.ts
│ │ ├── log
│ │ │ └── adminopr.ts
│ │ ├── admin
│ │ │ └── admin.ts
│ │ └── auth
│ │ │ └── auth.ts
│ └── http
│ │ ├── code.ts
│ │ └── index.ts
├── router
│ ├── modules
│ │ ├── components.ts
│ │ └── routes.ts
│ └── index.ts
└── init.ts
├── .editorconfig
├── .gitignore
├── tsconfig.json
├── LICENSE
├── vue.config.js
├── package.json
├── .eslintrc.js
├── README.md
└── README.en.md
/mock/modules/comm.json:
--------------------------------------------------------------------------------
1 | {
2 | "code": 0,
3 | "message": "操作成功!"
4 | }
--------------------------------------------------------------------------------
/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/logo.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/logo-mini.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/logo-mini.png
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/public/images/avatar.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/images/avatar.jpeg
--------------------------------------------------------------------------------
/public/images/figure-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/images/figure-1.png
--------------------------------------------------------------------------------
/public/images/figure-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/images/figure-2.png
--------------------------------------------------------------------------------
/public/images/plant-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/images/plant-1.png
--------------------------------------------------------------------------------
/public/images/plant-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/images/plant-2.png
--------------------------------------------------------------------------------
/src/assets/images/bg1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/src/assets/images/bg1.jpg
--------------------------------------------------------------------------------
/public/assets/images/null.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/assets/images/null.jpg
--------------------------------------------------------------------------------
/public/assets/images/logo/qq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/assets/images/logo/qq.png
--------------------------------------------------------------------------------
/public/assets/images/logo/baidu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/assets/images/logo/baidu.png
--------------------------------------------------------------------------------
/public/assets/images/logo/douyin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/assets/images/logo/douyin.png
--------------------------------------------------------------------------------
/public/assets/images/logo/email.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/assets/images/logo/email.png
--------------------------------------------------------------------------------
/public/assets/images/logo/google.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/assets/images/logo/google.png
--------------------------------------------------------------------------------
/public/assets/images/logo/taobao.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/assets/images/logo/taobao.png
--------------------------------------------------------------------------------
/public/assets/images/logo/weixin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/assets/images/logo/weixin.png
--------------------------------------------------------------------------------
/public/assets/images/logo/xigua.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/assets/images/logo/xigua.png
--------------------------------------------------------------------------------
/public/assets/images/login_avatar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/assets/images/login_avatar.jpg
--------------------------------------------------------------------------------
/public/assets/images/logo/bilibili.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/assets/images/logo/bilibili.png
--------------------------------------------------------------------------------
/public/assets/images/logo/facebook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/assets/images/logo/facebook.png
--------------------------------------------------------------------------------
/public/assets/images/logo/jingdong.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/assets/images/logo/jingdong.png
--------------------------------------------------------------------------------
/public/assets/images/logo/kuaishou.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/assets/images/logo/kuaishou.png
--------------------------------------------------------------------------------
/public/assets/images/logo/toutiao.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/assets/images/logo/toutiao.png
--------------------------------------------------------------------------------
/public/assets/images/logo/twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/assets/images/logo/twitter.png
--------------------------------------------------------------------------------
/public/assets/images/logo/youtube.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/assets/images/logo/youtube.png
--------------------------------------------------------------------------------
/public/assets/images/logo/zhifubao.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/assets/images/logo/zhifubao.png
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{js,jsx,ts,tsx,vue}]
2 | indent_style = space
3 | indent_size = 2
4 | trim_trailing_whitespace = true
5 | insert_final_newline = true
6 |
--------------------------------------------------------------------------------
/public/images/21ac2b09aa79bd2244d244fff4d76447.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/images/21ac2b09aa79bd2244d244fff4d76447.jpg
--------------------------------------------------------------------------------
/public/images/4e558470e518f2d2950149a807ac0fef.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/images/4e558470e518f2d2950149a807ac0fef.jpeg
--------------------------------------------------------------------------------
/public/images/ad35dddcf60f2f00dba3b2fa8883bfcb.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/images/ad35dddcf60f2f00dba3b2fa8883bfcb.jpeg
--------------------------------------------------------------------------------
/public/images/b2553ba0e33d8203503477b46a0029ff.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/images/b2553ba0e33d8203503477b46a0029ff.jpeg
--------------------------------------------------------------------------------
/public/images/e29d994ec3d5d2424ce5448d816d9e20.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/images/e29d994ec3d5d2424ce5448d816d9e20.jpeg
--------------------------------------------------------------------------------
/public/images/eed68c68672f38f2933951d6910069c8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/images/eed68c68672f38f2933951d6910069c8.jpg
--------------------------------------------------------------------------------
/public/images/f8c1fb49d1da365a80ee8d430e1e22a6.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todoadmin/vue-admin-chart/HEAD/public/images/f8c1fb49d1da365a80ee8d430e1e22a6.jpeg
--------------------------------------------------------------------------------
/src/config/index.ts:
--------------------------------------------------------------------------------
1 | // 设置相关功能 文件
2 | import * as G from '@/config/modules/global'
3 | import * as HUrl from '@/config/modules/HUrl'
4 |
5 | export {
6 | G,
7 | HUrl
8 | }
9 |
--------------------------------------------------------------------------------
/src/store/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Store 仓库存储相关操作(使用Pinia作为默认存储,不适用vuex)
3 | */
4 | // 设置、用户、临时数据相关
5 | import settingStore from './modules/setting'
6 |
7 | export {
8 | settingStore,
9 | }
10 |
--------------------------------------------------------------------------------
/src/store/init.ts:
--------------------------------------------------------------------------------
1 | import { createPinia } from 'pinia' // 导入pinia存储store库
2 |
3 | // store存储持久化
4 | import piniaPersist from 'pinia-plugin-persist'
5 |
6 | // 创建pinia的store实例
7 | const store = createPinia()
8 | store.use(piniaPersist)
9 | export default store
10 |
--------------------------------------------------------------------------------
/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | // 设置相关功能 文件
2 | import * as setting from '@/utils/modules/setting'
3 | // 公共函数类库
4 | import * as comm from '@/utils/modules/comm'
5 | // session,localstorage缓存操作相关
6 | import cache from '@/utils/modules/cache'
7 |
8 | export {
9 | setting,
10 | comm,
11 | cache,
12 | }
13 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 | import { init } from './init' // 引入init初始化文件,尽可能减少对vue框架文件的修改
4 |
5 | const app = createApp(App)
6 | // 初始化相关的属性
7 | init({ app }).then(async ({ router }) => {
8 | router.isReady().then(() => app.mount('#app'))
9 | })
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw?
24 | *.tgitconfig
25 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
19 |
20 |
25 |
--------------------------------------------------------------------------------
/src/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | declare module '*.vue' {
3 | import type { DefineComponent } from 'vue'
4 | const component: DefineComponent<{}, {}, any>
5 | export default component
6 | }
7 |
8 | declare module '*.json' {
9 | const value: any;
10 | export default value;
11 | }
12 |
13 | declare module 'js-md5' {
14 | import md5 from 'js-md5'
15 | export default md5
16 | }
17 | declare module "*.md"
18 |
--------------------------------------------------------------------------------
/src/views/layout/components/main.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
20 |
21 |
23 |
--------------------------------------------------------------------------------
/src/service/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 数据请求服务接口相关API或函数处理
3 | * @author jihua.huang
4 | * @since 2022-03-15
5 | */
6 | import http from '@/service/http'
7 | import * as SAuth from './modules/auth/auth'
8 | import * as SAdmin from './modules/admin/admin'
9 | import * as SLogAdminOpr from './modules/log/adminopr'
10 | import * as SBanner from './modules/banner/index'
11 |
12 | export {
13 | http,
14 | SAuth,
15 | SAdmin,
16 | SBanner,
17 | SLogAdminOpr,
18 | }
19 |
--------------------------------------------------------------------------------
/public/assets/css/custom.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";.el-sub-menu__title:hover{background:transparent !important;}.theme-default{background:#001529;}.theme-default.collapse-sub-menu{background:#fff !important;}.theme-default .el-sub-menu__title{color:#fff !important;}.theme-default > .logo{color:#dedede;}.theme-default .el-menu-item,.theme-default .el-sub-menu__title{color:#f1f1f1;}.theme-default > li:hover,.theme-default.df-sub-menu:hover,.theme-default > li.is-active,.theme-default.df-sub-menu.is-active{color:#f1f2f3 !important;background-color:#409eff !important;}
--------------------------------------------------------------------------------
/src/service/modules/banner/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 封装广告橱窗功能、比如:列表、添加、删除、修改、审核功能等
3 | * @author jihua.huang
4 | * @date 2022-04-26
5 | */
6 | //引入文件
7 | import { http } from "@/service"; //引入网络请求http
8 | import { HUrl } from "@/config"; //引入http请求URL地址
9 |
10 | /**
11 | * 列表
12 | * @param params object
13 | * @returns json object
14 | */
15 | export const list = async (params : any = {}) => {
16 | let data: any;
17 | await http.get(HUrl.BANNER_URL,params).then((result : any) => {
18 | data = result;
19 | }).catch((err: any) => {
20 | http.catch(err)
21 | });
22 | return data;
23 | }
24 |
--------------------------------------------------------------------------------
/src/service/modules/log/adminopr.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 封装日志Log(管理员操作日志)相关功能等
3 | * @author jihua.huang
4 | * @date 2022-04-10
5 | */
6 | //引入文件
7 | import { http } from "@/service"; //引入网络请求http
8 | import { HUrl } from "@/config"; //引入http请求URL地址
9 |
10 | /**
11 | * 列表
12 | * @param params object
13 | * @returns json object
14 | */
15 | export const list = async (params : any = {}) => {
16 | let data: any;
17 | await http.get(HUrl.LOG_ADMIN_OPR_URL,params).then((result : any) => {
18 | data = result;
19 | }).catch((err: any) => {
20 | http.catch(err)
21 | });
22 | return data;
23 | }
24 |
--------------------------------------------------------------------------------
/src/service/modules/admin/admin.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 封装管理员功能、比如:列表、添加、删除、修改、审核、角色、权限、功能等
3 | * @author jihua.huang
4 | * @date 2022-03-29
5 | */
6 | //引入文件
7 | import { http } from "@/service"; //引入网络请求http
8 | import { HUrl } from "@/config"; //引入http请求URL地址
9 |
10 | /**
11 | * 列表
12 | * @param params object
13 | * @returns json object
14 | */
15 | export const list = async (params : any = {}) => {
16 | let data: any;
17 | await http.get(HUrl.ADMIN_URL,params).then((result : any) => {
18 | data = result;
19 | }).catch((err: any) => {
20 | http.catch(err)
21 | });
22 | return data;
23 | }
24 |
--------------------------------------------------------------------------------
/src/config/modules/base.ts:
--------------------------------------------------------------------------------
1 | /*HTTP Restful API 数据交换地址 */
2 | //Production 生产环境
3 | if (process.env.NODE_ENV === 'production') {
4 | //http restful API 请求地址
5 | exports.BASE_URL = 'https://api.todoadmin.com'
6 | } else {
7 | //Dev开发环境 http restful API 请求地址
8 | exports.BASE_URL = 'http://localhost:8080'
9 | }
10 | /** 后缀地址(可以为版本目录,如:/v1) */
11 | exports.PREFIX_PATH = '/v1'
12 |
13 | //DEV host 地址
14 | exports.DEV_HOST = 'localhost'
15 | //DEV port 端口
16 | exports.DEV_PORT = '8080'
17 | //DEV proxy
18 | exports.PROXY_ROOT = '/api'
19 | //DEV环境数据使用 mock数据 还是api接口数据
20 | //value: mock | api
21 | exports.DEV_DATA_SOURCE = 'mock'
22 |
--------------------------------------------------------------------------------
/src/views/dashboard/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
29 |
30 |
--------------------------------------------------------------------------------
/src/config/modules/HUrl.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 接口请求地址配置信息
3 | * @author jihua.huang
4 | * @since 2022-03-19
5 | */
6 | //引入基本配置文件base.js
7 | const BASE = require("./base.ts")
8 |
9 | //HTTP RESTFUL根地址
10 | export const HTTP_BASE_URL = BASE.BASE_URL
11 |
12 | /** 后缀地址(可以为版本目录,如:/v1) */
13 | export const BASE_PREFIX = HTTP_BASE_URL + BASE.PREFIX_PATH
14 |
15 | /** 用户登陆提交数据接口 */
16 | export const LOGIN_URL = BASE_PREFIX + '/auth/login'
17 | /** 用户登出提交数据接口 */
18 | export const LOGOUT_URL = BASE_PREFIX + '/auth/logout'
19 | /** 管理员管理提交数据接口 */
20 | export const ADMIN_URL = BASE_PREFIX + '/admin/user'
21 |
22 | /** 广告橱窗数据接口 */
23 | export const BANNER_URL = BASE_PREFIX + '/banner/index'
24 |
25 | /** 管理员操作日志数据接口 */
26 | export const LOG_ADMIN_OPR_URL = BASE_PREFIX + '/log/adminopr'
--------------------------------------------------------------------------------
/src/views/layout/components/setting/affix.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 设置
4 |
5 |
6 |
22 |
34 |
--------------------------------------------------------------------------------
/src/config/config.ts:
--------------------------------------------------------------------------------
1 | /*HTTP Restful API 数据交换地址 */
2 | // 是否是生产环境
3 | const PRODUCTION = process.env.NODE_ENV === 'production'
4 | //获取CDN相关的配置
5 | const CDN = require('./modules/cdn.ts')
6 | //获取基本的配置
7 | const BASE = require('./modules/base.ts')
8 |
9 | //资源环境
10 | exports.PRODUCTION = PRODUCTION
11 | //静态资源CDN
12 | exports.EXTERNALS = PRODUCTION ? CDN.PROD_EXTERNALS : CDN.DEV_EXTERNALS
13 | //静态资源CDN
14 | exports.STATIC_CDN = PRODUCTION ? CDN.prodCDN : CDN.devCDN
15 | //资源环境
16 | //Api restful 地址
17 | exports.BASE_URL = BASE.BASE_URL
18 | //DEV host 地址
19 | exports.DEV_HOST = BASE.DEV_HOST
20 | //DEV port 端口
21 | exports.DEV_PORT = BASE.DEV_PORT
22 | //DEV proxy
23 | exports.PROXY_ROOT = BASE.PROXY_ROOT
24 | //DEV环境数据使用 mock数据 还是api接口数据
25 | //value: mock | api default value: api
26 | exports.DEV_DATA_SOURCE = BASE.DEV_DATA_SOURCE || 'mock'
27 |
--------------------------------------------------------------------------------
/src/views/dashboard/readme.en.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
29 |
30 |
31 |
41 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "esnext",
5 | "strict": true,
6 | "jsx": "preserve",
7 | "moduleResolution": "node",
8 | "skipLibCheck": true,
9 | "esModuleInterop": true,
10 | "allowSyntheticDefaultImports": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "useDefineForClassFields": true,
13 | "sourceMap": true,
14 | "baseUrl": ".",
15 | "types": [
16 | "webpack-env"
17 | ],
18 | "paths": {
19 | "@/*": [
20 | "src/*"
21 | ]
22 | },
23 | "lib": [
24 | "esnext",
25 | "dom",
26 | "dom.iterable",
27 | "scripthost"
28 | ]
29 | },
30 | "include": [
31 | "src/**/*.ts",
32 | "src/**/*.tsx",
33 | "src/**/*.vue",
34 | "tests/**/*.ts",
35 | "tests/**/*.tsx"
36 | ],
37 | "exclude": [
38 | "node_modules"
39 | ]
40 | }
41 |
--------------------------------------------------------------------------------
/src/service/http/code.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * http response 返回code的特殊处理
3 | * @author jihua.huang
4 | * @date 2022-04-02
5 | */
6 |
7 | export const responseCode = [
8 | 10000,//系统强制升级直接退出,(不可使用)
9 | 10001,//系统可升级(可使用)
10 | 10002,//系统全局重要通知,(不可使用)【点击确认直接退出】
11 | 10003,//系统全局重要通知,(可使用)【点击确认关闭提示窗,系统可继续使用】
12 | 10004,//任何信息的公告,比如:提示部分用户或者所有用户,在xx时候充值赠送红包,红包可进行购买任何东西,但不能提现,(可使用)【点击确认关闭提示窗,系统可继续使用】
13 | 10006,//缺少参数
14 | 10007,//系统繁忙,请稍后重试!
15 | 10008,//请求超时,请稍后重试!
16 | 10009,//非法请求
17 | 10010,//接口访问权限受限
18 | 10011,//请求长度超过限制
19 | 10012,//接口不存在
20 | 10013,//IP请求频次超过上限
21 | 10014,//用户请求频次超过上限
22 | 10015,//token未被授权
23 | 10016,//APP未被授权
24 | 10017,//用户未授权
25 | 10018,//接口签名不合法
26 | 10019,//token失效
27 | 10020,//该设备信息异常
28 | 10021,//认证已失效,请重新登录系统
29 | 10022,//权限不足,请联系管理员
30 | 10023,//记录不存在
31 | 10024,//未知错误
32 | 10026,//请求过于频繁,请稍后重试
33 | 10300,//在代码中传入message错误信息即可
34 | ]
--------------------------------------------------------------------------------
/src/views/layout/components/header/collapse.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
27 |
28 |
40 |
--------------------------------------------------------------------------------
/src/views/layout/components/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 维护component的所有共用组件,以便统一调用
3 | * 直接调用index.ts文件,相关的组件名即可,不需要调用不通目录下的vue文件
4 | * @Author: jihua.huang
5 | * @Since: 2022-03-17
6 | */
7 | // ==========主模板==========
8 | export { default as Main } from './main.vue'
9 |
10 | // ==========左边菜单栏==========
11 | export { default as CompAside } from './aside/index.vue'
12 | export { default as CompAsideSubmenu } from './aside/submenu.vue'
13 |
14 | // ==========头部工具栏(收缩、面包屑、工具栏、用户profile、logo、通知信息、tabs页面标签等)==========
15 | // ----------头部Index包含(收缩、面包屑、工具栏、用户profile)----------
16 | export { default as CompHeader } from './header/index.vue'
17 | export { default as CompHeaderLogo } from './header/logo.vue'
18 |
19 | // ==========设置(工具箱、消息弹出层等)==========
20 | export { default as CompSettingAlertMessage } from './setting/alert-message.vue'
21 |
22 | // ===========回到顶部===============
23 | export { default as CompAffix } from './setting/affix.vue'
24 | export { default as CompDrawer } from './setting/drawer.vue'
25 |
--------------------------------------------------------------------------------
/src/views/layout/components/header/logo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
22 |
23 |
41 |
--------------------------------------------------------------------------------
/src/views/layout/components/header/toolbar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
27 |
28 |
45 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 TodoAdmin
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.
22 |
--------------------------------------------------------------------------------
/src/views/error/404.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 返回登陆页面
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
40 |
--------------------------------------------------------------------------------
/src/router/modules/components.ts:
--------------------------------------------------------------------------------
1 | //========================对应的Route component Vue组件模板地址(非赖加载方式)======================
2 | import Layout from '@/views/layout/index.vue'
3 | import LoginLayout from '@/views/auth/login.vue'
4 | import NotFound from '@/views/error/404.vue'
5 | //========================对应的Route component Vue组件模板地址(非赖加载方式)======================
6 |
7 | //========================对应的Route component Vue组件模板地址(赖加载方式)======================
8 | //首页
9 | const Home = () => import('@/views/dashboard/index.vue')
10 | //广告橱窗首页
11 | const BannerIndex = () => import('@/views/banner/index/index.vue')
12 | //管理员管理首页
13 | const AdminUser = () => import('@/views/admin/user/index.vue')
14 | //日志管理-管理员操作日志首页
15 | const LogAdminOpr = () => import('@/views/log/admin/operate.vue')
16 | //README
17 | const ReadMeEN = () => import('@/views/dashboard/readme.en.vue')
18 |
19 | //========================对应的Route component Vue组件模板地址(赖加载方式)======================
20 |
21 | export const componentRouter = {
22 | 'Layout':Layout,
23 | 'LoginLayout':LoginLayout,
24 | 'NotFound':NotFound,
25 | 'Home':Home,
26 | 'BannerIndex':BannerIndex,
27 | 'AdminUser':AdminUser,
28 | 'LogAdminOpr':LogAdminOpr,
29 | 'ReadMeEN':ReadMeEN,
30 | }
31 |
--------------------------------------------------------------------------------
/src/init.ts:
--------------------------------------------------------------------------------
1 | /*
2 | 此文件的创建目的是为了尽可能减少对vue框架本身文件的修改
3 | 此文件是:初始化相关组件、插件、存储、网络、图标,以及引入样式、JS/TS文件等
4 | */
5 | import router from './router' // 路由
6 | import store from './store/init' // store 存储仓库
7 | import ElementPlus from 'element-plus' // 引入ElementPlus
8 | import * as ElementPlusIconsVue from '@element-plus/icons-vue'
9 |
10 | //当为非生产环境(!production)时导入mock
11 | if (process.env.NODE_ENV !== "production") {
12 | require("element-plus/dist/index.css")
13 | //引入配置文件config.js
14 | const conf = require("./config/config.ts")
15 | //DEV环境数据使用 mock数据 还是api接口数据
16 | //value: mock || api default value: api
17 | if (conf.DEV_DATA_SOURCE === 'mock') {
18 | // import { mockXHR } from './../mock/index'; // 引入自定义的mock
19 | const MockM = require("./../mock/index.ts");
20 | const mockXHR = MockM.mockXHR;
21 | mockXHR()
22 | }
23 | }
24 |
25 | export async function init(options: { app: any }) {
26 | const { app } = options
27 | app.use(store)
28 | app.use(router)
29 | // 引入ElementPlus以及初始化相关的部分属性
30 | app.use(ElementPlus)
31 | // 初始化Element ICON图标
32 | for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
33 | app.component(key, component)
34 | }
35 | //ElIcon({ app })
36 | return { router }
37 | }
38 |
--------------------------------------------------------------------------------
/src/views/layout/components/setting/alert-message.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
12 |
13 |
14 |
15 |
39 |
--------------------------------------------------------------------------------
/src/router/index.ts:
--------------------------------------------------------------------------------
1 | import { createRouter,createWebHistory } from 'vue-router'
2 |
3 | import { routes, existWhite } from './modules/routes'
4 | import { ElMessage } from 'element-plus'
5 | import { cache } from '@/utils';
6 | import { G } from '@/config'
7 |
8 | const router = createRouter({
9 | history: createWebHistory(),
10 | routes
11 | })
12 |
13 | // 导航路由守卫
14 | router.beforeEach((to:any, from:any, next:any) => {
15 | try {
16 | const title = to.meta && to.meta.title;
17 | if (title) {
18 | document.title = title;
19 | }
20 | // 路由在白名单里面
21 | if (existWhite(to.path)) {
22 | next()
23 | } else {
24 | const token = cache.getLocalStorage(G.AUTHORIZATION_TOKEN)
25 | // 如果token或userInfo为空、null、{}则跳转到指定login页面进行登陆
26 | if (!token) {
27 | // 保存我们所在的位置,以便以后再来
28 | next(G.LOGIN_URL);
29 | } else {
30 | if (to.matched.length === 0) {
31 | ElMessage.error('找不到路由-NotFound Router...')
32 | from.name ? next({ path: from.path, query: from.query }) : next(G.NOTFOUND_URL)
33 | } else {
34 | next()
35 | }
36 | }
37 | }
38 | } catch (error) {
39 | throw error
40 | }
41 | })
42 |
43 | // 路由跳转后钩子函数中 - 执行进度条加载结束
44 | router.afterEach(() => {
45 | })
46 |
47 | export default router
48 |
--------------------------------------------------------------------------------
/src/views/layout/components/header/breadcrumb.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{item.title}}
6 |
7 |
8 |
9 |
10 |
11 |
34 |
35 |
48 |
--------------------------------------------------------------------------------
/src/views/layout/components/header/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
40 |
41 |
52 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | <%= htmlWebpackPlugin.options.title %>
8 |
9 |
10 | <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
11 |
12 |
13 | <% } %>
14 |
15 |
16 |
17 | We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.
18 |
19 |
20 |
21 |
22 |
23 | <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
24 |
25 | <% } %>
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/mock/index.ts:
--------------------------------------------------------------------------------
1 | import Mock from 'mockjs'
2 | //引入配置文件config.js
3 | const conf = require("../src/config/config.ts")
4 | // 设置拦截ajax请求的相应时间
5 | Mock.setup({
6 | timeout: '200-500'
7 | })
8 | //读取json文件
9 | function getJsonFile(filePath:string = '') {
10 | if (!filePath) return {}
11 | //读取指定json文件
12 | var json = require('./modules/' + filePath)
13 | return json
14 | }
15 |
16 | // 获取mock的响应数据
17 | const getResponse = (
18 | url: string,
19 | type: string,
20 | data: {}[],
21 | res: {}[],
22 | ) => {
23 | return {
24 | url,
25 | type: type || "get",
26 | response: (config: any) => {
27 | return res
28 | },
29 | }
30 | }
31 |
32 | //axios的请求地址,比如:http://api.xxx.com
33 | const MOCK_BASE_URL = conf.BASE_URL
34 | //api版本目录,比如:v1
35 | const PREFIX_PATH = conf.PREFIX_PATH
36 | const mocks = [
37 | getResponse(MOCK_BASE_URL + PREFIX_PATH + "/auth/login", "post", [], getJsonFile('login.json')),
38 | getResponse(MOCK_BASE_URL + PREFIX_PATH + "/auth/logout", "post", [], getJsonFile('comm.json')),
39 | getResponse(MOCK_BASE_URL + PREFIX_PATH + "/banner/index", "get", [], getJsonFile('bannerIndex.json')),
40 | getResponse(MOCK_BASE_URL + PREFIX_PATH + "/admin/user", "get", [], getJsonFile('adminUser.json')),
41 | getResponse(MOCK_BASE_URL + PREFIX_PATH + "/log/adminopr", "get", [], getJsonFile('logAdminopr.json')),
42 | ]
43 |
44 | export const mockXHR = () => {
45 | for (const i of mocks) {
46 | Mock.mock(new RegExp(i.url), i.type || "get", i.response)
47 | }
48 | }
--------------------------------------------------------------------------------
/src/config/modules/global.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 常量、相关配置信息
3 | */
4 | // 请求头验证的 Authorization token 字段名称
5 | export const AUTHORIZATION_TOKEN:string = 'token'
6 | // 路由菜单列表
7 | export const ROUTE_MENU:string = 'menu'
8 |
9 | // axios请求的timeout超时时间,多少秒
10 | export const AXIOS_TIMEOUT:number = 5000
11 |
12 | // 保存语言的cache storage对应 key
13 | export const LANG_KEY:string = 'LanguageKey'
14 |
15 | // 语言选择(先获取ver.lang的语言,如果ver.lang不存在,则获取LANG_DEFAULT常量的值) zh-cn:中文 en-us:英文 默认为:中文简体
16 | export const LANG_DEFAULT:string = 'zh-cn'
17 | // 默认主题皮肤
18 | export const THEME_DEFAULT = 'theme-default'
19 |
20 | // 保存过期时间的token key
21 | export const TOKEN_TIME_KEY = 'ExpireTime'
22 | // 过期时间有效时长
23 | export const TOKEN_TIME_VALUE = 2 * 24 * 60 * 60
24 |
25 | // 后台管理列表每页默认多少条
26 | export const TABLE_LIST_SIZE = 20
27 |
28 | // 跳转Login的URL地址
29 | export const LOGIN_URL = '/login';
30 | // 跳转Home的URL地址
31 | export const HOME_URL = '/';
32 | // 跳转404URL地址
33 | export const NOTFOUND_URL = '/404';
34 | // 地图map CDN地址 https://geo.datav.aliyun.com/areas_v3/bound = /amap
35 | export const MAPS_URL = {
36 | //'china':'https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json',
37 | 'china':'/api/assets/json/china.json',
38 | //'china':'https://geo.datav.aliyun.com/areas_v3/bound/geojson?code=100000_full',
39 | '100000':'https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json',
40 | };
41 |
42 | //Github项目仓库地址
43 | export const GITHUB_REPO_URL = 'https://github.com/todoadmin/vue-admin-chart'
44 | //Gitee 码云项目仓库地址
45 | export const GITEE_REPO_URL = 'https://gitee.com/todoadmin/vue-admin-chart'
46 |
--------------------------------------------------------------------------------
/mock/modules/adminUser.json:
--------------------------------------------------------------------------------
1 | {
2 | "code": 0,
3 | "message": "操作成功!",
4 | "data": {
5 | "list": [
6 | {
7 | "id": 24,
8 | "uqid": 188,
9 | "uid": 890770,
10 | "level": 10,
11 | "status": 1,
12 | "salt": 21227,
13 | "gender": 1,
14 | "create_time": 1650776342,
15 | "update_time": 0,
16 | "login_time": 0,
17 | "password": "8dfbb697ec9f75a074e26d67c5122511",
18 | "username": "ttttt",
19 | "truename": "哈市是",
20 | "ip": "2130706433",
21 | "email": "vpanda666@gmail.com",
22 | "remark": "哈哈哈12312312",
23 | "role": "[136, 134, 90, 112, 114, 118]",
24 | "extra": "[55, 163, 165, 170]"
25 | },
26 | {
27 | "id": 19,
28 | "uqid": 156,
29 | "uid": 777157,
30 | "level": 10,
31 | "status": 1,
32 | "salt": 6851,
33 | "gender": 2,
34 | "create_time": 1647396480,
35 | "update_time": 1647590886,
36 | "login_time": 1647590880,
37 | "password": "8f4ffa93791f8a92e7e5a1b1f490f1ac",
38 | "username": "admin",
39 | "truename": "管理员",
40 | "ip": "2130706433",
41 | "email": "test123456@admin.com",
42 | "remark": "143343",
43 | "role": "[118]",
44 | "extra": "[259, 261, 265, 267, 1425]"
45 | }
46 | ],
47 | "total": 2,
48 | "size": 2,
49 | "page": 1
50 | }
51 | }
--------------------------------------------------------------------------------
/src/views/layout/components/aside/submenu.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{ menu.meta.title }}
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | {{ subitem.meta.title }}
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
48 |
57 |
--------------------------------------------------------------------------------
/src/service/modules/auth/auth.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 封装登陆/登出/验证码/token等
3 | * @author jihua.huang
4 | * @date 2022-03-09
5 | */
6 | //引入文件
7 | import { http } from "@/service"; //引入网络请求http
8 | import { G,HUrl } from "@/config"; //引入http请求URL地址
9 | //导入 store的存储模块
10 | import { settingStore } from '@/store'
11 | // 导入cache模块
12 | import { cache } from '@/utils'
13 |
14 | /**
15 | * 用户登陆
16 | * @param params object
17 | * @returns json object
18 | */
19 | export const login = async (params : any) => {
20 | // 获取setting store
21 | const settStore = settingStore()
22 |
23 | let data: any;
24 | await http.post(HUrl.LOGIN_URL,params).then((result : any) => {
25 | //只处理code = 0的数据
26 | if (result.code === 0) {
27 | //type:0 为ping 心跳,不需处理,WS数据
28 | if (result.type !== 0) {
29 | // 设置token,并写入到store中
30 | let token = result.token || ''
31 | //Pinia 保存一份
32 | settStore.setToken(token)
33 | //LocalStorage原始也保存一份
34 | cache.setLocalStorage(G.AUTHORIZATION_TOKEN,token)
35 | }
36 |
37 | // 设置用户基本信息,并写入到store中
38 | let userInfo = result.data.userInfo
39 | if (userInfo) {
40 | settStore.setUserInfo(userInfo)
41 | }
42 | }
43 | data = result;
44 | }).catch((err: any) => {
45 | http.catch(err)
46 | });
47 | return data;
48 | }
49 |
50 |
51 | /**
52 | * 用户登出(需要清理相关的数据和缓存,已经初始化某些数据)
53 | * @param params object
54 | * @returns json object
55 | */
56 | export const logout = async (params : any) => {
57 | let data: any;
58 | await http.post(HUrl.LOGOUT_URL,params).then((result : any) => {
59 | //退出登陆要清理相关的localstrage和session缓存
60 | //清理session
61 | //清除localStorage所有的值
62 | cache.clearLocalStorage()
63 | data = result;
64 | }).catch((err: any) => {
65 | http.catch(err)
66 | });
67 | return data;
68 | }
69 |
--------------------------------------------------------------------------------
/src/config/modules/cdn.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 配置CDN相关 setting CDN
3 | */
4 | //获取package.json的属性内容
5 | const pack = require('../../../package.json')
6 | //获取package.json的依赖属性
7 | const ver = pack.dependencies
8 | //生产环境的CDN连接地址 production cdn link
9 | exports.prodCDN = {
10 | css: [
11 | 'https://cdn.bootcdn.net/ajax/libs/element-plus/' + ver['element-plus'].replace(/\~|\^/g, '') + '/index.css',
12 | 'https://cdn.bootcdn.net/ajax/libs/github-markdown-css/' + ver['github-markdown-css'].replace(/\~|\^/g, '') + '/github-markdown.min.css',
13 | ],
14 | js: [
15 | 'https://cdn.bootcdn.net/ajax/libs/vue/' + ver.vue.replace(/\~|\^/g, '') + '/vue.runtime.global.prod.min.js',
16 | 'https://cdn.bootcdn.net/ajax/libs/vue-router/' + ver['vue-router'].replace(/\~|\^/g, '') + '/vue-router.global.prod.min.js',
17 | 'https://cdn.bootcdn.net/ajax/libs/axios/' + ver.axios.replace(/\~|\^/g, '') + '/axios.min.js',
18 | 'https://cdn.bootcdn.net/ajax/libs/vue-demi/' + ver['vue-demi'].replace(/\~|\^/g, '') + '/index.iife.min.js',
19 | 'https://cdn.bootcdn.net/ajax/libs/pinia/' + ver.pinia.replace(/\~|\^/g, '') + '/pinia.iife.prod.min.js',
20 | 'https://cdn.bootcdn.net/ajax/libs/element-plus/' + ver['element-plus'].replace(/\~|\^/g, '') + '/index.full.min.js',
21 | 'https://cdn.bootcss.com/blueimp-md5/2.10.0/js/md5.min.js',
22 | 'https://unpkg.com/@element-plus/icons-vue',
23 | 'https://cdn.jsdelivr.net/npm/@element-plus/icons-vue@2.0.6/dist/index.iife.min.js',
24 | ],
25 | }
26 |
27 | //DEV环境的CDN连接地址 dev cdn link
28 | exports.devCDN = {
29 | css: [
30 | '/assets/css/element-plus.min.css',
31 | '/assets/css/github-markdown.min.css',
32 | ],
33 | js: [
34 | ],
35 | }
36 |
37 | //cdn方式引入文件,以下文件不打包,使用外部CDN连接
38 | exports.PROD_EXTERNALS = {
39 | vue:'Vue',
40 | 'vue-router': 'VueRouter',
41 | 'vue-demi': 'VueDemi',
42 | axios:'axios',
43 | pinia:'Pinia',
44 | 'element-plus':'ElementPlus',
45 | '@element-plus/icons-vue':'ElementPlusIconsVue',
46 | 'js-md5':'md5',
47 | }
48 |
49 | exports.DEV_EXTERNALS = {}
50 |
--------------------------------------------------------------------------------
/src/utils/modules/cache.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 自定义Cache公共函数,主要操作localStorage和sessionStorage
3 | * @author: Jihua.Huang
4 | * @date: 2022-3-1
5 | */
6 | const cache = {
7 | // ====================localStorage======================
8 | /**
9 | * @name: 设置localStorage值
10 | * @date: 2022-3-1
11 | * @param: key string cache-key名称
12 | * @param: value string cache值
13 | */
14 | setLocalStorage(key: string, value: string) {
15 | window.localStorage.setItem(key, value)
16 | },
17 |
18 | /**
19 | * @name: 获取localStorage值
20 | * @date: 2022-3-1
21 | * @param: key string cache-key名称
22 | */
23 | getLocalStorage(key: string) {
24 | const value = window.localStorage.getItem(key)
25 | return value || ''
26 | },
27 |
28 | /**
29 | * @name: 删除localStorage值
30 | * @date: 2022-3-1
31 | * @param: key string cache-key名称
32 | */
33 | delLocalStorage(key: string) {
34 | window.localStorage.removeItem(key)
35 | },
36 |
37 | /**
38 | * @name: 清除localStorage所有的值
39 | * @date: 2022-3-1
40 | * @param: null
41 | */
42 | clearLocalStorage() {
43 | window.localStorage.clear()
44 | },
45 |
46 |
47 | // ====================sessionStorage======================
48 | /**
49 | * @name: 设置sessionStorage值
50 | * @date: 2022-3-1
51 | * @param: key string cache名称
52 | * @param: value string cache-key名称
53 | */
54 | setSessionStorage(key: string, value: string) {
55 | window.sessionStorage.setItem(key, value)
56 | },
57 |
58 | /**
59 | * @name: 获取sessionStorage值
60 | * @date: 2022-3-1
61 | * @param: key string cache-key名称
62 | */
63 | getSessionStorage(key: string) {
64 | const value = window.sessionStorage.getItem(key)
65 | return value || ''
66 | },
67 |
68 | /**
69 | * @name: 删除sessionStorage值
70 | * @date: 2022-3-1
71 | * @param: key string cache-key名称
72 | */
73 | delSessionStorage(key: string) {
74 | window.sessionStorage.removeItem(key)
75 | },
76 |
77 | /**
78 | * @name: 清除sessionStorage所有的值
79 | * @date: 2022-3-1
80 | * @param: null
81 | */
82 | clearSessionStorage() {
83 | window.sessionStorage.clear()
84 | }
85 | }
86 | export default cache
87 |
--------------------------------------------------------------------------------
/src/views/layout/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
48 |
49 |
102 |
--------------------------------------------------------------------------------
/src/store/modules/setting.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 定义基于pinia的store存储
3 | * 设置相关的store数据(token、菜单、标签等相关)
4 | * @author jihua.huang
5 | * @since 2022-03-15
6 | */
7 | import { defineStore } from 'pinia'
8 |
9 | // 创建store,defineStore调用后返回函数,调用该函数获得Store实体
10 | const settingStore = defineStore({
11 | // 必传的参数,id值,在store中唯一
12 | id: 'settingStore',
13 | // 定义数据,返回对象和属性
14 | state: () => ({
15 | token: '', // 请求token
16 | userInfo: '', // 用户基本信息
17 | prefer: {}, // 设置偏好,包括:主题皮肤等
18 | collapse: false, // 左边菜单折叠
19 | drawer: false, // 右边抽屉工具页面
20 | dropDown: false, // 用户名的下拉菜单折叠
21 | defaultActive: '', // 默认激活的菜单path -key
22 | }),
23 | // 获取store模块的属性
24 | getters: {
25 | getToken: (state) => state.token,
26 | getUserInfo: (state) => state.userInfo,
27 | getPrefer: (state) => state.prefer,
28 | getCollapse: (state) => state.collapse,
29 | getDrawer: (state) => state.drawer,
30 | getDropDown: (state) => state.dropDown,
31 | getDefaultActive: (state) => state.defaultActive,
32 | },
33 | // 设置store模块的属性
34 | actions: {
35 | // 保存token
36 | setToken(token: string) {
37 | this.token = token
38 | },
39 | // 保存用户基本信息
40 | setUserInfo(userInfo: any) {
41 | this.userInfo = userInfo
42 | },
43 | // 设置偏好,包括:主题皮肤等
44 | setPrefer(prefer: any) {
45 | this.prefer = prefer
46 | },
47 | // 保存左边menu折叠状态
48 | setCollapse(collapse: boolean) {
49 | this.collapse = collapse
50 | },
51 | // 设置右边抽屉工具页面打开关闭状态
52 | setDrawer(drawer: boolean) {
53 | this.drawer = drawer
54 | },
55 | // 保存用户名的下拉menu折叠状态
56 | setDropDown(dropDown: boolean) {
57 | this.dropDown = dropDown
58 | },
59 | // 设置默认激活的菜单path -key
60 | setDefaultActive(defaultActive: string) {
61 | this.defaultActive = defaultActive
62 | },
63 | },
64 |
65 | // 开启数据缓存 -- 需要在store/index.js中import piniaPluginPersist 插件
66 | persist: {
67 | enabled: true, // 开启持久化
68 | strategies: [
69 | {
70 | // key: 'token', //自定义Key,也可以去掉,使用默认值为参数id的值
71 | storage: localStorage, // 可以为localStorage或者sessionStorage
72 | // 可以通过paths指定需要持久化的值,其他没有指定的则不会持久化
73 | paths: [
74 | 'token', 'collapse', 'userInfo', 'dropDown','defaultActive', 'drawer', 'prefer',
75 | ]
76 | }
77 | ]
78 | }
79 | })
80 |
81 | export default settingStore
82 |
--------------------------------------------------------------------------------
/src/views/layout/components/aside/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
24 |
25 |
26 |
68 |
86 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | // 引入配置文件config.js
2 | const conf = require('./src/config/config.ts')
3 |
4 | const { defineConfig } = require('@vue/cli-service')
5 | const webpack = require('webpack')
6 | module.exports = defineConfig({
7 | productionSourceMap: false, //不生成map文件
8 | transpileDependencies: true,
9 | lintOnSave: false,
10 | parallel: false,
11 | chainWebpack: config => {
12 | // Markdown文件
13 | config.module.rule('md')
14 | .test(/\.md/)
15 | .use('vue-loader')
16 | .loader('vue-loader')
17 | .end()
18 | .use('vue-markdown-loader')
19 | .loader('vue-markdown-loader/lib/markdown-compiler')
20 | .options({
21 | raw: true
22 | })
23 | // 导入cdn静态文件连接 来自config.ts
24 | config.plugin('html').tap(args => {
25 | args[0].cdn = conf.STATIC_CDN
26 | return args
27 | })
28 | if (conf.PRODUCTION) {
29 | // 删除预加载优化
30 | config.plugins.delete('preload')
31 | config.plugins.delete('prefetch')
32 | // 压缩优化
33 | config.optimization.minimize(true)
34 | // 分割优化
35 | config.optimization.splitChunks({
36 | chunks: 'all'
37 | })
38 | // 清除生成环境的console.log输出
39 | config.optimization
40 | .minimizer('terser')
41 | .tap(args => {
42 | Object.assign(args[0].terserOptions.compress, {
43 | pure_funcs: ['console.log']
44 | })
45 | return args
46 | })
47 | }
48 | },
49 | configureWebpack: {
50 | // cdn的方式引入js文件等
51 | externals: conf.EXTERNALS,
52 | optimization: {
53 | splitChunks: {
54 | cacheGroups: {
55 | // node_modules目录下的库剥离
56 | vendor: {
57 | chunks: 'all',
58 | test: /node_modules/,
59 | name: 'vendor',
60 | minChunks: 1,
61 | maxInitialRequests: 5,
62 | minSize: 0,
63 | priority: 100
64 | },
65 | // 公用|自定义模块剥离
66 | common: {
67 | chunks: 'all',
68 | test: /[\\/]src[\\/](utils|config|service|router|store|directive)[\\/]/,
69 | name: 'common',
70 | minChunks: 1,
71 | maxInitialRequests: 5,
72 | minSize: 0,
73 | priority: 60
74 | },
75 | runtimeChunk: {
76 | name: 'manifest'
77 | }
78 | }
79 | }
80 | }
81 | },
82 | devServer: {
83 | host: conf.DEV_HOST, // dev环境主机地址
84 | port: conf.DEV_PORT, // dev环境默认端口
85 | proxy: {
86 | [conf.PROXY_ROOT]: {
87 | target: conf.BASE_URL, // 设置地址代替axios的BASE_URL
88 | ws: true, // 代理 websocket
89 | changeOrigin: true, // 跨域
90 | secure: true, // https接口
91 | // 路径重写
92 | pathRewrite: {
93 | ['^${conf.PROXY_ROOT}']: '/'
94 | }
95 | }
96 | }
97 | }
98 | })
99 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-admin-chart",
3 | "version": "1.0.0",
4 | "author": "程序猿视觉[CoderVision] ",
5 | "homepage": "https://base.todoadmin.com",
6 | "description": "Simple fast beautiful vue admin template,vue3 admin,vue-admin,vue-admin-chart,vue后台管理,vue3管理后台,todoadmin chart,vue element-plus,element admin,vue echart,vue element admin,https://base.todoadmin.com",
7 | "license": "MIT",
8 | "private": false,
9 | "scripts": {
10 | "serve": "vue-cli-service serve",
11 | "build": "vue-cli-service build",
12 | "lint": "vue-cli-service lint",
13 | "report": "vue-cli-service build --report --mode production"
14 | },
15 | "dependencies": {
16 | "@element-plus/icons-vue": "^2.0.4",
17 | "axios": "^0.27.2",
18 | "core-js": "^3.23.1",
19 | "element-plus": "^2.2.5",
20 | "github-markdown-css": "^5.1.0",
21 | "highlight.js": "^11.5.1",
22 | "js-md5": "^0.7.3",
23 | "pinia": "^2.0.14",
24 | "pinia-plugin-persist": "^1.0.0",
25 | "vue": "^3.2.37",
26 | "vue-demi": "^0.13.1",
27 | "vue-router": "^4.0.16"
28 | },
29 | "devDependencies": {
30 | "@typescript-eslint/eslint-plugin": "^5.28.0",
31 | "@typescript-eslint/parser": "^5.28.0",
32 | "@vue/cli-plugin-babel": "^5.0.5",
33 | "@vue/cli-plugin-eslint": "^5.0.5",
34 | "@vue/cli-plugin-router": "^5.0.5",
35 | "@vue/cli-plugin-typescript": "^5.0.5",
36 | "@vue/cli-service": "^5.0.5",
37 | "@vue/eslint-config-standard": "^7.0.0",
38 | "@vue/eslint-config-typescript": "^11.0.0",
39 | "babel-eslint": "^10.1.0",
40 | "eslint": "^8.17.0",
41 | "eslint-plugin-import": "^2.26.0",
42 | "eslint-plugin-node": "^11.1.0",
43 | "eslint-plugin-promise": "^6.0.0",
44 | "eslint-plugin-vue": "^9.1.1",
45 | "mockjs": "^1.1.0",
46 | "sass": "^1.52.3",
47 | "sass-loader": "^13.0.0",
48 | "terser-webpack-plugin": "^5.3.3",
49 | "ts-loader": "^9.3.0",
50 | "typescript": "^4.7.3",
51 | "vue-loader": "^17.0.0",
52 | "vue-markdown-loader": "^2.5.0",
53 | "vue-template-compiler": "^2.6.14"
54 | },
55 | "repository": {
56 | "type": "git",
57 | "url": "git+https://github.com/todoadmin/vue-admin-chart.git"
58 | },
59 | "keywords": [
60 | "todoadmin",
61 | "vue",
62 | "admin",
63 | "chart-admin",
64 | "dashboard",
65 | "element-ui",
66 | "vue-admin",
67 | "element-admin",
68 | "admin-template",
69 | "admin-management",
70 | "management-system"
71 | ],
72 | "bugs": {
73 | "url": "https://github.com/todoadmin/vue-admin-chart/issues"
74 | },
75 | "engines": {
76 | "node": ">=8.9",
77 | "npm": ">= 3.0.0"
78 | },
79 | "eslintConfig": {
80 | "root": true,
81 | "env": {
82 | "node": true
83 | },
84 | "extends": [
85 | "plugin:vue/vue3-essential",
86 | "@vue/standard",
87 | "@vue/typescript/recommended"
88 | ],
89 | "parserOptions": {
90 | "ecmaVersion": 2020
91 | },
92 | "rules": {}
93 | },
94 | "browserslist": [
95 | "> 1%",
96 | "last 2 versions",
97 | "not dead",
98 | "not ie 11"
99 | ]
100 | }
101 |
--------------------------------------------------------------------------------
/src/views/layout/components/setting/drawer.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 |
78 |
79 |
93 |
--------------------------------------------------------------------------------
/src/views/layout/components/header/profile.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{data.userInfo.username}}
8 |
9 |
10 |
11 |
12 |
13 | 个人中心
14 | Github仓库
15 | Gitee码云仓库
16 | 登出
17 |
18 |
19 |
20 |
21 |
22 |
23 |
96 |
97 |
141 |
--------------------------------------------------------------------------------
/src/utils/modules/comm.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 共用函数
3 | * @author jihua.huang
4 | * @since 2022-03-24
5 | */
6 |
7 |
8 | /**
9 | * 转换为字符串(false null function undefined NaN 0 空对象 空数组 统一转为空字符串)
10 | * @param value any
11 | * @return String 转换后的字符串
12 | */
13 | export const toStr = (value:any) => {
14 | let str:string = ''
15 | if (typeof value === 'undefined') {
16 | str = ''
17 | } else if (!value || value === null || typeof value === 'function' || value.isNaN || JSON.stringify(value) === '{}') {
18 | str = ''
19 | } else {
20 | str = value.toString()
21 | }
22 | return str
23 | }
24 |
25 | /**
26 | * 转换开关值(true null function undefined NaN 空对象 空数组 统一转为开)
27 | * @param value any
28 | * @return boolen 转换后的trun/false
29 | */
30 | export const hasOnOff = (value:any) => {
31 | let ret:boolean = false
32 | if (typeof value === 'undefined') {
33 | ret = true
34 | } else {
35 | if (typeof value === 'string') {
36 | ret = !!parseInt(value)
37 | } else if (typeof value === 'number') {
38 | ret = !!value
39 | } else {
40 | ret = true
41 | }
42 | }
43 | return ret
44 | }
45 |
46 | /**
47 | * 拼接成字符串
48 | * @param str string
49 | * @param str... string
50 | * @return string str
51 | */
52 | export const concatStr = (str:string,str1:string) => {
53 | return str + str1
54 | }
55 |
56 | /**
57 | * 格式化unix时间戳为年月日格式(2022-03-18 10:08:00)
58 | * @param time number
59 | * @param format string 格式 默认:yyyy-MM-dd h:m:s
60 | * @return string str
61 | */
62 | export const formatDate = (time:number = 0,format:string = '') => {
63 | let date:any
64 | if (time > 0) {
65 | let timeStr = time.toString();
66 | if (timeStr.length > 10) {
67 | date = new Date(time);
68 | } else {
69 | // 如果是毫秒则不需要*1000,如果是秒,则需要*1000
70 | date = new Date(time * 1000);
71 | }
72 | } else {
73 | date = new Date();
74 | }
75 |
76 | if (!format) return date.toLocaleString();
77 | let dateMap:any = {
78 | y: date.getFullYear(),
79 | M: date.getMonth() + 1,
80 | d: date.getDate(),
81 | h: date.getHours(),
82 | m: date.getMinutes(),
83 | s: date.getSeconds(),
84 | S: date.getMilliseconds()
85 | };
86 | return format.replace(/(y+)|(M+)|(d+)|(h+)|(m+)|(s+)|(S+)/g, (a) => _add0(dateMap[a[0]], a.length))
87 |
88 | }
89 |
90 | function _add0(time:any, len:number) {
91 | let timeStr = time.toString();
92 | let l = timeStr.length;
93 | return l < len ? '0' . repeat(len - l) + time : time;
94 | }
95 |
96 | /**
97 | * 判断字符串是否在item中
98 | * @param item object/string item项
99 | * @param need string 字符串
100 | * @return number 1:弱,2:中,3:强
101 | */
102 | export const isIndexOf = (item:any,need:any) => {
103 | if (typeof item === 'undefined' || item === null || typeof need === 'undefined' || typeof need === 'undefined') return false
104 | if (Object.keys(item).length >= 1 && need) {
105 | if (item.indexOf(need) !== -1) {
106 | return true;
107 | }
108 | }
109 | return false
110 | }
111 |
112 | /**
113 | * 字符串的IP地址转为整型的IP(127.0.0.1 -> 2130706433 )
114 | * @param ipAddress string 字符串的IP地址
115 | * @return number 整型IP地址
116 | */
117 | export const ip2long = ( ipAddress:string ) => {
118 | var output:any;
119 | if ( ipAddress.match ( /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ ) ) {
120 | var parts:any = ipAddress.split ( '.' );
121 | var output:any;
122 | output = ( parts [ 0 ] * Math.pow ( 256, 3 ) ) +
123 | ( parts [ 1 ] * Math.pow ( 256, 2 ) ) +
124 | ( parts [ 2 ] * Math.pow ( 256, 1 ) ) +
125 | ( parts [ 3 ] * Math.pow ( 256, 0 ) );
126 | }
127 | return output<<0;
128 | }
129 |
130 | /**
131 | * 整型的IP转为字符串的IP地址(2130706433 -> 127.0.0.1)
132 | * @param longAddress number 整型IP地址
133 | * @return string 字符串的IP地址
134 | */
135 | export const long2ip = ( longAddress:number ) => {
136 | longAddress = longAddress>>>0;
137 | var output;
138 |
139 | if ( !isNaN ( longAddress ) && ( longAddress >= 0 || longAddress <= 4294967295 ) ) {
140 | output = Math.floor (longAddress / Math.pow ( 256, 3 ) ) + '.' +
141 | Math.floor ( ( longAddress % Math.pow ( 256, 3 ) ) / Math.pow ( 256, 2 ) ) + '.' +
142 | Math.floor ( ( ( longAddress % Math.pow ( 256, 3 ) ) % Math.pow ( 256, 2 ) ) /
143 | Math.pow ( 256, 1 ) ) + '.' +
144 | Math.floor ( ( ( ( longAddress % Math.pow ( 256, 3 ) ) % Math.pow ( 256, 2 ) ) %
145 | Math.pow ( 256, 1 ) ) / Math.pow ( 256, 0 ) );
146 | }
147 | return output;
148 | }
149 |
--------------------------------------------------------------------------------
/src/utils/modules/setting.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 设置相关功能
3 | * @author jihua.huang
4 | * @since 2022-03-14
5 | */
6 | import { G } from '@/config'
7 | import { storeToRefs } from 'pinia'
8 | import { settingStore } from '@/store' // 引入setting permission的store
9 |
10 | /**
11 | * 初始化相关pinia store对象
12 | * @return {*}
13 | */
14 | const initStore = () => {
15 | const settStore = settingStore()
16 |
17 | // 设置为响应数据
18 | const refSettStore = storeToRefs(settingStore())
19 | return { settStore, refSettStore }
20 | }
21 |
22 | /**
23 | * 设置左边菜单收起/展开
24 | * @returns bool
25 | */
26 | export function setCollapse() {
27 | let collapse = initStore().settStore.collapse || false
28 | initStore().settStore.setCollapse(!collapse)
29 | }
30 |
31 | /**
32 | * 获取左边菜单的收起/展开 状态
33 | * @returns bool
34 | */
35 | export function getCollapse() {
36 | const { collapse } = initStore().refSettStore
37 | return collapse
38 | }
39 |
40 | /**
41 | * 设置右边抽屉工具页面打开/关闭 状态
42 | * @returns bool
43 | */
44 | export function setDrawer() {
45 | let drawer = initStore().settStore.drawer || false
46 | initStore().settStore.setDrawer(!drawer)
47 | }
48 |
49 | /**
50 | * 获取设置右边抽屉工具页面打开/关闭 状态
51 | * @returns bool
52 | */
53 | export function getDrawer() {
54 | const { drawer } = initStore().refSettStore
55 | return drawer
56 | }
57 |
58 | /**
59 | * 设置用户名的下拉菜单收起/展开
60 | * @returns bool
61 | */
62 | export function setDropDown() {
63 | let dropDown = initStore().settStore.dropDown || false
64 | initStore().settStore.setDropDown(!dropDown)
65 | }
66 |
67 | /**
68 | * 获取用户名的下拉菜单收起/展开 状态
69 | * @returns bool
70 | */
71 | export function getDropDown() {
72 | const { dropDown } = initStore().refSettStore
73 | return dropDown
74 | }
75 |
76 | /**
77 | * 获取用户的基本信息
78 | * @returns object
79 | */
80 | export function getUserInfo() {
81 | const { userInfo } = initStore().refSettStore
82 | const info : any = userInfo
83 | return info.value
84 | }
85 |
86 | /**
87 | * 设置默认激活的菜单path -key
88 | * @returns number
89 | */
90 | export function setDefaultActive(path: string) {
91 | if (path) {
92 | initStore().settStore.setDefaultActive(path)
93 | }
94 | return true
95 | }
96 |
97 | /**
98 | * 获取默认激活的菜单path -key
99 | * @returns number
100 | */
101 | export function getDefaultActive() {
102 | const { defaultActive } = initStore().refSettStore
103 | return defaultActive
104 | }
105 |
106 | /**
107 | * 获取路由数据转换成面包屑数据
108 | * @returns number
109 | */
110 | export const getBreadcrumb = (route: any) => {
111 | let list:any = []
112 | const matched:any = route.matched || []
113 | const home = ['/', '/home']
114 | const homeObj = {
115 | path: '/home',
116 | name: 'Home',
117 | title: '首页',
118 | link: true
119 | }
120 | // 获取数组长度
121 | const length = Object.keys(matched).length
122 | if (length >= 1) {
123 | Object.values(matched).forEach((item:any) => {
124 | if (item.path && item.path !== '/') {
125 | let breadcrumb:any = {
126 | path: item.path,
127 | name: item.name,
128 | title: item.meta.title
129 | }
130 | list.push(breadcrumb)
131 | }
132 | })
133 | }
134 | return list
135 | }
136 |
137 | /**
138 | * 设置偏好设置信息
139 | * @returns number
140 | */
141 | export function setPrefer(data: any) {
142 | // 如果数据值为空,则不处理
143 | if (Object.keys(data).length < 1) {
144 | return
145 | }
146 |
147 | // 获取store里的prefer数据
148 | const prefer = initStore().refSettStore.prefer
149 | let newData:any = {}
150 | // 存在数据的处理
151 | if (Object.keys(prefer.value).length >= 1) {
152 | // 合并对象
153 | newData = Object.assign(prefer.value, data)
154 | } else {
155 | newData = data
156 | }
157 | if (newData) {
158 | // 保存数据到store中
159 | initStore().settStore.setPrefer(newData)
160 | }
161 | return true
162 | }
163 |
164 | /**
165 | * 获取偏好设置信息
166 | * @returns number
167 | */
168 | export const getPrefer = () => {
169 | const { prefer } = initStore().refSettStore
170 | // 如果不存在主题皮肤,则使用默认皮肤
171 | return prefer
172 | }
173 |
174 | /**
175 | * 获取偏好设置信息
176 | * @returns number
177 | */
178 | export const getTheme = (val:any) => {
179 | if (typeof val === 'undefined' || !val) {
180 | // 如果不存在主题皮肤,则使用默认皮肤
181 | return G.THEME_DEFAULT
182 | } else {
183 | return val
184 | }
185 | }
186 | /**
187 | * 获取某个偏好设置的开关信息信息
188 | * @returns number
189 | */
190 | export const getOnOff = (val:any) => {
191 | if (typeof val === 'undefined') {
192 | // 如果不存在key,则使用默认 1
193 | return 1
194 | } else {
195 | return parseInt(val) === 0 ? 0 : 1
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/mock/modules/bannerIndex.json:
--------------------------------------------------------------------------------
1 | {
2 | "code": 0,
3 | "message": "操作成功!",
4 | "data": {
5 | "list": [
6 | {
7 | "id": 7,
8 | "uid": 1,
9 | "uqid": 1810,
10 | "sort": 0,
11 | "create_time": 1653929648,
12 | "status": 2,
13 | "start_time": 1661961600,
14 | "end_time": 1664467200,
15 | "ext": "jpeg",
16 | "filename": "8",
17 | "url": "",
18 | "title": "9月清仓大甩卖11",
19 | "content": "9月清仓大甩卖",
20 | "banner_url": "/images/ad35dddcf60f2f00dba3b2fa8883bfcb.jpeg",
21 | "thumb_url": "/images/ad35dddcf60f2f00dba3b2fa8883bfcb.jpeg"
22 | },
23 | {
24 | "id": 6,
25 | "uid": 1,
26 | "uqid": 1231,
27 | "sort": 0,
28 | "create_time": 1652410084,
29 | "status": 1,
30 | "start_time": 1659283200,
31 | "end_time": 1661875200,
32 | "ext": "jpg",
33 | "filename": "沙漠",
34 | "url": "",
35 | "title": "8月不会停12",
36 | "content": "8月不会停",
37 | "banner_url": "/images/eed68c68672f38f2933951d6910069c8.jpg",
38 | "thumb_url": "/images/eed68c68672f38f2933951d6910069c8.jpg"
39 | },
40 | {
41 | "id": 5,
42 | "uid": 1,
43 | "uqid": 1229,
44 | "sort": 0,
45 | "create_time": 1652410042,
46 | "status": 1,
47 | "start_time": 1656604800,
48 | "end_time": 1659196800,
49 | "ext": "jpg",
50 | "filename": "hp",
51 | "url": "",
52 | "title": "7月等你来13",
53 | "content": "7月等你来",
54 | "banner_url": "/images/21ac2b09aa79bd2244d244fff4d76447.jpg",
55 | "thumb_url": "/images/21ac2b09aa79bd2244d244fff4d76447.jpg"
56 | },
57 | {
58 | "id": 4,
59 | "uid": 1,
60 | "uqid": 1227,
61 | "sort": 0,
62 | "create_time": 1652409997,
63 | "status": 1,
64 | "start_time": 1654012800,
65 | "end_time": 1656518400,
66 | "ext": "jpeg",
67 | "filename": "天空下的温暖",
68 | "url": "",
69 | "title": "6月疯狂打折14",
70 | "content": "6月疯狂打折",
71 | "banner_url": "/images/4e558470e518f2d2950149a807ac0fef.jpeg",
72 | "thumb_url": "/images/4e558470e518f2d2950149a807ac0fef.jpeg"
73 | },
74 | {
75 | "id": 3,
76 | "uid": 1,
77 | "uqid": 1224,
78 | "sort": 0,
79 | "create_time": 1653840063,
80 | "status": 1,
81 | "start_time": 1651334400,
82 | "end_time": 1653926400,
83 | "ext": "jpeg",
84 | "filename": "3",
85 | "url": "",
86 | "title": "5月玩到底15",
87 | "content": "5月玩到底",
88 | "banner_url": "/images/f8c1fb49d1da365a80ee8d430e1e22a6.jpeg",
89 | "thumb_url": "/images/f8c1fb49d1da365a80ee8d430e1e22a6.jpeg"
90 | },
91 | {
92 | "id": 2,
93 | "uid": 1,
94 | "uqid": 1221,
95 | "sort": 0,
96 | "create_time": 1653840001,
97 | "status": 1,
98 | "start_time": 1652803200,
99 | "end_time": 1656432000,
100 | "ext": "jpeg",
101 | "filename": "1",
102 | "url": "",
103 | "title": "年中大促销16",
104 | "content": "年中大促销",
105 | "banner_url": "/images/b2553ba0e33d8203503477b46a0029ff.jpeg",
106 | "thumb_url": "/images/b2553ba0e33d8203503477b46a0029ff.jpeg"
107 | },
108 | {
109 | "id": 1,
110 | "uid": 1,
111 | "uqid": 1219,
112 | "sort": 0,
113 | "create_time": 1653840032,
114 | "status": 1,
115 | "start_time": 1652457600,
116 | "end_time": 1655568000,
117 | "ext": "jpeg",
118 | "filename": "13",
119 | "url": "",
120 | "title": "618大优惠17",
121 | "content": "618大优惠",
122 | "banner_url": "/images/e29d994ec3d5d2424ce5448d816d9e20.jpeg",
123 | "thumb_url": "/images/e29d994ec3d5d2424ce5448d816d9e20.jpeg"
124 | }
125 | ],
126 | "info": {
127 | "uid": 1,
128 | "username": "coderVision"
129 | },
130 | "total": 7,
131 | "size": 7,
132 | "page": 1
133 | }
134 | }
--------------------------------------------------------------------------------
/src/views/form/image.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
30 | Click to upload
31 |
32 |
33 | jpg/png files with a size less than 500kb
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
46 |
47 |
48 |
49 |
128 |
129 |
159 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true
5 | },
6 | extends: [
7 | 'plugin:vue/vue3-essential',
8 | '@vue/standard',
9 | '@vue/typescript/recommended'
10 | ],
11 | parserOptions: {
12 | parser: 'babel-eslint',
13 | ecmaVersion: 2020
14 | },
15 | rules: {
16 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
17 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
18 | 'space-before-function-paren': 0,
19 | 'vue/singleline-html-element-content-newline': 'off',
20 | 'vue/multiline-html-element-content-newline': 'off',
21 | 'vue/name-property-casing': ['error', 'PascalCase'],
22 | 'vue/no-v-html': 'off',
23 | 'vue/html-self-closing': ['error', {
24 | html: {
25 | void: 'never',
26 | normal: 'always',
27 | component: 'always'
28 | },
29 | svg: 'always',
30 | math: 'always'
31 | }],
32 | 'accessor-pairs': 2,
33 | 'arrow-spacing': [2, {
34 | before: true,
35 | after: true
36 | }],
37 | 'block-spacing': [2, 'always'],
38 | 'brace-style': [2, '1tbs', {
39 | allowSingleLine: true
40 | }],
41 | 'comma-dangle': [2, 'never'],
42 | 'comma-spacing': [2, {
43 | before: false,
44 | after: true
45 | }],
46 | 'comma-style': [2, 'last'],
47 | 'constructor-super': 2,
48 | curly: [2, 'multi-line'],
49 | 'dot-location': [2, 'property'],
50 | 'eol-last': 2,
51 | 'handle-callback-err': [2, '^(err|error)$'],
52 | indent: [2, 2, {
53 | SwitchCase: 1
54 | }],
55 | 'jsx-quotes': [2, 'prefer-single'],
56 | 'key-spacing': [2, {
57 | beforeColon: false,
58 | afterColon: true
59 | }],
60 | 'keyword-spacing': [2, {
61 | before: true,
62 | after: true
63 | }],
64 | 'new-cap': [2, {
65 | newIsCap: true,
66 | capIsNew: false
67 | }],
68 | 'new-parens': 2,
69 | 'no-array-constructor': 2,
70 | 'no-caller': 2,
71 | 'no-class-assign': 2,
72 | 'no-cond-assign': 2,
73 | 'no-const-assign': 2,
74 | 'no-control-regex': 0,
75 | 'no-delete-var': 2,
76 | 'no-dupe-args': 2,
77 | 'no-dupe-class-members': 2,
78 | 'no-dupe-keys': 2,
79 | 'no-duplicate-case': 2,
80 | 'no-empty-character-class': 2,
81 | 'no-empty-pattern': 2,
82 | 'no-eval': 2,
83 | 'no-ex-assign': 2,
84 | 'no-extend-native': 2,
85 | 'no-extra-bind': 2,
86 | 'no-extra-boolean-cast': 2,
87 | 'no-extra-parens': [2, 'functions'],
88 | 'no-fallthrough': 2,
89 | 'no-floating-decimal': 2,
90 | 'no-func-assign': 2,
91 | 'no-implied-eval': 2,
92 | 'no-inner-declarations': [2, 'functions'],
93 | 'no-invalid-regexp': 2,
94 | 'no-irregular-whitespace': 2,
95 | 'no-iterator': 2,
96 | 'no-label-var': 2,
97 | 'no-labels': [2, {
98 | allowLoop: false,
99 | allowSwitch: false
100 | }],
101 | 'no-lone-blocks': 2,
102 | 'no-mixed-spaces-and-tabs': 2,
103 | 'no-multi-spaces': 2,
104 | 'no-multi-str': 2,
105 | 'no-multiple-empty-lines': [2, {
106 | max: 1
107 | }],
108 | 'no-native-reassign': 2,
109 | 'no-negated-in-lhs': 2,
110 | 'no-new-object': 2,
111 | 'no-new-require': 2,
112 | 'no-new-symbol': 2,
113 | 'no-new-wrappers': 2,
114 | 'no-obj-calls': 2,
115 | 'no-octal': 2,
116 | 'no-octal-escape': 2,
117 | 'no-path-concat': 2,
118 | 'no-proto': 2,
119 | 'no-redeclare': 2,
120 | 'no-regex-spaces': 2,
121 | 'no-return-assign': [2, 'except-parens'],
122 | 'no-self-assign': 2,
123 | 'no-self-compare': 2,
124 | 'no-sequences': 2,
125 | 'no-shadow-restricted-names': 2,
126 | 'no-spaced-func': 2,
127 | 'no-sparse-arrays': 2,
128 | 'no-this-before-super': 2,
129 | 'no-throw-literal': 2,
130 | 'no-trailing-spaces': 2,
131 | 'no-undef': 2,
132 | 'no-undef-init': 2,
133 | 'no-unexpected-multiline': 2,
134 | 'no-unmodified-loop-condition': 2,
135 | 'no-unneeded-ternary': [2, {
136 | defaultAssignment: false
137 | }],
138 | 'no-unreachable': 2,
139 | 'no-unsafe-finally': 2,
140 | 'no-unused-vars': [2, {
141 | vars: 'all',
142 | args: 'none'
143 | }],
144 | 'no-useless-call': 2,
145 | 'no-useless-computed-key': 2,
146 | 'no-useless-constructor': 2,
147 | 'no-useless-escape': 0,
148 | 'no-whitespace-before-property': 2,
149 | 'no-with': 2,
150 | 'one-var': [2, {
151 | initialized: 'never'
152 | }],
153 | 'padded-blocks': [2, 'never'],
154 | quotes: [2, 'single', {
155 | avoidEscape: true,
156 | allowTemplateLiterals: true
157 | }],
158 | semi: [2, 'never'],
159 | 'semi-spacing': [2, {
160 | before: false,
161 | after: true
162 | }],
163 | 'space-before-blocks': [2, 'always'],
164 | 'space-in-parens': [2, 'never'],
165 | 'space-infix-ops': 2,
166 | 'space-unary-ops': [2, {
167 | words: true
168 | }],
169 | 'spaced-comment': [2, 'always', {
170 | markers: ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
171 | }],
172 | 'template-curly-spacing': [2, 'never'],
173 | 'valid-typeof': 2,
174 | 'yield-star-spacing': [2, 'both'],
175 | yoda: [2, 'never'],
176 | 'prefer-const': 0,
177 | 'object-curly-spacing': [2, 'always', {
178 | objectsInObjects: false
179 | }],
180 | 'array-bracket-spacing': [2, 'never']
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/mock/modules/login.json:
--------------------------------------------------------------------------------
1 | {
2 | "code": 0,
3 | "message": "操作成功!",
4 | "token": "eyJhbGciOiJIUzI1NiIsInR5cGUiOiJKV1QifQ.eyJpc3MiOiJ7XCJ1aWRcIjoxLFwidXNlcm5hbWVcIjpcImd1ZXN0XCJ9Iiwic3ViIjoiYXBpLnRvZG9hZG1pbi5jbiIsImF1ZCI6ImFwaS50b2RvYWRtaW4uY24iLCJpYXQiOjE2NTUyNjg3NjQsImV4cCI6MTY1NTI4MzE2NCwibmJmIjoxNjU1MjY4NzY0LCJqdGkiOiJmZmJmYjYwYTQ2OTRiYzcyNzBmNTQ3OGIwOGNlY2I1ZiJ9.Xvpz4EPMXS6hi9HfFGviqqyQ4c-SylBTF4QuRNyXpPI",
5 | "data": {
6 | "userInfo": {
7 | "uid": 1,
8 | "username": "guest",
9 | "truename": "李大龙",
10 | "status": 1,
11 | "level": 0,
12 | "avatar_url": "/images/avatar.jpeg"
13 | },
14 | "menu": [
15 | {
16 | "path": "/",
17 | "redirect": "/home",
18 | "name": "Home",
19 | "component": "Layout",
20 | "meta": {
21 | "title": "首页",
22 | "layout": true,
23 | "icon": "House",
24 | "requiresAuth": true,
25 | "hidden": false,
26 | "keepAlive": true,
27 | "new": false
28 | },
29 | "children": [
30 | {
31 | "path": "/home",
32 | "name": "Home",
33 | "component": "Dashboard",
34 | "meta": {
35 | "title": "首页",
36 | "icon": "House",
37 | "layout": false,
38 | "requiresAuth": true,
39 | "hidden": false,
40 | "keepAlive": true,
41 | "new": false
42 | }
43 | }
44 | ]
45 | },
46 | {
47 | "path": "/banner",
48 | "name": "Banner",
49 | "component": "Layout",
50 | "meta": {
51 | "title": "广告橱窗管理",
52 | "layout": false,
53 | "icon": "ScaleToOriginal",
54 | "requiresAuth": true,
55 | "hidden": false,
56 | "keepAlive": true,
57 | "new": false
58 | },
59 | "children": [
60 | {
61 | "path": "/banner/index",
62 | "name": "BannerIndex",
63 | "component": "@/views/banner/index/index.vue",
64 | "meta": {
65 | "title": "广告橱窗列表",
66 | "icon": "ScaleToOriginal",
67 | "layout": false,
68 | "requiresAuth": true,
69 | "hidden": false,
70 | "keepAlive": true,
71 | "new": false
72 | },
73 | "actions": [
74 | 1148,
75 | 1150,
76 | 1152,
77 | 1159,
78 | 1161
79 | ]
80 | }
81 | ]
82 | },
83 | {
84 | "path": "/admin",
85 | "name": "Admin",
86 | "component": "Layout",
87 | "meta": {
88 | "title": "管理员管理",
89 | "layout": false,
90 | "icon": "User",
91 | "requiresAuth": true,
92 | "hidden": false,
93 | "keepAlive": true,
94 | "new": false
95 | },
96 | "children": [
97 | {
98 | "path": "/admin/user",
99 | "name": "AdminUser",
100 | "component": "@/views/admin/user/index.vue",
101 | "meta": {
102 | "title": "管理员列表",
103 | "icon": "User",
104 | "layout": false,
105 | "requiresAuth": true,
106 | "hidden": false,
107 | "keepAlive": true,
108 | "new": false
109 | },
110 | "actions": [
111 | 175,
112 | 178,
113 | 181,
114 | 1823,
115 | 1825
116 | ]
117 | }
118 | ]
119 | },
120 | {
121 | "path": "/log",
122 | "name": "Log",
123 | "component": "Layout",
124 | "meta": {
125 | "title": "日志管理",
126 | "layout": false,
127 | "icon": "Document",
128 | "requiresAuth": true,
129 | "hidden": false,
130 | "keepAlive": true,
131 | "new": false
132 | },
133 | "children": [
134 | {
135 | "path": "/log/adminopr",
136 | "name": "LogAdminOpr",
137 | "component": "@/views/log/admin/operate.vue",
138 | "meta": {
139 | "title": "管理员操作日志",
140 | "icon": "Document",
141 | "layout": false,
142 | "requiresAuth": true,
143 | "hidden": false,
144 | "keepAlive": true,
145 | "new": false
146 | },
147 | "actions": [
148 | 146
149 | ]
150 | }
151 | ]
152 | }
153 | ]
154 | }
155 | }
--------------------------------------------------------------------------------
/src/views/log/admin/operate.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
12 |
13 |
14 | 查询
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | 删除日志
23 |
24 |
总共 {{ data.pagination.total }}
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | 用户ID: {{ scope.row.uid }}
35 |
36 |
37 | {{ scope.row.username }}
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | {{ comm.long2ip(scope.row.ip) }}
48 |
49 |
50 |
51 |
52 |
53 | {{ comm.formatDate(scope.row.create_time) }}
54 |
55 |
56 |
57 |
58 | 删除
59 |
60 |
61 |
62 |
63 |
64 |
65 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
182 |
249 |
--------------------------------------------------------------------------------
/mock/modules/logAdminopr.json:
--------------------------------------------------------------------------------
1 | {
2 | "code": 0,
3 | "message": "操作成功!",
4 | "data": {
5 | "list": [
6 | {
7 | "id": 1066,
8 | "uqid": 14108,
9 | "uid": 0,
10 | "func_code": 1161,
11 | "create_time": 1654941682,
12 | "link_id": 0,
13 | "username": "backend",
14 | "ip": "2886860801",
15 | "content": "广告橱窗列表-下架"
16 | },
17 | {
18 | "id": 1065,
19 | "uqid": 14100,
20 | "uid": 0,
21 | "func_code": 1161,
22 | "create_time": 1654941320,
23 | "link_id": 0,
24 | "username": "backend",
25 | "ip": "2886860801",
26 | "content": "广告橱窗列表-下架"
27 | },
28 | {
29 | "id": 1064,
30 | "uqid": 14089,
31 | "uid": 0,
32 | "func_code": 1159,
33 | "create_time": 1654940523,
34 | "link_id": 1810,
35 | "username": "backend",
36 | "ip": "2886860801",
37 | "content": "广告橱窗列表-上架[1810]"
38 | },
39 | {
40 | "id": 1063,
41 | "uqid": 13897,
42 | "uid": 0,
43 | "func_code": 8808,
44 | "create_time": 1654926287,
45 | "link_id": 8821,
46 | "username": "backend",
47 | "ip": "2886860801",
48 | "content": "会员角色管理-分配权限[店铺管理员]"
49 | },
50 | {
51 | "id": 1062,
52 | "uqid": 13894,
53 | "uid": 0,
54 | "func_code": 49,
55 | "create_time": 1654926225,
56 | "link_id": 13893,
57 | "username": "backend",
58 | "ip": "2886860801",
59 | "content": "菜单管理-新增[店铺中心]"
60 | },
61 | {
62 | "id": 1061,
63 | "uqid": 13887,
64 | "uid": 0,
65 | "func_code": 394,
66 | "create_time": 1654925945,
67 | "link_id": 584,
68 | "username": "backend",
69 | "ip": "2886860801",
70 | "content": "会员列表-编辑[2-coderVision]"
71 | },
72 | {
73 | "id": 1060,
74 | "uqid": 13885,
75 | "uid": 0,
76 | "func_code": 394,
77 | "create_time": 1654925898,
78 | "link_id": 3,
79 | "username": "backend",
80 | "ip": "2886860801",
81 | "content": "会员列表-编辑[1-guest]"
82 | },
83 | {
84 | "id": 1059,
85 | "uqid": 13883,
86 | "uid": 0,
87 | "func_code": 394,
88 | "create_time": 1654925865,
89 | "link_id": 3,
90 | "username": "backend",
91 | "ip": "2886860801",
92 | "content": "会员列表-编辑[1-guest]"
93 | },
94 | {
95 | "id": 1058,
96 | "uqid": 13845,
97 | "uid": 0,
98 | "func_code": 165,
99 | "create_time": 1654918320,
100 | "link_id": 13841,
101 | "username": "backend",
102 | "ip": "2886860801",
103 | "content": "全局ID管理-删除"
104 | },
105 | {
106 | "id": 1057,
107 | "uqid": 13281,
108 | "uid": 0,
109 | "func_code": 8808,
110 | "create_time": 1654876125,
111 | "link_id": 8821,
112 | "username": "backend",
113 | "ip": "2886860801",
114 | "content": "会员角色管理-分配权限[店铺管理员]"
115 | },
116 | {
117 | "id": 1056,
118 | "uqid": 13263,
119 | "uid": 0,
120 | "func_code": 49,
121 | "create_time": 1654873969,
122 | "link_id": 13262,
123 | "username": "backend",
124 | "ip": "2886860801",
125 | "content": "菜单管理-新增[物流订单列表]"
126 | },
127 | {
128 | "id": 1055,
129 | "uqid": 13258,
130 | "uid": 0,
131 | "func_code": 51,
132 | "create_time": 1654873860,
133 | "link_id": 1425,
134 | "username": "backend",
135 | "ip": "2886860801",
136 | "content": "菜单管理-编辑[物流管理]"
137 | },
138 | {
139 | "id": 1054,
140 | "uqid": 8842,
141 | "uid": 0,
142 | "func_code": 394,
143 | "create_time": 1654842977,
144 | "link_id": 3,
145 | "username": "backend",
146 | "ip": "2886860801",
147 | "content": "会员列表-编辑[1-guest]"
148 | },
149 | {
150 | "id": 1053,
151 | "uqid": 8841,
152 | "uid": 0,
153 | "func_code": 394,
154 | "create_time": 1654842294,
155 | "link_id": 584,
156 | "username": "backend",
157 | "ip": "2886860801",
158 | "content": "会员列表-编辑[2-guest]"
159 | },
160 | {
161 | "id": 1052,
162 | "uqid": 8840,
163 | "uid": 0,
164 | "func_code": 394,
165 | "create_time": 1654842287,
166 | "link_id": 584,
167 | "username": "backend",
168 | "ip": "2886860801",
169 | "content": "会员列表-编辑[2-guest]"
170 | },
171 | {
172 | "id": 1051,
173 | "uqid": 8839,
174 | "uid": 0,
175 | "func_code": 394,
176 | "create_time": 1654842125,
177 | "link_id": 584,
178 | "username": "backend",
179 | "ip": "2886860801",
180 | "content": "会员列表-编辑[2-guest]"
181 | },
182 | {
183 | "id": 1050,
184 | "uqid": 8838,
185 | "uid": 0,
186 | "func_code": 394,
187 | "create_time": 1654842117,
188 | "link_id": 3,
189 | "username": "backend",
190 | "ip": "2886860801",
191 | "content": "会员列表-编辑[1-guest]"
192 | },
193 | {
194 | "id": 1049,
195 | "uqid": 8837,
196 | "uid": 0,
197 | "func_code": 394,
198 | "create_time": 1654841911,
199 | "link_id": 584,
200 | "username": "backend",
201 | "ip": "2886860801",
202 | "content": "会员列表-编辑[1-guest]"
203 | },
204 | {
205 | "id": 1048,
206 | "uqid": 8836,
207 | "uid": 0,
208 | "func_code": 394,
209 | "create_time": 1654837903,
210 | "link_id": 3,
211 | "username": "backend",
212 | "ip": "2886860801",
213 | "content": "会员列表-编辑[1-guest]"
214 | },
215 | {
216 | "id": 1047,
217 | "uqid": 8835,
218 | "uid": 0,
219 | "func_code": 8808,
220 | "create_time": 1654837764,
221 | "link_id": 8832,
222 | "username": "backend",
223 | "ip": "2886860801",
224 | "content": "会员角色管理-分配权限[展示员-2]"
225 | }
226 | ],
227 | "total": 924,
228 | "size": 20,
229 | "page": 47
230 | }
231 | }
--------------------------------------------------------------------------------
/src/router/modules/routes.ts:
--------------------------------------------------------------------------------
1 | //========================对应的Route component Vue组件模板地址======================
2 | import { componentRouter } from './components';
3 | //========================对应的Route component Vue组件模板地址======================
4 |
5 | //静态路由列表
6 | export const routesStatic:any = [
7 | {
8 | path: '/',//路径地址
9 | redirect: '/home',//重定向地址
10 | component: componentRouter.Layout,//view组件
11 | meta: {
12 | title: '首页',//菜单标题名称
13 | icon: 'House',//菜单图标
14 | requiresAuth: true,//需认证才能显示该页面
15 | hidden: false,//该菜单是否在view的menu组件隐藏
16 | layout: true,//该菜单只作为一级菜单标题显示
17 | keepAlive:true,//该菜单对应的页面是否保存缓存,用于keep-alive组件设置
18 | new:false,//是否为新功能
19 | },
20 | children: [
21 | {
22 | path: 'home',
23 | name: 'Home',
24 | component: componentRouter.Home,
25 | meta: {
26 | title: '首页',
27 | icon: 'House',
28 | requiresAuth: true,
29 | hidden: false,
30 | keepAlive:true,
31 | new:false,//是否为新功能
32 | }
33 | }
34 | ]
35 | },
36 | {
37 | path: '/form',
38 | redirect: '/form/index',//重定向地址
39 | name: 'Form',
40 | component: componentRouter.Layout,
41 | meta: {
42 | title: '表单组件',
43 | icon: 'Paperclip',
44 | requiresAuth: true,
45 | layout: true,
46 | hidden: false,
47 | keepAlive:true,
48 | new:false,
49 | },
50 | children: [
51 | {
52 | path: '/form/index',
53 | name: 'FormIndex',
54 | component: () => import('@/views/form/index.vue'),
55 | meta: {
56 | title: '表单组件',
57 | icon: 'Paperclip',
58 | requiresAuth: true,
59 | hidden: false,
60 | keepAlive:true,
61 | new:true,
62 | },
63 | }
64 | ]
65 | },
66 | {
67 | path: '/image',
68 | redirect: '/image/index',//重定向地址
69 | name: 'Image',
70 | component: componentRouter.Layout,
71 | meta: {
72 | title: '图片组件',
73 | icon: 'Paperclip',
74 | requiresAuth: true,
75 | layout: true,
76 | hidden: false,
77 | keepAlive:true,
78 | new:false,
79 | },
80 | children: [
81 | {
82 | path: '/image/index',
83 | name: 'ImageIndex',
84 | component: () => import('@/views/form/image.vue'),
85 | meta: {
86 | title: '图片组件',
87 | icon: 'Paperclip',
88 | requiresAuth: true,
89 | hidden: false,
90 | keepAlive:true,
91 | new:true,
92 | },
93 | }
94 | ]
95 | },
96 | {
97 | path: '/other',
98 | redirect: '/other/index',//重定向地址
99 | name: 'Other',
100 | component: componentRouter.Layout,
101 | meta: {
102 | title: '其他组件',
103 | icon: 'Paperclip',
104 | requiresAuth: true,
105 | layout: true,
106 | hidden: false,
107 | keepAlive:true,
108 | new:false,
109 | },
110 | children: [
111 | {
112 | path: '/other/index',
113 | name: 'OtherIndex',
114 | component: () => import('@/views/form/other.vue'),
115 | meta: {
116 | title: '其他组件',
117 | icon: 'Paperclip',
118 | requiresAuth: true,
119 | hidden: false,
120 | keepAlive:true,
121 | new:true,
122 | },
123 | }
124 | ]
125 | },
126 | {
127 | path: '/banner',
128 | name: 'Banner',
129 | component: componentRouter.Layout,
130 | meta: {
131 | title: '广告橱窗',
132 | icon: 'ScaleToOriginal',
133 | requiresAuth: true,
134 | hidden: false,
135 | keepAlive:true,
136 | new:false,
137 | },
138 | children: [
139 | {
140 | path: '/banner/index',
141 | name: 'BannerIndex',
142 | component: componentRouter.BannerIndex,
143 | meta: {
144 | title: '广告橱窗列表',
145 | icon: 'ScaleToOriginal',
146 | requiresAuth: true,
147 | hidden: false,
148 | keepAlive:true,
149 | new:true,
150 | },
151 | }
152 | ]
153 | },
154 | {
155 | path: '/admin',
156 | name: 'Admin',
157 | component: componentRouter.Layout,
158 | meta: {
159 | title: '管理员管理',
160 | icon: 'User',
161 | requiresAuth: true,
162 | hidden: false,
163 | keepAlive:true,
164 | new:false,
165 | },
166 | children: [
167 | {
168 | path: '/admin/user',
169 | name: 'AdminUser',
170 | component: componentRouter.AdminUser,
171 | meta: {
172 | title: '管理员列表',
173 | icon: 'User',
174 | requiresAuth: true,
175 | hidden: false,
176 | keepAlive:true,
177 | new:false,
178 | },
179 | }
180 | ]
181 | },
182 | {
183 | path: '/log',
184 | name: 'Log',
185 | component: componentRouter.Layout,
186 | meta: {
187 | title: '日志管理',
188 | icon: 'Document',
189 | requiresAuth: true,
190 | hidden: false,
191 | keepAlive:true,
192 | new:false,
193 | },
194 | children: [
195 | {
196 | path: '/log/adminopr',
197 | name: 'LogAdminOpr',
198 | component: componentRouter.LogAdminOpr,
199 | meta: {
200 | title: '管理员操作日志',
201 | icon: 'Document',
202 | requiresAuth: true,
203 | hidden: false,
204 | keepAlive:true,
205 | new:false,
206 | }
207 | }
208 | ]
209 | },
210 | {
211 | path: '/others',
212 | name: 'Others',
213 | component: componentRouter.Layout,
214 | meta: {
215 | title: '其他页面',
216 | icon: 'InfoFilled',
217 | requiresAuth: true,
218 | hidden: false,
219 | keepAlive:true,
220 | new:false,
221 | },
222 | children: [
223 | {
224 | path: '/404',
225 | name: 'NotFound',
226 | component: componentRouter.NotFound,
227 | meta: {
228 | title: '404',
229 | icon: 'InfoFilled',
230 | requiresAuth: true,
231 | hidden: false,
232 | keepAlive:true,
233 | new:false,
234 | }
235 | },
236 | {
237 | path: '/README.md',
238 | name: 'README.cn',
239 | component: componentRouter.Home,
240 | meta: {
241 | title: 'README-中文',
242 | icon: 'InfoFilled',
243 | requiresAuth: true,
244 | hidden: false,
245 | keepAlive:true,
246 | new:false,
247 | }
248 | },
249 | {
250 | path: '/README.en.md',
251 | name: 'README.en',
252 | component: componentRouter.ReadMeEN,
253 | meta: {
254 | title: 'README-En',
255 | icon: 'InfoFilled',
256 | requiresAuth: true,
257 | hidden: false,
258 | keepAlive:true,
259 | new:false,
260 | }
261 | }
262 | ]
263 | }
264 | ]
265 |
266 | //静态白名单路由列表
267 | export const routesWhite = [
268 | {
269 | path: '/404',
270 | name: '404',
271 | component: componentRouter.NotFound,
272 | meta: {
273 | title: '404-NotFound',
274 | requiresAuth: false,
275 | hidden: true,
276 | layout: true,
277 | }
278 | },
279 | {
280 | path: '/login',
281 | name: 'Login',
282 | component: componentRouter.LoginLayout,
283 | meta: {
284 | title: '登录',
285 | layout: true,
286 | requiresAuth: false,
287 | hidden: true,
288 | }
289 | },
290 | {
291 | path: '/register',
292 | name: 'Register',
293 | component: componentRouter.LoginLayout,
294 | meta: {
295 | title: '注册',
296 | layout: true,
297 | requiresAuth: false,
298 | hidden: true,
299 | }
300 | }
301 | ]
302 |
303 | //获取动态路由列表
304 | export const routes = routesStatic.concat(routesWhite)
305 |
306 | //获取路由url path地址白名单列表 路由白名单 - 不重定向白名单 ['/404','/login', '/register']
307 | const whiteList = () => {
308 | let list:any = []
309 | for (let item of routes) {
310 | //也可以转换为大写或小写再保存
311 | list.push(item.path)
312 | }
313 | return list
314 | }
315 |
316 | //路由在白名单里面
317 | export const existWhite = (path: string) => {
318 | if (whiteList().indexOf(path) !== -1) {
319 | return true;
320 | } else return false;
321 | }
322 |
--------------------------------------------------------------------------------
/src/views/auth/login.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | TodoAdmin管理系统-base
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | 登录
33 |
34 |
35 |
38 |
39 |
40 |
44 |
45 |
46 |
47 | Copyright (c) {{data.table.year}}, Todoadmin.com
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
184 |
185 |
--------------------------------------------------------------------------------
/src/views/banner/index/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | 新增
15 | 删除
16 | 上架
17 | 下架
18 |
19 |
总共 {{ data.pagination.total }}
20 |
21 |
22 |
23 |
24 |
25 |
26 | 未发布
27 | 上架
28 | 下架
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | {{ scope.row.content }}
43 |
44 |
45 | {{ scope.row.title }}
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | 结束日期: {{ comm.formatDate(scope.row.end_time) }}
56 |
57 |
58 | {{ comm.formatDate(scope.row.start_time) }}
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | 编辑
67 | 下架
68 | 上架
69 | 删除
70 |
71 |
72 |
73 |
74 |
75 |
76 |
216 |
217 |
329 |
--------------------------------------------------------------------------------
/src/service/http/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 封装axios网络请求
3 | */
4 | import axios from "axios"
5 | import EventEmitter from 'events'
6 | import { G } from '@/config' //引入常量和配置信息
7 | import { ElLoading } from 'element-plus'
8 | // 导入模块
9 | import { cache } from '@/utils';
10 | import { responseCode } from './code';
11 |
12 | //定义一个异常信息接口,返回的数据
13 | interface IException {
14 | code : number,
15 | message: string
16 | }
17 |
18 | const IExceptionData: IException = {
19 | code: -1,
20 | message: '#网络异常-Net Exception#'
21 | }
22 |
23 | let loading:any = null;
24 | class Request extends EventEmitter {
25 | constructor(){
26 | super();
27 | this.interceptors()
28 | }
29 |
30 | /**
31 | * 数据加载动画效果
32 | */
33 | startLoading(value:string = '') {
34 | if (value) {
35 | loading = ElLoading.service({
36 | target: value,//局部刷新动画,填写class .notice-tabs
37 | lock: false,
38 | fullscreen: false,
39 | text: '加载中...',
40 | background: 'rgba(0,0,0,0.5)'
41 | })
42 | } else {
43 | loading = ElLoading.service({
44 | lock: false,
45 | text: '拼命加载中...',
46 | background: 'rgba(0,0,0,0.7)'
47 | })
48 | }
49 | return loading
50 | }
51 | /**
52 | * 数据停止加载动画效果
53 | */
54 | endLoading() {
55 | if (loading) {
56 | loading.close()
57 | }
58 | }
59 |
60 | /**
61 | * 拦截器处理
62 | */
63 | interceptors() {
64 | // 添加请求拦截器
65 | axios.interceptors.request.use(
66 | (config) => {
67 | let paramsData = config.params || {}
68 | if (!paramsData.hasOwnProperty('getBox')) {
69 | //数据加载动画效果(全屏loading)
70 | this.startLoading()
71 | } else {
72 | if (config.params.getBox) {
73 | //数据加载动画效果(局部loading)
74 | this.startLoading(config.params.getBox)
75 | //剔除该key
76 | delete config.params.getBox
77 | }
78 | }
79 |
80 | //如果未定义config,则默认为空
81 | if (!config) {
82 | config = {};
83 | }
84 | if (!config.headers) {
85 | config.headers = {};
86 | }
87 |
88 | const token = cache.getLocalStorage(G.AUTHORIZATION_TOKEN)
89 | let Authorization:string = ''
90 | if (token.length >= 20) {
91 | Authorization = 'Bearer ' + token;
92 | }
93 | // 为请求头对象,添加 Token 验证的 Authorization 字段
94 | config.headers.Authorization = Authorization;
95 | // 发送请求前的处理
96 | return config
97 | },
98 | error => {
99 | this.error(error,'request')
100 | }
101 | );
102 | // 添加响应拦截器
103 | axios.interceptors.response.use(
104 | // 请求响应的处理
105 | response => {
106 | setTimeout(() => {
107 | //数据结束加载动画效果
108 | this.endLoading();
109 | }, 60);
110 | if (response.hasOwnProperty('status')) {
111 | const status = response.status;
112 | //code 为正常code范围值,响应成功
113 | if ((status >= 200 && status < 300) || status === 304) {
114 | this.code(response.data)
115 | return Promise.resolve(response.data);
116 | } else {
117 | // 响应错误逻辑处理 5xx 4xx 等等
118 | this.error(response,'response#1')
119 | }
120 | } else {
121 | this.error(response,'response#2')
122 | }
123 | },
124 | // 响应错误的处理
125 | error => {
126 | // 状态码
127 | this.error(error,'response#3')
128 | }
129 | );
130 | }
131 | get(url : string,params : any) {
132 | return axios({
133 | method: 'get',
134 | url,
135 | params,
136 | });
137 | }
138 | //在某个div里显示loading加载
139 | getBox(url : string,params : any,box : any = {}) {
140 | params['getBox'] = box['getBox'] || ''
141 | return axios({
142 | method: 'get',
143 | url,
144 | params
145 | });
146 | }
147 |
148 | /**
149 | * upload 请求
150 | * @param { String } url Url
151 | * @param { Object } params 参数/数据
152 | * @param { Object } options 设置header 相关属性、timeout、以及其他http request参数
153 | */
154 | upload(url : string,data : any = '') {
155 | return axios({
156 | method: 'post',
157 | url,
158 | headers: { 'Content-Type': 'multipart/form-data' },
159 | data
160 | });
161 | }
162 |
163 | /**
164 | * Axios Post 请求
165 | * @param { String } url Url
166 | * @param { Object } params 参数/数据
167 | * @param { Object } options 设置header 相关属性、timeout、以及其他http request参数
168 | */
169 | post(url : string,params : any = '',options : any = null) {
170 | let data = this.reqParams(params,options)
171 | return axios({
172 | method: 'post',
173 | url,
174 | data
175 | });
176 | }
177 |
178 | /**
179 | * Axios Delete 请求
180 | * @param { String } url Url
181 | * @param { Object } params 参数/数据
182 | * @param { Object } options 设置header 相关属性、timeout、以及其他http request参数
183 | */
184 | delete(url : string,params : any = '',options : any = null) {
185 | let data = this.reqParams(params,options)
186 | return axios({
187 | method: 'delete',
188 | url,
189 | data
190 | });
191 | }
192 |
193 | /**
194 | * Axios Put 请求
195 | * @param { String } url Url
196 | * @param { Object } params 参数/数据
197 | * @param { Object } options 设置header 相关属性、timeout、以及其他http request参数
198 | */
199 | put(url : string,params : any = '',options: any = null) {
200 | let data = this.reqParams(params,options)
201 | return axios({
202 | method: 'put',
203 | url,
204 | data
205 | });
206 | }
207 |
208 | /**
209 | * Axios Patch 请求
210 | * @param { String } url Url
211 | * @param { Object } params 参数/数据
212 | * @param { Object } options 设置header 相关属性、timeout、以及其他http request参数
213 | */
214 | patch(url : string,params : any = '',options : any = null) {
215 | let data = this.reqParams(params,options)
216 | return axios({
217 | method: 'patch',
218 | url,
219 | data
220 | });
221 | }
222 |
223 | /**
224 | * 处理请求参数
225 | * @param { Object } params 参数/数据
226 | * @param { Object } options 设置header 相关属性、timeout、以及其他http request参数
227 | */
228 | reqParams(params : any, options : any = null) {
229 | if (typeof params === 'object') {
230 | if (Object.keys(params).length < 1) {
231 | params = {}
232 | }
233 | //过滤 {} null [] '' 等长度少于4的
234 | if (JSON.stringify(options).length > 4) {
235 | Object.assign(params, options);
236 | }
237 | return params
238 | }
239 | return {}
240 | }
241 |
242 | /**
243 | * 统一处理code返回值的函数(如果需要对code某些返回值进行拦截处理)
244 | * @param {*} res
245 | * @param {*} resolve
246 | * @param {*} reject
247 | */
248 | code(res : any) {
249 | //统一处理一些特殊的code值,比如权限不足,token过期,接口已关闭,维护中等相关的状态
250 | if (res.hasOwnProperty('code')) {
251 | //如果返回值的code中存在responseCode的内容,则进行处理
252 | if (responseCode.includes(res.code)) {
253 | let message:any
254 | if (res.hasOwnProperty('message')) {
255 | message = res.message
256 | }
257 | }
258 | }
259 | }
260 |
261 | /**
262 | * 成功回调函数
263 | * @param {*} res
264 | * @param {*} resolve
265 | * @param {*} reject
266 | */
267 | success(res : any, resolve : any,reject : any) {
268 | if (res.hasOwnProperty('data')) {
269 | //统一处理一些特俗的code值,比如权限不足,token过期,接口已关闭,维护中等相关的状态
270 | if (res.data) {
271 | resolve(res)
272 | } else {
273 | //失败回调
274 | this.fail(res,reject)
275 | }
276 | } else {
277 | resolve(res)
278 | }
279 | }
280 |
281 |
282 | /**
283 | * 失败回调函数
284 | * @param {*} res 数据
285 | * @param {*} reject
286 | */
287 | fail(res : any, reject : any) {
288 | console.log(res,'+++===---:::Axios Failed:::---===+++')
289 | //数据结束加载动画效果
290 | this.endLoading();
291 | let errExp:IException = {
292 | code: IExceptionData.code,
293 | message:IExceptionData.message + '#fail'
294 | }
295 | return Promise.reject(errExp)
296 | }
297 |
298 | /**
299 | * 失败回调函数
300 | * @param {*} res 数据
301 | * @param {*} reject
302 | */
303 | catch(res : any) {
304 | console.log(res,'+++===---:::Axios Catch Exception:::---===+++')
305 | //数据结束加载动画效果
306 | this.endLoading();
307 | let errExp:IException = {
308 | code: IExceptionData.code,
309 | message:IExceptionData.message + '#catch'
310 | }
311 | return Promise.reject(errExp)
312 | }
313 |
314 | /**
315 | * 异常错误回调函数
316 | * @param {*} error 异常错误数据
317 | * @param {*} type 是request还是response类型
318 | */
319 | error(error : any,type:string) {
320 | console.log(error,'+++===---:::Axios ' + type + ' Error:::---===+++')
321 | //数据结束加载动画效果
322 | this.endLoading();
323 | let errExp:IException = {
324 | code: IExceptionData.code,
325 | message:IExceptionData.message + '#' + type
326 | }
327 | return Promise.reject(errExp)
328 | }
329 | }
330 |
331 | const http = new Request();
332 |
333 | export default http;
334 |
--------------------------------------------------------------------------------
/src/views/admin/user/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
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 | 真名: {{ scope.row.truename }}
45 |
46 |
47 | {{ scope.row.username }}
48 |
49 |
50 |
51 |
52 |
53 |
54 | 普通管理员
55 | 超级管理员
56 | 未分配
57 |
58 |
59 |
65 |
66 | 正常
67 | 暂停
68 | 停用
69 | 未知
70 |
71 |
72 |
73 |
74 | 男性
75 | 女性
76 | 未知
77 |
78 |
79 |
80 |
81 |
82 |
83 | 注册时间: {{ comm.formatDate(scope.row.create_time) }}
84 | 更新时间: {{ comm.formatDate(scope.row.update_time) }}
85 |
86 |
87 | {{ scope.row.login_time }}
88 |
89 |
90 |
91 |
92 |
93 |
94 | {{ comm.long2ip(scope.row.ip) }}
95 |
96 |
97 |
98 |
99 |
100 | 删除
101 |
102 |
103 |
104 |
105 |
106 |
107 |
248 |
249 |
316 |
--------------------------------------------------------------------------------
/src/views/form/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
28 |
29 |
30 |
31 |
32 |
39 |
40 |
41 |
42 | -
43 |
44 |
45 |
46 |
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 | Create
79 | Reset
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | "Full Name" label is automatically attached to the input:
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | "Your Information" serves as a label for the group of inputs.
100 | You must specify labels on the individal inputs. Placeholders are not
101 | replacements for using the "label" attribute.
102 |
103 |
104 |
105 |
106 |
107 |
112 |
113 |
114 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
310 |
311 |
328 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 简体中文 | [English](./README.en.md)
2 |
3 | TodoAdmin-vue
4 |
5 |
6 |
7 |
8 |
9 |
10 | 一阳动、万物生!愿美好不期而遇、愿幸福如约而至、愿疫情早日消散、一起奔赴更好的未来、不辜负你我所有的努力。
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | > TodoAdmin-Vue版:是一个集成管理后台端模板解决方案,项目采用TS脚本语言,基于Vue 3.2+/Vue-cli 5.0+/Vue-router 4.0+、Axios0.2.7+、Element-plus 2.2+、Pinia 2.0+、ECharts 5.3+等搭建,项目是以Composition api风格编写,采用远程API接口和本地Mock双接口模式加载数据。
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | ## 体验Demo地址
40 |
41 | - [Todoadmin-pro Pro专业版演示地址(vue3.2+ 支持 PC、平板、手机)](https://pro.todoadmin.com)
42 | - [Todoadmin-base 基本版演示地址(vue3.2+ 支持 PC、平板、手机)](https://base.todoadmin.com)
43 | 用户名:guest
密码:123456
44 |
45 |
46 |
47 |
48 | ## 克隆vue-admin-chart 项目 [点击访问Github仓库](https://github.com/todoadmin/vue-admin-chart)
49 |
50 | ```bash
51 | # 克隆项目
52 | git clone -b https://github.com/todoadmin/vue-admin-chart.git
53 | # 安装依赖
54 | npm i or yarn install
55 | # 本地开发 启动项目
56 | npm run serve or yarn serve
57 | ```
58 |
59 |
60 | ## 克隆vue-admin-chart 项目 [点击访问Gitee仓库](https://gitee.com/todoadmin/vue-admin-chart)
61 |
62 | ```bash
63 | # 克隆项目
64 | git clone -b https://gitee.com/todoadmin/vue-admin-chart.git
65 | # 安装依赖
66 | npm i or yarn install
67 | # 本地开发 启动项目
68 | npm run serve or yarn serve
69 | ```
70 |
71 |
72 | 以下为Pro版本的相关介绍
73 |
74 |
75 | ## 项目生态插件【依赖】列表
76 |
77 | | 标题名称 | 版本 | 描述 |
78 | | --------------------- | ------------------------------------------------------------ | ------------------------------------------------------- |
79 | | [vue] | [![vue-ico]][vue] | 构建用户界面的渐进式框架 |
80 | | [vue-router] | [![vue-router-ico]][vue-router] | 单页应用程序路由 |
81 | | [vue-cli] | [![vue-cli-ico]][vue-cli] | 项目脚手架 |
82 | | [axios] | [![axios-ico]][axios] | 基于promise的网络请求库 |
83 | | [element-plus] | [![element-plus-ico]][element-plus] | 基于Vue3的组件库 |
84 | | [element-plus-icons] | [![element-plus-icons-ico]][element-plus-icons] | 基于Vue3的组件图标库 |
85 | | [vue-quill] | [![vue-quill-ico]][vue-quill] | 可视化在线文本编辑器 |
86 | | [quill-image-resize] | [![quill-image-resize-ico]][quill-image-resize] | 文本编辑器图片重置尺寸 |
87 | | [vue-cropper] | [![vue-cropper-ico]][vue-cropper] | 基于Vue3的图片裁剪 |
88 | | [pinia] | [![pinia-ico]][pinia] | 状态管理 |
89 | | [vue-i18n-next] | [![vue-i18n-next-ico]][vue-i18n-next] | 多国语言文字切换 |
90 | | [js-md5] | [![js-md5-ico]][js-md5] | MD5加密 |
91 | | [nprogress] | [![nprogress-ico]][nprogress] | 进度条加载 |
92 | | [echarts] | [![echarts-ico]][echarts] | 多功能图表 |
93 |
94 |
95 |
96 | ## 项目安装(依赖安装)
97 | ```
98 | npm install or yarn install
99 | ```
100 |
101 | ### 运行开发环境
102 | ```
103 | npm run serve or yarn serve
104 | ```
105 |
106 | ### 生产环境打包
107 | ```
108 | npm run build or yarn build
109 | ```
110 |
111 | ### 修复文件
112 | ```
113 | npm run lint
114 | ```
115 |
116 | ### 配置文件
117 | ```
118 | #config目录下
119 | /src/config
120 |
121 | #项目主体配置import模块
122 | /src/config/index.ts
123 |
124 | #项目启动环境配置引入模块
125 | /src/config/config.ts
126 |
127 | #项目启动环境(生产环境/Dev环境)基本配置引入模块
128 | /src/config/module/base.ts
129 |
130 | #项目启动环境(生产环境/Dev环境)CDN配置引入模块
131 | /src/config/module/cdn.ts
132 |
133 | #项目主体全局常量import模块
134 | /src/config/module/global.ts
135 |
136 | #项目主体HTTP/HTTPS Restful请求接口地址常量import模块
137 | /src/config/module/HUrl.ts
138 | ```
139 |
140 |
141 | [vue]: https://github.com/vuejs/vue
142 | [vue-ico]:https://img.shields.io/badge/Vue-v3.2.36-brightgreen
143 |
144 | [vue-router]: https://github.com/vuejs/vue-router
145 | [vue-router-ico]:https://img.shields.io/badge/Vue--router-v4.0.15-brightgreen
146 |
147 | [vue-cli]: https://github.com/vuejs/vue-cli
148 | [vue-cli-ico]:https://img.shields.io/badge/Vue--cli-v5.0.1-brightgreen
149 |
150 | [axios]: https://github.com/axios/axios
151 | [axios-ico]:https://img.shields.io/badge/axios-v0.2.7-brightgreen
152 |
153 | [element-plus]: https://github.com/element-plus/element-plus
154 | [element-plus-ico]:https://img.shields.io/badge/element--plus-v2.2.2-brightgreen
155 |
156 | [element-plus-icons]: https://github.com/element-plus/element-plus-icons
157 | [element-plus-icons-ico]:https://img.shields.io/badge/element--plus--icons-2.x-brightgreen
158 |
159 | [vue-quill]: https://github.com/vueup/vue-quill
160 | [vue-quill-ico]:https://img.shields.io/badge/Vue--quill-v1.0.0--beta.8-brightgreen
161 |
162 | [quill-image-resize]: https://github.com/kensnyder/quill-image-resize-module
163 | [quill-image-resize-ico]:https://img.shields.io/badge/Quill--image--resize-v3.0.0-brightgreen
164 |
165 | [vue-cropper]: https://github.com/xyxiao001/vue-cropper
166 | [vue-cropper-ico]:https://img.shields.io/badge/vue--cropper-v1.0.3-brightgreen
167 |
168 | [pinia]: https://github.com/vuejs/pinia
169 | [pinia-ico]:https://img.shields.io/badge/Pinia-v2.0.14-brightgreen
170 |
171 | [vue-jsonp]: https://github.com/LancerComet/vue-jsonp
172 | [vue-jsonp-ico]:https://img.shields.io/badge/Vue--jsonp-v2.0.0-brightgreen
173 |
174 | [vue-i18n-next]: https://github.com/intlify/vue-i18n-next/tree/master/packages/vue-i18n
175 | [vue-i18n-next-ico]:https://img.shields.io/badge/Vue--i18n-v9.1.10-brightgreen
176 |
177 | [js-md5]: https://github.com/emn178/js-md5
178 | [js-md5-ico]:https://img.shields.io/badge/js--md5-v0.7.3-brightgreen
179 |
180 | [nprogress]: https://github.com/rstacruz/nprogress
181 | [nprogress-ico]:https://img.shields.io/badge/nprogress-v0.2.0-brightgreen
182 |
183 | [echarts]: http://echarts.apache.org
184 | [echarts-ico]:https://img.shields.io/badge/echarts-v5.3.2-brightgreen
185 |
186 | ---
187 |
188 | ## 前后端功能简介
189 | 前端
190 | - CDN 分布式引入JS/样式/图片/Json/地图数据
191 | - 独家采用API远程实时数据接口和Mock本地数据双接口,可自由切换API或Mock
192 | - 120+高质量组件页面
193 | - 管理后台采用实时接口数据传输
194 | - 实时生成可视化数据大屏动态图表
195 | - 实时数据采用Websocket交互
196 | - 采用Composition API模式
197 | - 采用JWT 认证
198 | - 实时监控系统&服务器资源使用
199 | - 所有开源版本均可免费商用
200 | - 跨平台 PC、手机端、平板等多端兼容
201 | - 动态路由菜单认证和精确到用户的权限路由渲染
202 | - 支持MarkDown(md)文件加载成Vue组件页面
203 | - 支持mock本地模拟数据和远程模拟数据
204 | - 支持按钮功能级别的权限控制
205 | - 支持会员用户和管理员用户的角色、权限等分配
206 | - 支持多种主题切换以及自定义添加主题样式
207 | - 支持多国语言文字切换
208 | - 支持Pinia的状态管理模式
209 | - 支持自定义Vue指令
210 | - 支持对接第三方物流平台
211 | - 支持绑定第三方账号功能
212 | - 支持日志追溯(用户操作和管理员操作)
213 |
214 | 后端
215 | - 接口语言版本:Go (1.7+)
216 | - 接口语言版本:PHP (8.0.2 +)/Swoole (4.8+)
217 | - 接口语言版本:SpringBoot (2.2+)
218 | - 可支持多种开源关系数据库切换:MySQL、MariaDB、PostgreSQL、openGauss、TiDB
219 | - 可支持多种内存数据库切换:Redis、Memcached
220 | - 可支持关系型数据库的集群
221 | - 可支持内存型数据库的集群
222 | - 可支持静态文件(图片、视频、文档等)云存储和CDN分发
223 |
224 |
225 | ## Demo地址&仓库地址
226 |
227 | - [Todoadmin-pro Pro专业版演示地址(vue3.2+ 支持 PC、平板、手机)](https://pro.todoadmin.com)
228 | - [Todoadmin-base 基本版演示地址(vue3.2+ 支持 PC、平板、手机)](https://base.todoadmin.com)
229 | - [Github 地址](https://github.com/todoadmin/vue-admin-chart)
230 | - [Gitee 码云地址](https://gitee.com/todoadmin/vue-admin-chart)
231 | 用户名:guest
密码:123456
232 |
233 | ## 打赏&联系
234 |
235 | - 请喝杯茶呗,打赏后联系 QQ 308407381
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 | ## 优势&注意事项
249 |
250 | ```
251 | 对比其他开源Admin后台管理框架有如下优势:
252 | 1. 独家采用API远程实时数据接口和Mock本地数据双接口调试(可自由切换数据接口模式)
253 | 2. 支持前后端路由菜单权限和功能按钮权限控制
254 | 3. 采用实时接口传输数据,让你事半功倍
255 | 4. 偏好数据、主题切换、多国语言切换等配置
256 | 5. 支持原生css和scss 自动排序,eslint 自动修复
257 | 6. axios 二次封装,支持多种模式和参数方式
258 | 7. websocket 封装,支持实时数据传输方式
259 | 8. 支持MD5/RSA加密登录
260 | 9. 支持https数据加密传输
261 | 10. 使用CDN分发项目样式css和js、图片,让速度飞起来
262 | 11. 支持全屏操作
263 | 12. 支持MarkDown(md)文件加载成Vue组件页面
264 |
265 | 使用注意事项:
266 | 1. 项目默认使用Chrome浏览器,Vue Devtools 插件调试
267 | 2. 项目默认使用VSCode + Eslint校验规范,需要配置vscode编辑器
268 | 3. 项目也可以使用Goland或IntelliJ IDEA + 相关插件开发
269 | 4. 项目使用MIT开源协议,请保留MIT开源协议即可免费商用
270 |
271 | ```
272 |
273 |
274 | ## 后台效果图预览
275 |
276 | 以下是截取的是 pro 版的效果图展示:
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 | ## 提问
348 |
349 | 如果你有任何疑问可以提出,作者会快速处理
350 |
351 | ## 问题提交
352 |
353 | 如果项目存在任何问题或者Bug,可以提交Issue
354 |
355 |
356 |
357 | ## 浏览器&移动端浏览器
358 |
359 | 主流浏览器和IE 10+.
360 |
361 | | [ ](https://godban.github.io/browsers-support-badges/) IE/Edge | [ ](https://godban.github.io/browsers-support-badges/) Firefox | [ ](https://godban.github.io/browsers-support-badges/) Chrome | [ ](https://godban.github.io/browsers-support-badges/) Safari |
362 | | --------------------------------------------------------- | --------------------------------------------------------- | --------------------------------------------------------- | --------------------------------------------------------- |
363 | | IE10/IE11/Edge | last 2 versions | last 2 versions | last 2 versions |
364 |
365 |
366 | ## 贡献
367 |
368 | 多谢每一位支持本项目的人士!
369 |
370 |
371 |
372 | ## 鸣谢
373 |
374 | | 项目(排名不分先后) |
375 | | ---------------------------------------------------------------- |
376 | | [vue](https://github.com/vuejs/vue) |
377 | | [element-plus](https://github.com/element-plus/element-plus) |
378 | | [pinia](https://github.com/vuejs/pinia) |
379 | | [vue-i18n-next](https://github.com/intlify/vue-i18n-next/tree/master/packages/vue-i18n) |
380 | | [axios](https://github.com/axios/axios) |
381 | | [echarts](http://echarts.apache.org) |
382 | | [nprogress](https://github.com/rstacruz/nprogress) |
383 |
384 |
385 | ## 商用注意事项
386 |
387 | 此项目可免费用于商业用途,请遵守 [MIT](https://opensource.org/licenses/MIT) 协议并保留作者技术支持声明。
388 |
389 | Copyright (c) 2022-present, Todoadmin.com
390 |
--------------------------------------------------------------------------------
/README.en.md:
--------------------------------------------------------------------------------
1 | [简体中文](./README.md) | English
2 |
3 | TodoAdmin-vue
4 |
5 |
6 |
7 |
8 |
9 |
10 | Yang Qi rising, all things are born! May beauty come by chance, happiness come as promised, and the epidemic disappear as soon as possible. Let's go to a better future together and live up to all our efforts.
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | > TodoAdmin-Vue:It is an integrated management back-end template solution. The project uses TS script language and is based onVue 3.2+/Vue-cli 5.0+/Vue-router 4.0+、Axios0.2.7+、Element-plus 2.2+、Pinia 2.0+、ECharts 5.3+,The project is composition API style,use remote API & mock dual interface mode to load data.
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | ## Demo
40 |
41 | - [Todoadmin-pro Pro demo](https://pro.todoadmin.com)
42 | - [Todoadmin-base Basic demo](https://base.todoadmin.com)
43 | Username:guest
Password:123456
44 |
45 |
46 |
47 | ## Clone project [Click Github repository](https://github.com/todoadmin/vue-admin-chart)
48 |
49 | ```bash
50 | # Clone
51 | git clone -b https://github.com/todoadmin/vue-admin-chart.git
52 | # install
53 | npm i or yarn install
54 | # run project
55 | npm run serve or yarn serve
56 | ```
57 |
58 |
59 | ## Clone project [Click Gitee repository](https://gitee.com/todoadmin/vue-admin-chart)
60 |
61 | ```bash
62 | # Clone
63 | git clone -b https://gitee.com/todoadmin/vue-admin-chart.git
64 | # install
65 | npm i or yarn install
66 | # run project
67 | npm run serve or yarn serve
68 | ```
69 |
70 |
71 | The following is a introduction of the pro version
72 |
73 |
74 | ## Ecosystem
75 |
76 | | Project | Status | Description |
77 | | --------------------- | ------------------------------------------------------------ | ------------------------------------------------------- |
78 | | [vue] | [![vue-ico]][vue] | Progressive JS Framework |
79 | | [vue-router] | [![vue-router-ico]][vue-router] | Single-page application routing |
80 | | [vue-cli] | [![vue-cli-ico]][vue-cli] | Project scaffolding |
81 | | [axios] | [![axios-ico]][axios] | Promise network request Library |
82 | | [element-plus] | [![element-plus-ico]][element-plus] | Vue3 component library |
83 | | [element-plus-icons] | [![element-plus-icons-ico]][element-plus-icons] | Vue3 component Icon library |
84 | | [vue-quill] | [![vue-quill-ico]][vue-quill] | Visual online text editor |
85 | | [quill-image-resize] | [![quill-image-resize-ico]][quill-image-resize] | online text resize image |
86 | | [vue-cropper] | [![vue-cropper-ico]][vue-cropper] | vue image cropper |
87 | | [pinia] | [![pinia-ico]][pinia] | state management |
88 | | [vue-i18n-next] | [![vue-i18n-next-ico]][vue-i18n-next] | Multi language |
89 | | [js-md5] | [![js-md5-ico]][js-md5] | MD5 encryption |
90 | | [nprogress] | [![nprogress-ico]][nprogress] | Progress bar loading |
91 | | [echarts] | [![echarts-ico]][echarts] | echarts |
92 |
93 |
94 |
95 | ## Install(dependencies)
96 | ```
97 | npm install or yarn install
98 | ```
99 |
100 | ### Run dev
101 | ```
102 | npm run serve or yarn serve
103 | ```
104 |
105 | ### Build production
106 | ```
107 | npm run build or yarn build
108 | ```
109 |
110 | ### ESLint
111 | ```
112 | npm run lint
113 | ```
114 |
115 | ### Config
116 | ```
117 | #config dir
118 | /src/config
119 |
120 | #project main import module
121 | /src/config/index.ts
122 |
123 | #project run env require module
124 | /src/config/config.ts
125 |
126 | #project run env(production/Dev)base config require module
127 | /src/config/module/base.ts
128 |
129 | #project run env(production/Dev)CDN config require module
130 | /src/config/module/cdn.ts
131 |
132 | #project main global constant import module
133 | /src/config/module/global.ts
134 |
135 | #project HTTP/HTTPS Restful request constant import module
136 | /src/config/module/HUrl.ts
137 | ```
138 |
139 |
140 | [vue]: https://github.com/vuejs/vue
141 | [vue-ico]:https://img.shields.io/badge/Vue-v3.2.36-brightgreen
142 |
143 | [vue-router]: https://github.com/vuejs/vue-router
144 | [vue-router-ico]:https://img.shields.io/badge/Vue--router-v4.0.15-brightgreen
145 |
146 | [vue-cli]: https://github.com/vuejs/vue-cli
147 | [vue-cli-ico]:https://img.shields.io/badge/Vue--cli-v5.0.1-brightgreen
148 |
149 | [axios]: https://github.com/axios/axios
150 | [axios-ico]:https://img.shields.io/badge/axios-v0.2.7-brightgreen
151 |
152 | [element-plus]: https://github.com/element-plus/element-plus
153 | [element-plus-ico]:https://img.shields.io/badge/element--plus-v2.2.2-brightgreen
154 |
155 | [element-plus-icons]: https://github.com/element-plus/element-plus-icons
156 | [element-plus-icons-ico]:https://img.shields.io/badge/element--plus--icons-2.x-brightgreen
157 |
158 | [vue-quill]: https://github.com/vueup/vue-quill
159 | [vue-quill-ico]:https://img.shields.io/badge/Vue--quill-v1.0.0--beta.8-brightgreen
160 |
161 | [quill-image-resize]: https://github.com/kensnyder/quill-image-resize-module
162 | [quill-image-resize-ico]:https://img.shields.io/badge/Quill--image--resize-v3.0.0-brightgreen
163 |
164 | [vue-cropper]: https://github.com/xyxiao001/vue-cropper
165 | [vue-cropper-ico]:https://img.shields.io/badge/vue--cropper-v1.0.3-brightgreen
166 |
167 | [pinia]: https://github.com/vuejs/pinia
168 | [pinia-ico]:https://img.shields.io/badge/Pinia-v2.0.14-brightgreen
169 |
170 | [vue-jsonp]: https://github.com/LancerComet/vue-jsonp
171 | [vue-jsonp-ico]:https://img.shields.io/badge/Vue--jsonp-v2.0.0-brightgreen
172 |
173 | [vue-i18n-next]: https://github.com/intlify/vue-i18n-next/tree/master/packages/vue-i18n
174 | [vue-i18n-next-ico]:https://img.shields.io/badge/Vue--i18n-v9.1.10-brightgreen
175 |
176 | [js-md5]: https://github.com/emn178/js-md5
177 | [js-md5-ico]:https://img.shields.io/badge/js--md5-v0.7.3-brightgreen
178 |
179 | [nprogress]: https://github.com/rstacruz/nprogress
180 | [nprogress-ico]:https://img.shields.io/badge/nprogress-v0.2.0-brightgreen
181 |
182 | [echarts]: http://echarts.apache.org
183 | [echarts-ico]:https://img.shields.io/badge/echarts-v5.3.2-brightgreen
184 |
185 | ---
186 |
187 | ## Introduction functions
188 | Web
189 | - CDN Distributed js/ css / image / map json data
190 | - Adopted exclusively API remote real-time interface and mock data, and API or mock can be switched freely
191 | - 120+ high quality components page
192 | - The management real-time interface data transmission
193 | - Real time generation of large screen dynamic chart of visual data
194 | - Real-time data websocket interaction
195 | - Composition API models
196 | - JWT authentication
197 | - Real-time monitoring system & server resource usage
198 | - Commercially available free of charge
199 | - PC, mobile, tablet and other multi terminal compatibility
200 | - Dynamic routing menu authentication
201 | - Support MarkDown(md) file to Vue Component page
202 | - Support mock data and remote data
203 | - Support button function permission control
204 | - Support the assignment of roles and permissions of member and administrator
205 | - Support multiple theme switching and adding custom theme styles
206 | - Support multi language text switching
207 | - Support Pinia state management
208 | - Support for custom Vue directives
209 | - Support docking with third-party logistics platforms
210 | - Support binding third-party accounts
211 | - Support log tracing (member and administrator operation)
212 |
213 | Restful & Websocket
214 | - Go apis ver(1.7+)
215 | - PHP apis ver (8.0.2 +)/Swoole (4.8+)
216 | - SpringBoot apis ver (2.2+)
217 | - Support multiple open source relational database switching:MySQL、MariaDB、PostgreSQL、openGauss、TiDB
218 | - Supports multiple memory database switching:Redis、Memcached
219 | - Cluster supporting relational database
220 | - Cluster supporting memory database
221 | - Support cloud storage and CDN distribution of static files (images, videos, documents, ...)
222 |
223 |
224 | ## Demo & Repository
225 |
226 | - [Todoadmin-pro Pro demo](https://pro.todoadmin.com)
227 | - [Todoadmin-base Basic demo](https://base.todoadmin.com)
228 | - [Github repository](https://github.com/todoadmin/vue-admin-chart)
229 | - [Gitee repository](https://gitee.com/todoadmin/vue-admin-chart)
230 | Username:guest
Password:123456
231 |
232 | ## Reward & contact
233 |
234 | - If you agree with the project, you can reward and contact QQ:308407381
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 | ## Advantages & considerations
249 |
250 | ```
251 | Compared with other open source admin management, it has the following advantages:
252 | 1. Adopted exclusively remote api real-time interface and mock data, and API or mock can be switched freely
253 | 2. Routing menu permission and button permission control
254 | 3. Use real-time transmit data
255 | 4. Preference data, topic switching, multi language switching ...
256 | 5. Native CSS and SCSS automatic sorting and eslint automatic repair
257 | 6. Axios secondary packaging supports multiple modes and parameter modes
258 | 7. Websocket encapsulation, supporting real-time data transmission
259 | 8. Support md5/rsa encryption login
260 | 9. Support HTTPS data encryption transmission
261 | 10. Use CDN to distribute CSS, JS and image, so speed up
262 | 11. Full screen operation
263 | 12. Support MarkDown(md) file to Vue Component page
264 |
265 | Precautions for use:
266 | 1. Project uses Chrome browser , and Vue devtools plug-in debugging
267 | 2. Project uses the vscode + eslint verification, vscode editor needs to be configured
268 | 3. Project can also be developed using Golan or IntelliJ idea + related plug-ins
269 | 4. Project uses the MIT protocol. Please keep the MIT protocol for free commercial use
270 |
271 | ```
272 |
273 |
274 | ## Rendering Preview
275 |
276 | The following is the screenshot of the pro version:
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 | ## Questions
348 |
349 | For questions and support please use the official forum or community chat. The issue list of this repo is exclusively for bug reports and feature requests.
350 |
351 | ## Issues
352 |
353 | Please make sure to read the Issue Reporting Checklist before opening an issue. Issues not conforming to the guidelines may be closed immediately.
354 |
355 |
356 |
357 | ## Browser & mob
358 |
359 | Mainstream browsers and IE 10+.
360 |
361 | | [ ](https://godban.github.io/browsers-support-badges/) IE/Edge | [ ](https://godban.github.io/browsers-support-badges/) Firefox | [ ](https://godban.github.io/browsers-support-badges/) Chrome | [ ](https://godban.github.io/browsers-support-badges/) Safari |
362 | | --------------------------------------------------------- | --------------------------------------------------------- | --------------------------------------------------------- | --------------------------------------------------------- |
363 | | IE10/IE11/Edge | last 2 versions | last 2 versions | last 2 versions |
364 |
365 |
366 | ## Contribution
367 |
368 | Thank you to everyone who supports this project!
369 |
370 |
371 |
372 | ## Acknowledgment
373 |
374 | | Projects (in no particular order) |
375 | | ---------------------------------------------------------------- |
376 | | [vue](https://github.com/vuejs/vue) |
377 | | [element-plus](https://github.com/element-plus/element-plus) |
378 | | [pinia](https://github.com/vuejs/pinia) |
379 | | [vue-i18n-next](https://github.com/intlify/vue-i18n-next/tree/master/packages/vue-i18n) |
380 | | [axios](https://github.com/axios/axios) |
381 | | [echarts](http://echarts.apache.org) |
382 | | [nprogress](https://github.com/rstacruz/nprogress) |
383 |
384 |
385 | ## Commercial considerations
386 |
387 | This project can be used for commercial purposes free of charge. Please comply with [MIT]( https://opensource.org/licenses/MIT )Agreement and retention of the author's technical support statement
388 |
389 | Copyright (c) 2022-present, Todoadmin.com
390 |
--------------------------------------------------------------------------------
/src/views/form/other.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Update Github template
17 | Tom committed 2018/4/12 20:46
18 |
19 |
20 |
21 |
22 | Update Github template
23 | Tom committed 2018/4/3 20:46
24 |
25 |
26 |
27 |
28 | Update Github template
29 | Tom committed 2018/4/2 20:46
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | Dark
40 |
47 | {{ item.label }}
48 |
49 |
57 | {{ item.label }}
58 |
59 |
60 |
61 | Plain
62 |
69 | {{ item.label }}
70 |
71 |
79 | {{ item.label }}
80 |
81 |
82 |
83 |
84 |
85 |
86 | Content
87 |
88 |
94 | Content
95 |
96 |
97 |
98 |
99 |
100 |
101 | {{ percentage }}%
102 | Progressing
103 |
104 |
105 |
106 |
107 |
108 |
109 | Default
110 | Primary
111 | Success
112 | Info
113 | Warning
114 | Danger
115 | 中文
116 |
117 |
118 |
119 | Plain
120 | Primary
121 | Success
122 | Info
123 | Warning
124 | Danger
125 |
126 |
127 |
128 | Round
129 | Primary
130 | Success
131 | Info
132 | Warning
133 | Danger
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
158 |
159 |
163 |
164 |
Yummy hamburger
165 |
166 | {{ currentDate }}
167 | Operating
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
197 |
198 | Back
199 |
200 |
201 |
202 |
203 |
208 |
209 | Back
210 |
211 |
212 |
213 |
214 |
219 |
220 | Back
221 |
222 |
223 |
224 |
225 |
226 |
227 | Using slot as subtitle
228 |
229 |
230 | Back
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 | Large
242 | Default
243 | Small
244 |
245 |
246 |
253 |
254 | Operation
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 | Username
263 |
264 |
265 | kooriookami
266 |
267 |
268 |
269 |
270 |
271 |
272 | Telephone
273 |
274 |
275 | 18100000000
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 | Place
284 |
285 |
286 | Suzhou
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 | Remarks
295 |
296 |
297 | School
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 | Address
306 |
307 |
308 | No.1188, Wuzhong Avenue, Wuzhong District, Suzhou, Jiangsu Province
309 |
310 |
311 |
312 |
319 |
320 | Operation
321 |
322 | kooriookami
323 | 18100000000
324 | Suzhou
325 |
326 | School
327 |
328 | No.1188, Wuzhong Avenue, Wuzhong District, Suzhou, Jiangsu Province
330 |
331 |
332 |
333 |
334 |
335 |
336 |
483 |
484 |
556 |
--------------------------------------------------------------------------------