mirror of
				https://github.com/yzcheng90/x-springboot-ui
				synced 2025-11-04 05:35:56 +08:00 
			
		
		
		
	提交
This commit is contained in:
		
							
								
								
									
										5
									
								
								.env
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.env
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
# port 端口号
 | 
			
		||||
VUE_APP_PORT = 9999
 | 
			
		||||
 | 
			
		||||
# open 运行 npm run dev 时自动打开浏览器
 | 
			
		||||
VUE_APP_OPEN = false
 | 
			
		||||
							
								
								
									
										2
									
								
								.env.development
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								.env.development
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
# 开发环境
 | 
			
		||||
VUE_APP_BASE_API = 'http://localhost:9999/'
 | 
			
		||||
							
								
								
									
										2
									
								
								.env.production
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								.env.production
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
# 线上环境
 | 
			
		||||
VUE_APP_BASE_API = ''
 | 
			
		||||
							
								
								
									
										18
									
								
								.eslintignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								.eslintignore
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
*.sh
 | 
			
		||||
node_modules
 | 
			
		||||
lib
 | 
			
		||||
*.md
 | 
			
		||||
*.scss
 | 
			
		||||
*.woff
 | 
			
		||||
*.ttf
 | 
			
		||||
*.json
 | 
			
		||||
.vscode
 | 
			
		||||
.idea
 | 
			
		||||
dist
 | 
			
		||||
mock
 | 
			
		||||
public
 | 
			
		||||
bin
 | 
			
		||||
build
 | 
			
		||||
config
 | 
			
		||||
index.html
 | 
			
		||||
src/assets
 | 
			
		||||
							
								
								
									
										22
									
								
								.eslintrc.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								.eslintrc.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
	root: true,
 | 
			
		||||
	env: {
 | 
			
		||||
		node: true,
 | 
			
		||||
	},
 | 
			
		||||
	parserOptions: {
 | 
			
		||||
		parser: '@babel/eslint-parser',
 | 
			
		||||
	},
 | 
			
		||||
	plugins: ['vue'],
 | 
			
		||||
	extends: ['plugin:vue/essential', 'eslint:recommended'],
 | 
			
		||||
	rules: {
 | 
			
		||||
		// http://eslint.cn/docs/rules/
 | 
			
		||||
		'vue/no-parsing-error': 'off',
 | 
			
		||||
		'no-unused-vars': 'error',
 | 
			
		||||
		'no-dupe-args': 'error',
 | 
			
		||||
		'no-empty': 'off',
 | 
			
		||||
		'no-extra-semi': 'off',
 | 
			
		||||
		'no-constant-condition': 'off',
 | 
			
		||||
		'no-console': 'error',
 | 
			
		||||
		'vue/multi-word-component-names': 'off',
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										22
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
node_modules
 | 
			
		||||
.DS_Store
 | 
			
		||||
/dist
 | 
			
		||||
 | 
			
		||||
# local env files
 | 
			
		||||
.env.local
 | 
			
		||||
.env.*.local
 | 
			
		||||
 | 
			
		||||
# Log files
 | 
			
		||||
npm-debug.log*
 | 
			
		||||
yarn-debug.log*
 | 
			
		||||
yarn-error.log*
 | 
			
		||||
pnpm-debug.log*
 | 
			
		||||
 | 
			
		||||
# Editor directories and files
 | 
			
		||||
.idea
 | 
			
		||||
.vscode
 | 
			
		||||
*.suo
 | 
			
		||||
*.ntvs*
 | 
			
		||||
*.njsproj
 | 
			
		||||
*.sln
 | 
			
		||||
*.sw?
 | 
			
		||||
							
								
								
									
										39
									
								
								.prettierrc.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								.prettierrc.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
	// 一行最多多少个字符
 | 
			
		||||
	printWidth: 150,
 | 
			
		||||
	// 指定每个缩进级别的空格数
 | 
			
		||||
	tabWidth: 2,
 | 
			
		||||
	// 使用制表符而不是空格缩进行
 | 
			
		||||
	useTabs: true,
 | 
			
		||||
	// 在语句末尾打印分号
 | 
			
		||||
	semi: true,
 | 
			
		||||
	// 使用单引号而不是双引号
 | 
			
		||||
	singleQuote: true,
 | 
			
		||||
	// 更改引用对象属性的时间 可选值"<as-needed|consistent|preserve>"
 | 
			
		||||
	quoteProps: 'as-needed',
 | 
			
		||||
	// 在JSX中使用单引号而不是双引号
 | 
			
		||||
	jsxSingleQuote: false,
 | 
			
		||||
	// 多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"<none|es5|all>",默认none
 | 
			
		||||
	trailingComma: 'es5',
 | 
			
		||||
	// 在对象文字中的括号之间打印空格
 | 
			
		||||
	bracketSpacing: true,
 | 
			
		||||
	// jsx 标签的反尖括号需要换行
 | 
			
		||||
	jsxBracketSameLine: false,
 | 
			
		||||
	// 在单独的箭头函数参数周围包括括号 always:(x) => x \ avoid:x => x
 | 
			
		||||
	arrowParens: 'always',
 | 
			
		||||
	// 这两个选项可用于格式化以给定字符偏移量(分别包括和不包括)开始和结束的代码
 | 
			
		||||
	rangeStart: 0,
 | 
			
		||||
	rangeEnd: Infinity,
 | 
			
		||||
	// 指定要使用的解析器,不需要写文件开头的 @prettier
 | 
			
		||||
	requirePragma: false,
 | 
			
		||||
	// 不需要自动在文件开头插入 @prettier
 | 
			
		||||
	insertPragma: false,
 | 
			
		||||
	// 使用默认的折行标准 always\never\preserve
 | 
			
		||||
	proseWrap: 'preserve',
 | 
			
		||||
	// 指定HTML文件的全局空格敏感度 css\strict\ignore
 | 
			
		||||
	htmlWhitespaceSensitivity: 'css',
 | 
			
		||||
	// Vue文件脚本和样式标签缩进
 | 
			
		||||
	vueIndentScriptAndStyle: false,
 | 
			
		||||
	// 换行符使用 lf 结尾是 可选值"<auto|lf|crlf|cr>"
 | 
			
		||||
	endOfLine: 'lf',
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										21
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
MIT License
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2021 lyt-Top
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
in the Software without restriction, including without limitation the rights
 | 
			
		||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
SOFTWARE.
 | 
			
		||||
							
								
								
									
										37
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
 | 
			
		||||
#### 🚧 安装 cnpm、yarn
 | 
			
		||||
 | 
			
		||||
- 复制代码(桌面 cmd 运行) `npm install -g cnpm --registry=https://registry.npm.taobao.org`
 | 
			
		||||
- 复制代码(桌面 cmd 运行) `npm install -g yarn`
 | 
			
		||||
 | 
			
		||||
#### ⚡ 使用说明
 | 
			
		||||
 | 
			
		||||
建议使用 cnpm,因为 yarn 有时会报错。`npm install` 安装报错的话,请使用 `cnpm install`。
 | 
			
		||||
 | 
			
		||||
> 注意:`node` 需大于 `12.xxx` 小于等于 `v16.14.0`,否则安装依赖将报错。
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
# 克隆项目
 | 
			
		||||
git clone https://gitee.com/lyt-top/vue-next-admin.git
 | 
			
		||||
 | 
			
		||||
# 进入项目
 | 
			
		||||
cd vue-next-admin
 | 
			
		||||
 | 
			
		||||
# 切换分支
 | 
			
		||||
git checkout vue-prev-admin
 | 
			
		||||
 | 
			
		||||
# 安装依赖
 | 
			
		||||
cnpm install
 | 
			
		||||
cnpm install eslint-webpack-plugin --save-dev
 | 
			
		||||
cnpm install core-js --save-dev
 | 
			
		||||
 | 
			
		||||
# 运行项目
 | 
			
		||||
cnpm run dev
 | 
			
		||||
 | 
			
		||||
# 打包发布
 | 
			
		||||
cnpm run build
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### 📚 开发文档
 | 
			
		||||
 | 
			
		||||
- 查看开发文档:<a href="https://lyt-top.gitee.io/vue-next-admin-doc-preview" target="_blank">vue-next-admin-doc</a>
 | 
			
		||||
							
								
								
									
										4
									
								
								babel.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								babel.config.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
	presets: ['@vue/cli-plugin-babel/preset'],
 | 
			
		||||
	plugins: ['@babel/plugin-proposal-optional-chaining'],
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										11
									
								
								jsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								jsconfig.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
{
 | 
			
		||||
	"compilerOptions": {
 | 
			
		||||
		"allowJs": true,
 | 
			
		||||
		"lib": ["esnext", "dom", "dom.iterable", "scripthost"],
 | 
			
		||||
		"jsx": "preserve",
 | 
			
		||||
		"baseUrl": ".",
 | 
			
		||||
		"paths": {
 | 
			
		||||
			"/@/*": ["src/*"]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										71
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "vue-prev-admin",
 | 
			
		||||
  "version": "1.2.1",
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "description": "vue2 webpack admin template",
 | 
			
		||||
  "author": "lyt_20201208",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "dev": "vue-cli-service serve",
 | 
			
		||||
    "build": "vue-cli-service build",
 | 
			
		||||
    "lint": "vue-cli-service lint",
 | 
			
		||||
    "webpack": "webpack --version"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "axios": "0.24.0",
 | 
			
		||||
    "clipboard": "2.0.8",
 | 
			
		||||
    "countup.js": "2.0.8",
 | 
			
		||||
    "echarts": "5.2.2",
 | 
			
		||||
    "element-ui": "2.15.6",
 | 
			
		||||
    "nprogress": "0.2.0",
 | 
			
		||||
    "screenfull": "5.2.0",
 | 
			
		||||
    "sign-canvas": "1.1.4",
 | 
			
		||||
    "vue": "2.6.14",
 | 
			
		||||
    "vue-i18n": "8.26.7",
 | 
			
		||||
    "vue-particles": "1.0.9",
 | 
			
		||||
    "vue-router": "3.5.3",
 | 
			
		||||
    "vue-seamless-scroll": "1.1.23",
 | 
			
		||||
    "vuex": "3.6.2"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@babel/eslint-parser": "7.16.5",
 | 
			
		||||
    "@babel/plugin-proposal-optional-chaining": "7.17.12",
 | 
			
		||||
    "@vue/cli-plugin-babel": "4.5.15",
 | 
			
		||||
    "@vue/cli-plugin-eslint": "4.5.15",
 | 
			
		||||
    "@vue/cli-plugin-router": "4.5.15",
 | 
			
		||||
    "@vue/cli-plugin-vuex": "4.5.15",
 | 
			
		||||
    "@vue/cli-service": "4.5.15",
 | 
			
		||||
    "core-js": "^3.27.1",
 | 
			
		||||
    "eslint": "7.0.0",
 | 
			
		||||
    "eslint-plugin-vue": "8.2.0",
 | 
			
		||||
    "eslint-webpack-plugin": "^3.2.0",
 | 
			
		||||
    "sass": "1.45.0",
 | 
			
		||||
    "sass-loader": "10.1.1",
 | 
			
		||||
    "vue-template-compiler": "2.6.14"
 | 
			
		||||
  },
 | 
			
		||||
  "browserslist": [
 | 
			
		||||
    "> 1%",
 | 
			
		||||
    "last 2 versions",
 | 
			
		||||
    "not dead"
 | 
			
		||||
  ],
 | 
			
		||||
  "bugs": {
 | 
			
		||||
    "url": "https://gitee.com/lyt-top/vue-next-admin/issues"
 | 
			
		||||
  },
 | 
			
		||||
  "engines": {
 | 
			
		||||
    "node": ">=12.0.0",
 | 
			
		||||
    "npm": ">= 6.0.0"
 | 
			
		||||
  },
 | 
			
		||||
  "keywords": [
 | 
			
		||||
    "vue",
 | 
			
		||||
    "vue3",
 | 
			
		||||
    "vuejs/vue-next",
 | 
			
		||||
    "element-ui",
 | 
			
		||||
    "element-plus",
 | 
			
		||||
    "vue-next-admin",
 | 
			
		||||
    "next-admin"
 | 
			
		||||
  ],
 | 
			
		||||
  "repository": {
 | 
			
		||||
    "type": "git",
 | 
			
		||||
    "url": "https://gitee.com/lyt-top/vue-next-admin.git"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										290
									
								
								public/admin.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								public/admin.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,290 @@
 | 
			
		||||
{
 | 
			
		||||
	"code": 0,
 | 
			
		||||
	"data": [
 | 
			
		||||
		{
 | 
			
		||||
			"path": "/home",
 | 
			
		||||
			"name": "home",
 | 
			
		||||
			"component": "home",
 | 
			
		||||
			"meta": {
 | 
			
		||||
				"title": "message.router.home",
 | 
			
		||||
				"isLink": "",
 | 
			
		||||
				"isHide": false,
 | 
			
		||||
				"isKeepAlive": true,
 | 
			
		||||
				"isAffix": true,
 | 
			
		||||
				"isIframe": false,
 | 
			
		||||
				"roles": ["admin", "common"],
 | 
			
		||||
				"icon": "iconfont icon-shouye"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"path": "/tools",
 | 
			
		||||
			"name": "tools",
 | 
			
		||||
			"component": "tools",
 | 
			
		||||
			"meta": {
 | 
			
		||||
				"title": "message.router.tools",
 | 
			
		||||
				"isLink": "",
 | 
			
		||||
				"isHide": false,
 | 
			
		||||
				"isKeepAlive": true,
 | 
			
		||||
				"isAffix": false,
 | 
			
		||||
				"isIframe": false,
 | 
			
		||||
				"roles": ["admin", "common"],
 | 
			
		||||
				"icon": "iconfont icon-gongju"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"path": "/menu",
 | 
			
		||||
			"name": "menu",
 | 
			
		||||
			"component": "layout/routerView/parent",
 | 
			
		||||
			"redirect": "/menu/menu1",
 | 
			
		||||
			"meta": {
 | 
			
		||||
				"title": "message.router.menu",
 | 
			
		||||
				"isLink": "",
 | 
			
		||||
				"isHide": false,
 | 
			
		||||
				"isKeepAlive": true,
 | 
			
		||||
				"isAffix": false,
 | 
			
		||||
				"isIframe": false,
 | 
			
		||||
				"roles": ["admin", "common"],
 | 
			
		||||
				"icon": "iconfont icon-caidan"
 | 
			
		||||
			},
 | 
			
		||||
			"children": [
 | 
			
		||||
				{
 | 
			
		||||
					"path": "/menu/menu1",
 | 
			
		||||
					"name": "menu1",
 | 
			
		||||
					"component": "layout/routerView/parent",
 | 
			
		||||
					"redirect": "/menu/menu1/menu11",
 | 
			
		||||
					"meta": {
 | 
			
		||||
						"title": "message.router.menu1",
 | 
			
		||||
						"isLink": "",
 | 
			
		||||
						"isHide": false,
 | 
			
		||||
						"isKeepAlive": true,
 | 
			
		||||
						"isAffix": false,
 | 
			
		||||
						"isIframe": false,
 | 
			
		||||
						"roles": ["admin", "common"],
 | 
			
		||||
						"icon": "iconfont icon-caidan"
 | 
			
		||||
					},
 | 
			
		||||
					"children": [
 | 
			
		||||
						{
 | 
			
		||||
							"path": "/menu/menu1/menu11",
 | 
			
		||||
							"name": "menu11",
 | 
			
		||||
							"component": "menu/menu1/menu11/index",
 | 
			
		||||
							"meta": {
 | 
			
		||||
								"title": "message.router.menu11",
 | 
			
		||||
								"isLink": "",
 | 
			
		||||
								"isHide": false,
 | 
			
		||||
								"isKeepAlive": true,
 | 
			
		||||
								"isAffix": false,
 | 
			
		||||
								"isIframe": false,
 | 
			
		||||
								"roles": ["admin", "common"],
 | 
			
		||||
								"icon": "iconfont icon-caidan"
 | 
			
		||||
							}
 | 
			
		||||
						},
 | 
			
		||||
						{
 | 
			
		||||
							"path": "/menu/menu1/menu12",
 | 
			
		||||
							"name": "menu12",
 | 
			
		||||
							"component": "layout/routerView/parent",
 | 
			
		||||
							"redirect": "/menu/menu1/menu12/menu121",
 | 
			
		||||
							"meta": {
 | 
			
		||||
								"title": "message.router.menu12",
 | 
			
		||||
								"isLink": "",
 | 
			
		||||
								"isHide": false,
 | 
			
		||||
								"isKeepAlive": true,
 | 
			
		||||
								"isAffix": false,
 | 
			
		||||
								"isIframe": false,
 | 
			
		||||
								"roles": ["admin", "common"],
 | 
			
		||||
								"icon": "iconfont icon-caidan"
 | 
			
		||||
							},
 | 
			
		||||
							"children": [
 | 
			
		||||
								{
 | 
			
		||||
									"path": "/menu/menu1/menu12/menu121",
 | 
			
		||||
									"name": "menu121",
 | 
			
		||||
									"component": "menu/menu1/menu12/menu121/index",
 | 
			
		||||
									"meta": {
 | 
			
		||||
										"title": "message.router.menu121",
 | 
			
		||||
										"isLink": "",
 | 
			
		||||
										"isHide": false,
 | 
			
		||||
										"isKeepAlive": true,
 | 
			
		||||
										"isAffix": false,
 | 
			
		||||
										"isIframe": false,
 | 
			
		||||
										"roles": ["admin", "common"],
 | 
			
		||||
										"icon": "iconfont icon-caidan"
 | 
			
		||||
									}
 | 
			
		||||
								},
 | 
			
		||||
								{
 | 
			
		||||
									"path": "/menu/menu1/menu12/menu122",
 | 
			
		||||
									"name": "menu122",
 | 
			
		||||
									"component": "menu/menu1/menu12/menu122/index",
 | 
			
		||||
									"meta": {
 | 
			
		||||
										"title": "message.router.menu122",
 | 
			
		||||
										"isLink": "",
 | 
			
		||||
										"isHide": false,
 | 
			
		||||
										"isKeepAlive": true,
 | 
			
		||||
										"isAffix": false,
 | 
			
		||||
										"isIframe": false,
 | 
			
		||||
										"roles": ["admin", "common"],
 | 
			
		||||
										"icon": "iconfont icon-caidan"
 | 
			
		||||
									}
 | 
			
		||||
								}
 | 
			
		||||
							]
 | 
			
		||||
						},
 | 
			
		||||
						{
 | 
			
		||||
							"path": "/menu/menu1/menu13",
 | 
			
		||||
							"name": "menu13",
 | 
			
		||||
							"component": "menu/menu1/menu13/index",
 | 
			
		||||
							"meta": {
 | 
			
		||||
								"title": "message.router.menu13",
 | 
			
		||||
								"isLink": "",
 | 
			
		||||
								"isHide": false,
 | 
			
		||||
								"isKeepAlive": true,
 | 
			
		||||
								"isAffix": false,
 | 
			
		||||
								"isIframe": false,
 | 
			
		||||
								"roles": ["admin", "common"],
 | 
			
		||||
								"icon": "iconfont icon-caidan"
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					]
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					"path": "/menu/menu2",
 | 
			
		||||
					"name": "menu2",
 | 
			
		||||
					"component": "menu/menu2/index",
 | 
			
		||||
					"meta": {
 | 
			
		||||
						"title": "message.router.menu2",
 | 
			
		||||
						"isLink": "",
 | 
			
		||||
						"isHide": false,
 | 
			
		||||
						"isKeepAlive": true,
 | 
			
		||||
						"isAffix": false,
 | 
			
		||||
						"isIframe": false,
 | 
			
		||||
						"roles": ["admin", "common"],
 | 
			
		||||
						"icon": "iconfont icon-caidan"
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			]
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"path": "/fun",
 | 
			
		||||
			"name": "funIndex",
 | 
			
		||||
			"component": "layout/routerView/parent",
 | 
			
		||||
			"redirect": "/fun/tagsView",
 | 
			
		||||
			"meta": {
 | 
			
		||||
				"title": "message.router.funIndex",
 | 
			
		||||
				"isLink": "",
 | 
			
		||||
				"isHide": false,
 | 
			
		||||
				"isKeepAlive": true,
 | 
			
		||||
				"isAffix": false,
 | 
			
		||||
				"isIframe": false,
 | 
			
		||||
				"roles": ["admin", "common"],
 | 
			
		||||
				"icon": "iconfont icon-crew_feature"
 | 
			
		||||
			},
 | 
			
		||||
			"children": [
 | 
			
		||||
				{
 | 
			
		||||
					"path": "/fun/tagsView",
 | 
			
		||||
					"name": "funTagsView",
 | 
			
		||||
					"component": "fun/tagsView/index",
 | 
			
		||||
					"meta": {
 | 
			
		||||
						"title": "message.router.funTagsView",
 | 
			
		||||
						"isLink": "",
 | 
			
		||||
						"isHide": false,
 | 
			
		||||
						"isKeepAlive": true,
 | 
			
		||||
						"isAffix": false,
 | 
			
		||||
						"isIframe": false,
 | 
			
		||||
						"roles": ["admin", "common"],
 | 
			
		||||
						"icon": "el-icon-thumb"
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					"path": "/fun/signCanvas",
 | 
			
		||||
					"name": "funSignCanvas",
 | 
			
		||||
					"component": "fun/signCanvas/index",
 | 
			
		||||
					"meta": {
 | 
			
		||||
						"title": "message.router.funSignCanvas",
 | 
			
		||||
						"isLink": "",
 | 
			
		||||
						"isHide": false,
 | 
			
		||||
						"isKeepAlive": true,
 | 
			
		||||
						"isAffix": false,
 | 
			
		||||
						"isIframe": false,
 | 
			
		||||
						"roles": ["admin", "common"],
 | 
			
		||||
						"icon": "el-icon-edit"
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			]
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"path": "/pages",
 | 
			
		||||
			"name": "pagesIndex",
 | 
			
		||||
			"component": "layout/routerView/parent",
 | 
			
		||||
			"redirect": "/pages/formAdapt",
 | 
			
		||||
			"meta": {
 | 
			
		||||
				"title": "message.router.pagesIndex",
 | 
			
		||||
				"isLink": "",
 | 
			
		||||
				"isHide": false,
 | 
			
		||||
				"isKeepAlive": true,
 | 
			
		||||
				"isAffix": false,
 | 
			
		||||
				"isIframe": false,
 | 
			
		||||
				"roles": ["admin", "common"],
 | 
			
		||||
				"icon": "iconfont icon-fuzhiyemian"
 | 
			
		||||
			},
 | 
			
		||||
			"children": [
 | 
			
		||||
				{
 | 
			
		||||
					"path": "/pages/formAdapt",
 | 
			
		||||
					"name": "pagesFormAdapt",
 | 
			
		||||
					"component": "pages/formAdapt/index",
 | 
			
		||||
					"meta": {
 | 
			
		||||
						"title": "message.router.pagesFormAdapt",
 | 
			
		||||
						"isLink": "",
 | 
			
		||||
						"isHide": false,
 | 
			
		||||
						"isKeepAlive": true,
 | 
			
		||||
						"isAffix": false,
 | 
			
		||||
						"isIframe": false,
 | 
			
		||||
						"roles": ["admin", "common"],
 | 
			
		||||
						"icon": "iconfont icon-biaodan"
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			]
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"path": "/personal",
 | 
			
		||||
			"name": "personal",
 | 
			
		||||
			"component": "personal/index",
 | 
			
		||||
			"meta": {
 | 
			
		||||
				"title": "message.router.personal",
 | 
			
		||||
				"isLink": "",
 | 
			
		||||
				"isHide": false,
 | 
			
		||||
				"isKeepAlive": true,
 | 
			
		||||
				"isAffix": false,
 | 
			
		||||
				"isIframe": false,
 | 
			
		||||
				"roles": ["admin", "common"],
 | 
			
		||||
				"icon": "iconfont icon-gerenzhongxin"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"path": "/link",
 | 
			
		||||
			"name": "layoutLinkView",
 | 
			
		||||
			"component": "layout/routerView/parent",
 | 
			
		||||
			"meta": {
 | 
			
		||||
				"title": "message.router.layoutLinkView",
 | 
			
		||||
				"isLink": "https://element-plus.gitee.io/#/zh-CN/component/installation",
 | 
			
		||||
				"isHide": false,
 | 
			
		||||
				"isKeepAlive": false,
 | 
			
		||||
				"isAffix": false,
 | 
			
		||||
				"isIframe": false,
 | 
			
		||||
				"roles": ["admin"],
 | 
			
		||||
				"icon": "iconfont icon-caozuo-wailian"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"path": "/iframes",
 | 
			
		||||
			"name": "layoutIfameView",
 | 
			
		||||
			"component": "layout/routerView/parent",
 | 
			
		||||
			"meta": {
 | 
			
		||||
				"title": "message.router.layoutIfameView",
 | 
			
		||||
				"isLink": "https://element-plus.gitee.io/zh-CN/#/zh-CN/component/installation",
 | 
			
		||||
				"isHide": false,
 | 
			
		||||
				"isKeepAlive": false,
 | 
			
		||||
				"isAffix": true,
 | 
			
		||||
				"isIframe": true,
 | 
			
		||||
				"roles": ["admin"],
 | 
			
		||||
				"icon": "iconfont icon-neiqianshujuchucun"
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								public/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 1.1 KiB  | 
							
								
								
									
										30
									
								
								public/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								public/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
	<head>
 | 
			
		||||
		<meta charset="UTF-8" />
 | 
			
		||||
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
 | 
			
		||||
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
 | 
			
		||||
		<meta
 | 
			
		||||
			name="keywords"
 | 
			
		||||
			content="vue-next-admin,vue-prev-admin,vue-admin-wonderful,后台管理系统一站式平台模板,希望可以帮你完成快速开发。vue2.x,vue2.0,vue2,vue3,vue3.x,vue3.0,CompositionAPI,typescript,element plus,element,plus,admin,wonderful,wonderful-next,vue-next-admin,vite,vite-admin,快速,高效,后台模板,后台系统,管理系统"
 | 
			
		||||
		/>
 | 
			
		||||
		<meta
 | 
			
		||||
			name="description"
 | 
			
		||||
			content="vue-next-admin,基于 vue3 + CompositionAPI + typescript + vite + element plus,适配手机、平板、pc 的后台开源免费管理系统模板!vue-prev-admin,基于 vue2 +  element ui,适配手机、平板、pc 的后台开源免费管理系统模板!"
 | 
			
		||||
		/>
 | 
			
		||||
		<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
 | 
			
		||||
		<title>vue-prev-admin</title>
 | 
			
		||||
	</head>
 | 
			
		||||
	<body>
 | 
			
		||||
		<div id="app"></div>
 | 
			
		||||
		<script type="text/javascript">
 | 
			
		||||
			var _hmt = _hmt || [];
 | 
			
		||||
			(function() {
 | 
			
		||||
				var hm = document.createElement('script');
 | 
			
		||||
				hm.src = 'https://hm.baidu.com/hm.js?9d1e524198ede8205ac7c938c243344c';
 | 
			
		||||
				var s = document.getElementsByTagName('script')[0];
 | 
			
		||||
				s.parentNode.insertBefore(hm, s);
 | 
			
		||||
			})();
 | 
			
		||||
		</script>
 | 
			
		||||
	</body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										227
									
								
								public/test.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								public/test.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,227 @@
 | 
			
		||||
{
 | 
			
		||||
	"code": 0,
 | 
			
		||||
	"data": [
 | 
			
		||||
		{
 | 
			
		||||
			"path": "/home",
 | 
			
		||||
			"name": "home",
 | 
			
		||||
			"component": "home",
 | 
			
		||||
			"meta": {
 | 
			
		||||
				"title": "message.router.home",
 | 
			
		||||
				"isLink": "",
 | 
			
		||||
				"isHide": false,
 | 
			
		||||
				"isKeepAlive": true,
 | 
			
		||||
				"isAffix": true,
 | 
			
		||||
				"isIframe": false,
 | 
			
		||||
				"roles": ["admin", "common"],
 | 
			
		||||
				"icon": "iconfont icon-shouye"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"path": "/tools",
 | 
			
		||||
			"name": "tools",
 | 
			
		||||
			"component": "tools",
 | 
			
		||||
			"meta": {
 | 
			
		||||
				"title": "message.router.tools",
 | 
			
		||||
				"isLink": "",
 | 
			
		||||
				"isHide": false,
 | 
			
		||||
				"isKeepAlive": true,
 | 
			
		||||
				"isAffix": false,
 | 
			
		||||
				"isIframe": false,
 | 
			
		||||
				"roles": ["admin"],
 | 
			
		||||
				"icon": "iconfont icon-gongju"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"path": "/menu",
 | 
			
		||||
			"name": "menu",
 | 
			
		||||
			"component": "layout/routerView/parent",
 | 
			
		||||
			"redirect": "/menu/menu1",
 | 
			
		||||
			"meta": {
 | 
			
		||||
				"title": "message.router.menu",
 | 
			
		||||
				"isLink": "",
 | 
			
		||||
				"isHide": false,
 | 
			
		||||
				"isKeepAlive": true,
 | 
			
		||||
				"isAffix": false,
 | 
			
		||||
				"isIframe": false,
 | 
			
		||||
				"roles": ["admin"],
 | 
			
		||||
				"icon": "iconfont icon-caidan"
 | 
			
		||||
			},
 | 
			
		||||
			"children": [
 | 
			
		||||
				{
 | 
			
		||||
					"path": "/menu/menu1",
 | 
			
		||||
					"name": "menu1",
 | 
			
		||||
					"component": "layout/routerView/parent",
 | 
			
		||||
					"redirect": "/menu/menu1/menu11",
 | 
			
		||||
					"meta": {
 | 
			
		||||
						"title": "message.router.menu1",
 | 
			
		||||
						"isLink": "",
 | 
			
		||||
						"isHide": false,
 | 
			
		||||
						"isKeepAlive": true,
 | 
			
		||||
						"isAffix": false,
 | 
			
		||||
						"isIframe": false,
 | 
			
		||||
						"roles": ["admin", "common"],
 | 
			
		||||
						"icon": "iconfont icon-caidan"
 | 
			
		||||
					},
 | 
			
		||||
					"children": [
 | 
			
		||||
						{
 | 
			
		||||
							"path": "/menu/menu1/menu11",
 | 
			
		||||
							"name": "menu11",
 | 
			
		||||
							"component": "menu/menu1/menu11/index",
 | 
			
		||||
							"meta": {
 | 
			
		||||
								"title": "message.router.menu11",
 | 
			
		||||
								"isLink": "",
 | 
			
		||||
								"isHide": false,
 | 
			
		||||
								"isKeepAlive": true,
 | 
			
		||||
								"isAffix": false,
 | 
			
		||||
								"isIframe": false,
 | 
			
		||||
								"roles": ["admin", "common"],
 | 
			
		||||
								"icon": "iconfont icon-caidan"
 | 
			
		||||
							}
 | 
			
		||||
						},
 | 
			
		||||
						{
 | 
			
		||||
							"path": "/menu/menu1/menu12",
 | 
			
		||||
							"name": "menu12",
 | 
			
		||||
							"component": "layout/routerView/parent",
 | 
			
		||||
							"redirect": "/menu/menu1/menu12/menu121",
 | 
			
		||||
							"meta": {
 | 
			
		||||
								"title": "message.router.menu12",
 | 
			
		||||
								"isLink": "",
 | 
			
		||||
								"isHide": false,
 | 
			
		||||
								"isKeepAlive": true,
 | 
			
		||||
								"isAffix": false,
 | 
			
		||||
								"isIframe": false,
 | 
			
		||||
								"roles": ["admin", "common"],
 | 
			
		||||
								"icon": "iconfont icon-caidan"
 | 
			
		||||
							},
 | 
			
		||||
							"children": [
 | 
			
		||||
								{
 | 
			
		||||
									"path": "/menu/menu1/menu12/menu121",
 | 
			
		||||
									"name": "menu121",
 | 
			
		||||
									"component": "menu/menu1/menu12/menu121/index",
 | 
			
		||||
									"meta": {
 | 
			
		||||
										"title": "message.router.menu121",
 | 
			
		||||
										"isLink": "",
 | 
			
		||||
										"isHide": false,
 | 
			
		||||
										"isKeepAlive": true,
 | 
			
		||||
										"isAffix": false,
 | 
			
		||||
										"isIframe": false,
 | 
			
		||||
										"roles": ["admin", "common"],
 | 
			
		||||
										"icon": "iconfont icon-caidan"
 | 
			
		||||
									}
 | 
			
		||||
								},
 | 
			
		||||
								{
 | 
			
		||||
									"path": "/menu/menu1/menu12/menu122",
 | 
			
		||||
									"name": "menu122",
 | 
			
		||||
									"component": "menu/menu1/menu12/menu122/index",
 | 
			
		||||
									"meta": {
 | 
			
		||||
										"title": "message.router.menu122",
 | 
			
		||||
										"isLink": "",
 | 
			
		||||
										"isHide": false,
 | 
			
		||||
										"isKeepAlive": true,
 | 
			
		||||
										"isAffix": false,
 | 
			
		||||
										"isIframe": false,
 | 
			
		||||
										"roles": ["admin", "common"],
 | 
			
		||||
										"icon": "iconfont icon-caidan"
 | 
			
		||||
									}
 | 
			
		||||
								}
 | 
			
		||||
							]
 | 
			
		||||
						},
 | 
			
		||||
						{
 | 
			
		||||
							"path": "/menu/menu1/menu13",
 | 
			
		||||
							"name": "menu13",
 | 
			
		||||
							"component": "menu/menu1/menu13/index",
 | 
			
		||||
							"meta": {
 | 
			
		||||
								"title": "message.router.menu13",
 | 
			
		||||
								"isLink": "",
 | 
			
		||||
								"isHide": false,
 | 
			
		||||
								"isKeepAlive": true,
 | 
			
		||||
								"isAffix": false,
 | 
			
		||||
								"isIframe": false,
 | 
			
		||||
								"roles": ["admin", "common"],
 | 
			
		||||
								"icon": "iconfont icon-caidan"
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					]
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					"path": "/menu/menu2",
 | 
			
		||||
					"name": "menu2",
 | 
			
		||||
					"component": "menu/menu2/index",
 | 
			
		||||
					"meta": {
 | 
			
		||||
						"title": "message.router.menu2",
 | 
			
		||||
						"isLink": "",
 | 
			
		||||
						"isHide": false,
 | 
			
		||||
						"isKeepAlive": true,
 | 
			
		||||
						"isAffix": false,
 | 
			
		||||
						"isIframe": false,
 | 
			
		||||
						"roles": ["admin", "common"],
 | 
			
		||||
						"icon": "iconfont icon-caidan"
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			]
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"path": "/fun",
 | 
			
		||||
			"name": "funIndex",
 | 
			
		||||
			"component": "layout/routerView/parent",
 | 
			
		||||
			"redirect": "/fun/tagsView",
 | 
			
		||||
			"meta": {
 | 
			
		||||
				"title": "message.router.funIndex",
 | 
			
		||||
				"isLink": "",
 | 
			
		||||
				"isHide": false,
 | 
			
		||||
				"isKeepAlive": true,
 | 
			
		||||
				"isAffix": false,
 | 
			
		||||
				"isIframe": false,
 | 
			
		||||
				"roles": ["admin", "common"],
 | 
			
		||||
				"icon": "iconfont icon-crew_feature"
 | 
			
		||||
			},
 | 
			
		||||
			"children": [
 | 
			
		||||
				{
 | 
			
		||||
					"path": "/fun/tagsView",
 | 
			
		||||
					"name": "funTagsView",
 | 
			
		||||
					"component": "fun/tagsView/index",
 | 
			
		||||
					"meta": {
 | 
			
		||||
						"title": "message.router.funTagsView",
 | 
			
		||||
						"isLink": "",
 | 
			
		||||
						"isHide": false,
 | 
			
		||||
						"isKeepAlive": true,
 | 
			
		||||
						"isAffix": false,
 | 
			
		||||
						"isIframe": false,
 | 
			
		||||
						"roles": ["admin", "common"],
 | 
			
		||||
						"icon": "el-icon-thumb"
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			]
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"path": "/link",
 | 
			
		||||
			"name": "layoutLinkView",
 | 
			
		||||
			"component": "layout/routerView/parent",
 | 
			
		||||
			"meta": {
 | 
			
		||||
				"title": "message.router.layoutLinkView",
 | 
			
		||||
				"isLink": "https://element-plus.gitee.io/#/zh-CN/component/installation",
 | 
			
		||||
				"isHide": false,
 | 
			
		||||
				"isKeepAlive": false,
 | 
			
		||||
				"isAffix": false,
 | 
			
		||||
				"isIframe": false,
 | 
			
		||||
				"roles": ["admin"],
 | 
			
		||||
				"icon": "iconfont icon-caozuo-wailian"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"path": "/iframes",
 | 
			
		||||
			"name": "layoutIfameView",
 | 
			
		||||
			"component": "layout/routerView/parent",
 | 
			
		||||
			"meta": {
 | 
			
		||||
				"title": "message.router.layoutIfameView",
 | 
			
		||||
				"isLink": "https://gitee.com/lyt-top/vue-next-admin",
 | 
			
		||||
				"isHide": false,
 | 
			
		||||
				"isKeepAlive": false,
 | 
			
		||||
				"isAffix": true,
 | 
			
		||||
				"isIframe": true,
 | 
			
		||||
				"roles": ["admin"],
 | 
			
		||||
				"icon": "iconfont icon-neiqianshujuchucun"
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										76
									
								
								src/App.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								src/App.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,76 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div id="app">
 | 
			
		||||
		<router-view />
 | 
			
		||||
		<Setings ref="setingsRef" />
 | 
			
		||||
		<Upgrade v-if="getVersion" />
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import config from '/package.json';
 | 
			
		||||
import setIntroduction from '@/utils/setIconfont.js';
 | 
			
		||||
import { Local } from '@/utils/storage.js';
 | 
			
		||||
import Setings from '@/layout/navBars/breadcrumb/setings.vue';
 | 
			
		||||
import Upgrade from '@/layout/upgrade/index.vue';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'App',
 | 
			
		||||
	components: { Setings, Upgrade },
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.initSetIconfont();
 | 
			
		||||
		this.openSetingsDrawer();
 | 
			
		||||
		this.getLayoutThemeConfig();
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		// 获取版本号
 | 
			
		||||
		getVersion() {
 | 
			
		||||
			let isVersion = false;
 | 
			
		||||
			if (this.$route.path !== '/login') {
 | 
			
		||||
				if ((Local.get('version') && Local.get('version') !== config.version) || !Local.get('version')) isVersion = true;
 | 
			
		||||
			}
 | 
			
		||||
			return isVersion;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 设置初始化,防止刷新时恢复默认
 | 
			
		||||
		initSetIconfont() {
 | 
			
		||||
			// 设置批量第三方 icon 图标
 | 
			
		||||
			setIntroduction.cssCdn();
 | 
			
		||||
			// 设置批量第三方 js
 | 
			
		||||
			setIntroduction.jsCdn();
 | 
			
		||||
		},
 | 
			
		||||
		// 布局配置弹窗打开
 | 
			
		||||
		openSetingsDrawer() {
 | 
			
		||||
			this.bus.$on('openSetingsDrawer', () => {
 | 
			
		||||
				this.$refs.setingsRef.openDrawer();
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		// 获取缓存中的布局配置
 | 
			
		||||
		getLayoutThemeConfig() {
 | 
			
		||||
			if (Local.get('themeConfigPrev')) {
 | 
			
		||||
				this.$store.dispatch('themeConfig/setThemeConfig', Local.get('themeConfigPrev'));
 | 
			
		||||
				document.documentElement.style.cssText = Local.get('themeConfigStyle');
 | 
			
		||||
			} else {
 | 
			
		||||
				Local.set('themeConfigPrev', this.$store.state.themeConfig.themeConfig);
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	watch: {
 | 
			
		||||
		// 监听路由的变化
 | 
			
		||||
		$route: {
 | 
			
		||||
			handler(to) {
 | 
			
		||||
				this.$nextTick(() => {
 | 
			
		||||
					let webTitle = '';
 | 
			
		||||
					let { globalTitle } = this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
					to.path === '/login' ? (webTitle = to.meta.title) : (webTitle = this.$t(to.meta.title));
 | 
			
		||||
					document.title = `${webTitle} - ${globalTitle}` || globalTitle;
 | 
			
		||||
				});
 | 
			
		||||
			},
 | 
			
		||||
			deep: true,
 | 
			
		||||
			immediate: true,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	destroyed() {
 | 
			
		||||
		this.bus.$off('openSetingsDrawer');
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										25
									
								
								src/api/login/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/api/login/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
import request from '@/utils/request';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 登录api接口集合
 | 
			
		||||
 * @method signIn 用户登录
 | 
			
		||||
 * @method signOut 用户退出登录
 | 
			
		||||
 */
 | 
			
		||||
export function useLoginApi() {
 | 
			
		||||
	return {
 | 
			
		||||
		signIn: (params) => {
 | 
			
		||||
			return request({
 | 
			
		||||
				url: '/user/signIn',
 | 
			
		||||
				method: 'post',
 | 
			
		||||
				data: params,
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		signOut: (params) => {
 | 
			
		||||
			return request({
 | 
			
		||||
				url: '/user/signOut',
 | 
			
		||||
				method: 'post',
 | 
			
		||||
				data: params,
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								src/api/menu/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/api/menu/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
import request from '@/utils/request';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * webpack 的代理只是本地开发生效,打包后需要在部署环境 搭建 nginx 代理
 | 
			
		||||
 * 所以:
 | 
			
		||||
 * 开发环境,请求跨越的接口。为了配置跨越示例
 | 
			
		||||
 * 线上环境,请求目录下的 `json` 数据
 | 
			
		||||
 * 一般后端接口都会处理跨越问题,可根据具体情况进行修改
 | 
			
		||||
 * json 格式地址:https://gitee.com/lyt-top/vue-next-admin-images/tree/master/vue2
 | 
			
		||||
 * 本地菜单地址:public/xxx.json
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 后端控制菜单模拟json,路径在 https://gitee.com/lyt-top/vue-next-admin-images/tree/master/menu
 | 
			
		||||
 * 后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
 | 
			
		||||
 * @method getMenuAdmin 获取后端动态路由菜单(admin)
 | 
			
		||||
 * @method getMenuTest 获取后端动态路由菜单(test)
 | 
			
		||||
 */
 | 
			
		||||
export function useMenuApi() {
 | 
			
		||||
	return {
 | 
			
		||||
		getMenuAdmin: (params) => {
 | 
			
		||||
			// 本地数据,路径:`/public/xxx.json`
 | 
			
		||||
			return request({
 | 
			
		||||
				url: './admin.json',
 | 
			
		||||
				method: 'get',
 | 
			
		||||
				params,
 | 
			
		||||
			});
 | 
			
		||||
			// 模拟跨域
 | 
			
		||||
			// return request({
 | 
			
		||||
			// 	url: '/gitee/lyt-top/vue-next-admin-images/raw/master/vue2/admin.json',
 | 
			
		||||
			// 	method: 'get',
 | 
			
		||||
			// });
 | 
			
		||||
		},
 | 
			
		||||
		getMenuTest: (params) => {
 | 
			
		||||
			// 本地数据,路径:`/public/xxx.json`
 | 
			
		||||
			return request({
 | 
			
		||||
				url: './test.json',
 | 
			
		||||
				method: 'get',
 | 
			
		||||
				params,
 | 
			
		||||
			});
 | 
			
		||||
			// 模拟跨域
 | 
			
		||||
			// return request({
 | 
			
		||||
			// 	url: '/gitee/lyt-top/vue-next-admin-images/raw/master/vue2/test.json',
 | 
			
		||||
			// 	method: 'get',
 | 
			
		||||
			// });
 | 
			
		||||
		},
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										60
									
								
								src/i18n/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								src/i18n/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import VueI18n from 'vue-i18n';
 | 
			
		||||
import zhcnLocale from 'element-ui/lib/locale/lang/zh-CN';
 | 
			
		||||
import enLocale from 'element-ui/lib/locale/lang/en';
 | 
			
		||||
import zhtwLocale from 'element-ui/lib/locale/lang/zh-TW';
 | 
			
		||||
import store from '@/store/index.js';
 | 
			
		||||
 | 
			
		||||
import nextZhcn from '@/i18n/lang/zh-cn.js';
 | 
			
		||||
import nextEn from '@/i18n/lang/en.js';
 | 
			
		||||
import nextZhtw from '@/i18n/lang/zh-tw.js';
 | 
			
		||||
 | 
			
		||||
import pagesHomeZhcn from '@/i18n/pages/home/zh-cn.js';
 | 
			
		||||
import pagesHomeEn from '@/i18n/pages/home/en.js';
 | 
			
		||||
import pagesHomeZhtw from '@/i18n/pages/home/zh-tw.js';
 | 
			
		||||
import pagesLoginZhcn from '@/i18n/pages/login/zh-cn.js';
 | 
			
		||||
import pagesLoginEn from '@/i18n/pages/login/en.js';
 | 
			
		||||
import pagesLoginZhtw from '@/i18n/pages/login/zh-tw.js';
 | 
			
		||||
 | 
			
		||||
// 使用插件
 | 
			
		||||
Vue.use(VueI18n);
 | 
			
		||||
 | 
			
		||||
// 定义语言国际化内容
 | 
			
		||||
/**
 | 
			
		||||
 * 说明:
 | 
			
		||||
 * /src/i18n/lang 下的 js 为框架的国际化内容
 | 
			
		||||
 * /src/i18n/pages 下的 js 为各界面的国际化内容
 | 
			
		||||
 */
 | 
			
		||||
const messages = {
 | 
			
		||||
	'zh-cn': {
 | 
			
		||||
		...zhcnLocale,
 | 
			
		||||
		message: {
 | 
			
		||||
			...nextZhcn,
 | 
			
		||||
			...pagesHomeZhcn,
 | 
			
		||||
			...pagesLoginZhcn,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	en: {
 | 
			
		||||
		...enLocale,
 | 
			
		||||
		message: {
 | 
			
		||||
			...nextEn,
 | 
			
		||||
			...pagesHomeEn,
 | 
			
		||||
			...pagesLoginEn,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	'zh-tw': {
 | 
			
		||||
		...zhtwLocale,
 | 
			
		||||
		message: {
 | 
			
		||||
			...nextZhtw,
 | 
			
		||||
			...pagesHomeZhtw,
 | 
			
		||||
			...pagesLoginZhtw,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 导出语言国际化
 | 
			
		||||
export const i18n = new VueI18n({
 | 
			
		||||
	locale: store.state.themeConfig.themeConfig.globalI18n,
 | 
			
		||||
	fallbackLocale: 'zh-cn',
 | 
			
		||||
	messages,
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										164
									
								
								src/i18n/lang/en.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								src/i18n/lang/en.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,164 @@
 | 
			
		||||
// 定义内容
 | 
			
		||||
export default {
 | 
			
		||||
	router: {
 | 
			
		||||
		home: 'home',
 | 
			
		||||
		system: 'system',
 | 
			
		||||
		systemMenu: 'systemMenu',
 | 
			
		||||
		systemUser: 'systemUser',
 | 
			
		||||
		limits: 'limits',
 | 
			
		||||
		limitsFrontEnd: 'FrontEnd',
 | 
			
		||||
		limitsFrontEndPage: 'FrontEndPage',
 | 
			
		||||
		limitsFrontEndBtn: 'FrontEndBtn',
 | 
			
		||||
		limitsBackEnd: 'BackEnd',
 | 
			
		||||
		limitsBackEndEndPage: 'BackEndEndPage',
 | 
			
		||||
		menu: 'menu',
 | 
			
		||||
		menu1: 'menu1',
 | 
			
		||||
		menu11: 'menu11',
 | 
			
		||||
		menu12: 'menu12',
 | 
			
		||||
		menu121: 'menu121',
 | 
			
		||||
		menu122: 'menu122',
 | 
			
		||||
		menu13: 'menu13',
 | 
			
		||||
		menu2: 'menu2',
 | 
			
		||||
		funIndex: 'function',
 | 
			
		||||
		funTagsView: 'funTagsView',
 | 
			
		||||
		funSignCanvas: 'Online signature',
 | 
			
		||||
		funCountup: 'countup',
 | 
			
		||||
		funEchartsTree: 'echartsTree',
 | 
			
		||||
		funSelector: 'funSelector',
 | 
			
		||||
		funWangEditor: 'wangEditor',
 | 
			
		||||
		funCropper: 'cropper',
 | 
			
		||||
		funMindMap: 'G6 MindMap',
 | 
			
		||||
		funQrcode: 'qrcode',
 | 
			
		||||
		funEchartsMap: 'EchartsMap',
 | 
			
		||||
		funPrintJs: 'PrintJs',
 | 
			
		||||
		funClipboard: 'Copy cut',
 | 
			
		||||
		funScreenShort: 'screenCapture',
 | 
			
		||||
		pagesIndex: 'pages',
 | 
			
		||||
		pagesFiltering: 'Filtering',
 | 
			
		||||
		pagesFilteringDetails: 'FilteringDetails',
 | 
			
		||||
		pagesFilteringDetails1: 'FilteringDetails1',
 | 
			
		||||
		pagesIocnfont: 'iconfont icon',
 | 
			
		||||
		pagesElement: 'element icon',
 | 
			
		||||
		pagesAwesome: 'awesome icon',
 | 
			
		||||
		pagesCityLinkage: 'CityLinkage',
 | 
			
		||||
		pagesFormAdapt: 'FormAdapt',
 | 
			
		||||
		pagesListAdapt: 'ListAdapt',
 | 
			
		||||
		pagesWaterfall: 'Waterfall',
 | 
			
		||||
		pagesSteps: 'Steps',
 | 
			
		||||
		chartIndex: 'chartIndex',
 | 
			
		||||
		personal: 'personal',
 | 
			
		||||
		tools: 'tools',
 | 
			
		||||
		layoutLinkView: 'LinkView',
 | 
			
		||||
		layoutIfameView: 'IfameView',
 | 
			
		||||
	},
 | 
			
		||||
	staticRoutes: {
 | 
			
		||||
		signIn: 'signIn',
 | 
			
		||||
		notFound: 'notFound',
 | 
			
		||||
		noPower: 'noPower',
 | 
			
		||||
	},
 | 
			
		||||
	user: {
 | 
			
		||||
		title0: 'Component size',
 | 
			
		||||
		title1: 'Language switching',
 | 
			
		||||
		title2: 'Menu search',
 | 
			
		||||
		title3: 'Layout configuration',
 | 
			
		||||
		title4: 'news',
 | 
			
		||||
		title5: 'Full screen on',
 | 
			
		||||
		title6: 'Full screen off',
 | 
			
		||||
		dropdownDefault: 'default',
 | 
			
		||||
		dropdownMedium: 'medium',
 | 
			
		||||
		dropdownSmall: 'small',
 | 
			
		||||
		dropdownMini: 'mini',
 | 
			
		||||
		dropdown1: 'home page',
 | 
			
		||||
		dropdown2: 'Personal Center',
 | 
			
		||||
		dropdown3: '404',
 | 
			
		||||
		dropdown4: '401',
 | 
			
		||||
		dropdown5: 'Log out',
 | 
			
		||||
		dropdown6: 'Code warehouse',
 | 
			
		||||
		searchPlaceholder: 'Menu search: support Chinese, routing path',
 | 
			
		||||
		newTitle: 'notice',
 | 
			
		||||
		newBtn: 'All read',
 | 
			
		||||
		newGo: 'Go to the notification center',
 | 
			
		||||
		newDesc: 'No notice',
 | 
			
		||||
		logOutTitle: 'Tips',
 | 
			
		||||
		logOutMessage: 'This operation will log out. Do you want to continue?',
 | 
			
		||||
		logOutConfirm: 'determine',
 | 
			
		||||
		logOutCancel: 'cancel',
 | 
			
		||||
		logOutExit: 'Exiting',
 | 
			
		||||
		logOutSuccess: 'Exit successfully!',
 | 
			
		||||
	},
 | 
			
		||||
	tagsView: {
 | 
			
		||||
		refresh: 'refresh',
 | 
			
		||||
		close: 'close',
 | 
			
		||||
		closeOther: 'closeOther',
 | 
			
		||||
		closeAll: 'closeAll',
 | 
			
		||||
		fullscreen: 'fullscreen',
 | 
			
		||||
	},
 | 
			
		||||
	notFound: {
 | 
			
		||||
		foundTitle: 'Wrong address input, please re-enter the address~',
 | 
			
		||||
		foundMsg: 'You can check the web address first, and then re-enter or give us feedback.',
 | 
			
		||||
		foundBtn: 'Back to home page',
 | 
			
		||||
	},
 | 
			
		||||
	noAccess: {
 | 
			
		||||
		accessTitle: 'You are not authorized to operate~',
 | 
			
		||||
		accessMsg: 'Contact information: add QQ group discussion 665452019',
 | 
			
		||||
		accessBtn: 'Reauthorization',
 | 
			
		||||
	},
 | 
			
		||||
	layout: {
 | 
			
		||||
		configTitle: 'Layout configuration',
 | 
			
		||||
		oneTitle: 'Global Themes',
 | 
			
		||||
		twoTitle: 'Menu / top bar',
 | 
			
		||||
		twoTopBar: 'Top bar background',
 | 
			
		||||
		twoMenuBar: 'Menu background',
 | 
			
		||||
		twoColumnsMenuBar: 'Column menu background',
 | 
			
		||||
		twoTopBarColor: 'Top bar default font color',
 | 
			
		||||
		twoMenuBarColor: 'Menu default font color',
 | 
			
		||||
		twoColumnsMenuBarColor: 'Default font color bar menu',
 | 
			
		||||
		twoIsTopBarColorGradual: 'Top bar gradient',
 | 
			
		||||
		twoIsMenuBarColorGradual: 'Menu gradient',
 | 
			
		||||
		twoIsMenuBarColorHighlight: 'Menu font highlight',
 | 
			
		||||
		threeTitle: 'Interface settings',
 | 
			
		||||
		threeIsCollapse: 'Menu horizontal collapse',
 | 
			
		||||
		threeIsUniqueOpened: 'Menu accordion',
 | 
			
		||||
		threeIsFixedHeader: 'Fixed header',
 | 
			
		||||
		threeIsClassicSplitMenu: 'Classic layout split menu',
 | 
			
		||||
		threeIsLockScreen: 'Open the lock screen',
 | 
			
		||||
		threeLockScreenTime: 'screen locking(s/s)',
 | 
			
		||||
		fourTitle: 'Interface display',
 | 
			
		||||
		fourIsShowLogo: 'Sidebar logo',
 | 
			
		||||
		fourIsBreadcrumb: 'Open breadcrumb',
 | 
			
		||||
		fourIsBreadcrumbIcon: 'Open breadcrumb icon',
 | 
			
		||||
		fourIsTagsview: 'Open tagsview',
 | 
			
		||||
		fourIsTagsviewIcon: 'Open tagsview Icon',
 | 
			
		||||
		fourIsCacheTagsView: 'Enable tagsview cache',
 | 
			
		||||
		fourIsSortableTagsView: 'Enable tagsview drag',
 | 
			
		||||
		fourIsFooter: 'Open footer',
 | 
			
		||||
		fourIsGrayscale: 'Grey model',
 | 
			
		||||
		fourIsInvert: 'Color weak mode',
 | 
			
		||||
		fourIsDark: 'Dark Mode',
 | 
			
		||||
		fourIsWartermark: 'Turn on watermark',
 | 
			
		||||
		fourWartermarkText: 'Watermark copy',
 | 
			
		||||
		fiveTitle: 'Other settings',
 | 
			
		||||
		fiveTagsStyle: 'Tagsview style',
 | 
			
		||||
		fiveAnimation: 'page animation',
 | 
			
		||||
		fiveColumnsAsideStyle: 'Column style',
 | 
			
		||||
		fiveColumnsAsideLayout: 'Column layout',
 | 
			
		||||
		sixTitle: 'Layout switch',
 | 
			
		||||
		sixDefaults: 'One',
 | 
			
		||||
		sixClassic: 'Two',
 | 
			
		||||
		sixTransverse: 'Three',
 | 
			
		||||
		sixColumns: 'Four',
 | 
			
		||||
		tipText: 'Click the button below to copy the layout configuration to `/src/store/modules/themeConfig.js` It has been modified in.',
 | 
			
		||||
		copyText: 'replication configuration',
 | 
			
		||||
		resetText: 'restore default',
 | 
			
		||||
		copyTextSuccess: 'Copy succeeded!',
 | 
			
		||||
		copyTextError: 'Copy failed!',
 | 
			
		||||
	},
 | 
			
		||||
	upgrade: {
 | 
			
		||||
		title: 'New version',
 | 
			
		||||
		msg: 'The new version is available, please update it now! Dont worry, the update is fast!',
 | 
			
		||||
		desc: 'Prompt: Update will restore the default configuration',
 | 
			
		||||
		btnOne: 'Cruel refusal',
 | 
			
		||||
		btnTwo: 'Update now',
 | 
			
		||||
		btnTwoLoading: 'Updating',
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										164
									
								
								src/i18n/lang/zh-cn.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								src/i18n/lang/zh-cn.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,164 @@
 | 
			
		||||
// 定义内容
 | 
			
		||||
export default {
 | 
			
		||||
	router: {
 | 
			
		||||
		home: '首页',
 | 
			
		||||
		system: '系统设置',
 | 
			
		||||
		systemMenu: '菜单管理',
 | 
			
		||||
		systemUser: '用户管理',
 | 
			
		||||
		limits: '权限管理',
 | 
			
		||||
		limitsFrontEnd: '前端控制',
 | 
			
		||||
		limitsFrontEndPage: '页面权限',
 | 
			
		||||
		limitsFrontEndBtn: '按钮权限',
 | 
			
		||||
		limitsBackEnd: '后端控制',
 | 
			
		||||
		limitsBackEndEndPage: '页面权限',
 | 
			
		||||
		menu: '菜单嵌套',
 | 
			
		||||
		menu1: '菜单1',
 | 
			
		||||
		menu11: '菜单11',
 | 
			
		||||
		menu12: '菜单12',
 | 
			
		||||
		menu121: '菜单121',
 | 
			
		||||
		menu122: '菜单122',
 | 
			
		||||
		menu13: '菜单13',
 | 
			
		||||
		menu2: '菜单2',
 | 
			
		||||
		funIndex: '功能',
 | 
			
		||||
		funTagsView: 'tagsView 操作',
 | 
			
		||||
		funSignCanvas: '在线签名',
 | 
			
		||||
		funCountup: 'countup 数字滚动',
 | 
			
		||||
		funEchartsTree: 'echartsTree 树图',
 | 
			
		||||
		funSelector: '图标选择器',
 | 
			
		||||
		funWangEditor: 'wangEditor 编辑器',
 | 
			
		||||
		funCropper: 'cropper 图片裁剪',
 | 
			
		||||
		funMindMap: 'G6 思维导图',
 | 
			
		||||
		funQrcode: 'qrcode 二维码生成',
 | 
			
		||||
		funEchartsMap: '地理坐标/地图',
 | 
			
		||||
		funPrintJs: '页面打印',
 | 
			
		||||
		funClipboard: '复制剪切',
 | 
			
		||||
		funScreenShort: 'web端自定义截屏',
 | 
			
		||||
		pagesIndex: '页面',
 | 
			
		||||
		pagesFiltering: '过滤筛选组件',
 | 
			
		||||
		pagesFilteringDetails: '过滤筛选组件详情',
 | 
			
		||||
		pagesFilteringDetails1: '过滤筛选组件详情111',
 | 
			
		||||
		pagesIocnfont: 'iconfont 字体图标',
 | 
			
		||||
		pagesElement: 'element 字体图标',
 | 
			
		||||
		pagesAwesome: 'awesome 字体图标',
 | 
			
		||||
		pagesCityLinkage: '城市多级联动',
 | 
			
		||||
		pagesFormAdapt: '表单自适应',
 | 
			
		||||
		pagesListAdapt: '列表自适应',
 | 
			
		||||
		pagesWaterfall: '瀑布屏',
 | 
			
		||||
		pagesSteps: '步骤条',
 | 
			
		||||
		chartIndex: '大数据图表',
 | 
			
		||||
		personal: '个人中心',
 | 
			
		||||
		tools: '工具类集合',
 | 
			
		||||
		layoutLinkView: '外链',
 | 
			
		||||
		layoutIfameView: '内嵌 iframe',
 | 
			
		||||
	},
 | 
			
		||||
	staticRoutes: {
 | 
			
		||||
		signIn: '登录',
 | 
			
		||||
		notFound: '找不到此页面',
 | 
			
		||||
		noPower: '没有权限',
 | 
			
		||||
	},
 | 
			
		||||
	user: {
 | 
			
		||||
		title0: '组件大小',
 | 
			
		||||
		title1: '语言切换',
 | 
			
		||||
		title2: '菜单搜索',
 | 
			
		||||
		title3: '布局配置',
 | 
			
		||||
		title4: '消息',
 | 
			
		||||
		title5: '开全屏',
 | 
			
		||||
		title6: '关全屏',
 | 
			
		||||
		dropdownDefault: '默认',
 | 
			
		||||
		dropdownMedium: '中等',
 | 
			
		||||
		dropdownSmall: '小型',
 | 
			
		||||
		dropdownMini: '超小',
 | 
			
		||||
		dropdown1: '首页',
 | 
			
		||||
		dropdown2: '个人中心',
 | 
			
		||||
		dropdown3: '404',
 | 
			
		||||
		dropdown4: '401',
 | 
			
		||||
		dropdown5: '退出登录',
 | 
			
		||||
		dropdown6: '代码仓库',
 | 
			
		||||
		searchPlaceholder: '菜单搜索:支持中文、路由路径',
 | 
			
		||||
		newTitle: '通知',
 | 
			
		||||
		newBtn: '全部已读',
 | 
			
		||||
		newGo: '前往通知中心',
 | 
			
		||||
		newDesc: '暂无通知',
 | 
			
		||||
		logOutTitle: '提示',
 | 
			
		||||
		logOutMessage: '此操作将退出登录, 是否继续?',
 | 
			
		||||
		logOutConfirm: '确定',
 | 
			
		||||
		logOutCancel: '取消',
 | 
			
		||||
		logOutExit: '退出中',
 | 
			
		||||
		logOutSuccess: '安全退出成功!',
 | 
			
		||||
	},
 | 
			
		||||
	tagsView: {
 | 
			
		||||
		refresh: '刷新',
 | 
			
		||||
		close: '关闭',
 | 
			
		||||
		closeOther: '关闭其它',
 | 
			
		||||
		closeAll: '全部关闭',
 | 
			
		||||
		fullscreen: '当前页全屏',
 | 
			
		||||
	},
 | 
			
		||||
	notFound: {
 | 
			
		||||
		foundTitle: '地址输入错误,请重新输入地址~',
 | 
			
		||||
		foundMsg: '您可以先检查网址,然后重新输入或给我们反馈问题。',
 | 
			
		||||
		foundBtn: '返回首页',
 | 
			
		||||
	},
 | 
			
		||||
	noAccess: {
 | 
			
		||||
		accessTitle: '您未被授权,没有操作权限~',
 | 
			
		||||
		accessMsg: '联系方式:加QQ群探讨 665452019',
 | 
			
		||||
		accessBtn: '重新授权',
 | 
			
		||||
	},
 | 
			
		||||
	layout: {
 | 
			
		||||
		configTitle: '布局配置',
 | 
			
		||||
		oneTitle: '全局主题',
 | 
			
		||||
		twoTitle: '菜单 / 顶栏',
 | 
			
		||||
		twoTopBar: '顶栏背景',
 | 
			
		||||
		twoMenuBar: '菜单背景',
 | 
			
		||||
		twoColumnsMenuBar: '分栏菜单背景',
 | 
			
		||||
		twoTopBarColor: '顶栏默认字体颜色',
 | 
			
		||||
		twoMenuBarColor: '菜单默认字体颜色',
 | 
			
		||||
		twoColumnsMenuBarColor: '分栏菜单默认字体颜色',
 | 
			
		||||
		twoIsTopBarColorGradual: '顶栏背景渐变',
 | 
			
		||||
		twoIsMenuBarColorGradual: '菜单背景渐变',
 | 
			
		||||
		twoIsMenuBarColorHighlight: '菜单字体背景高亮',
 | 
			
		||||
		threeTitle: '界面设置',
 | 
			
		||||
		threeIsCollapse: '菜单水平折叠',
 | 
			
		||||
		threeIsUniqueOpened: '菜单手风琴',
 | 
			
		||||
		threeIsFixedHeader: '固定 Header',
 | 
			
		||||
		threeIsClassicSplitMenu: '经典布局分割菜单',
 | 
			
		||||
		threeIsLockScreen: '开启锁屏',
 | 
			
		||||
		threeLockScreenTime: '自动锁屏(s/秒)',
 | 
			
		||||
		fourTitle: '界面显示',
 | 
			
		||||
		fourIsShowLogo: '侧边栏 Logo',
 | 
			
		||||
		fourIsBreadcrumb: '开启 Breadcrumb',
 | 
			
		||||
		fourIsBreadcrumbIcon: '开启 Breadcrumb 图标',
 | 
			
		||||
		fourIsTagsview: '开启 Tagsview',
 | 
			
		||||
		fourIsTagsviewIcon: '开启 Tagsview 图标',
 | 
			
		||||
		fourIsCacheTagsView: '开启 TagsView 缓存',
 | 
			
		||||
		fourIsSortableTagsView: '开启 TagsView 拖拽',
 | 
			
		||||
		fourIsFooter: '开启 Footer',
 | 
			
		||||
		fourIsGrayscale: '灰色模式',
 | 
			
		||||
		fourIsInvert: '色弱模式',
 | 
			
		||||
		fourIsDark: '深色模式',
 | 
			
		||||
		fourIsWartermark: '开启水印',
 | 
			
		||||
		fourWartermarkText: '水印文案',
 | 
			
		||||
		fiveTitle: '其它设置',
 | 
			
		||||
		fiveTagsStyle: 'Tagsview 风格',
 | 
			
		||||
		fiveAnimation: '主页面切换动画',
 | 
			
		||||
		fiveColumnsAsideStyle: '分栏高亮风格',
 | 
			
		||||
		fiveColumnsAsideLayout: '分栏布局风格',
 | 
			
		||||
		sixTitle: '布局切换',
 | 
			
		||||
		sixDefaults: '默认',
 | 
			
		||||
		sixClassic: '经典',
 | 
			
		||||
		sixTransverse: '横向',
 | 
			
		||||
		sixColumns: '分栏',
 | 
			
		||||
		tipText: '点击下方按钮,复制布局配置去 `src/store/modules/themeConfig.js` 中修改。',
 | 
			
		||||
		copyText: '一键复制配置',
 | 
			
		||||
		resetText: '一键恢复默认',
 | 
			
		||||
		copyTextSuccess: '复制成功!',
 | 
			
		||||
		copyTextError: '复制失败!',
 | 
			
		||||
	},
 | 
			
		||||
	upgrade: {
 | 
			
		||||
		title: '新版本升级',
 | 
			
		||||
		msg: '新版本来啦,马上更新尝鲜吧!不用担心,更新很快的哦!',
 | 
			
		||||
		desc: '提示:更新会还原默认配置',
 | 
			
		||||
		btnOne: '残忍拒绝',
 | 
			
		||||
		btnTwo: '马上更新',
 | 
			
		||||
		btnTwoLoading: '更新中',
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										164
									
								
								src/i18n/lang/zh-tw.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								src/i18n/lang/zh-tw.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,164 @@
 | 
			
		||||
// 定义内容
 | 
			
		||||
export default {
 | 
			
		||||
	router: {
 | 
			
		||||
		home: '首頁',
 | 
			
		||||
		system: '系統設置',
 | 
			
		||||
		systemMenu: '選單管理',
 | 
			
		||||
		systemUser: '用戶管理',
 | 
			
		||||
		limits: '許可權管理',
 | 
			
		||||
		limitsFrontEnd: '前端控制',
 | 
			
		||||
		limitsFrontEndPage: '頁面許可權',
 | 
			
		||||
		limitsFrontEndBtn: '按鈕許可權',
 | 
			
		||||
		limitsBackEnd: '後端控制',
 | 
			
		||||
		limitsBackEndEndPage: '頁面許可權',
 | 
			
		||||
		menu: '選單嵌套',
 | 
			
		||||
		menu1: '選單1',
 | 
			
		||||
		menu11: '選單11',
 | 
			
		||||
		menu12: '選單12',
 | 
			
		||||
		menu121: '選單121',
 | 
			
		||||
		menu122: '選單122',
 | 
			
		||||
		menu13: '選單13',
 | 
			
		||||
		menu2: '選單2',
 | 
			
		||||
		funIndex: '功能',
 | 
			
		||||
		funTagsView: 'tagsView 操作',
 | 
			
		||||
		funSignCanvas: '線上簽名',
 | 
			
		||||
		funCountup: 'countup 數位滾動',
 | 
			
		||||
		funEchartsTree: 'echartsTree 樹圖',
 | 
			
		||||
		funSelector: '圖標選擇器',
 | 
			
		||||
		funWangEditor: 'wangEditor 編輯器',
 | 
			
		||||
		funCropper: 'cropper 圖片裁剪',
 | 
			
		||||
		funMindMap: 'G6 心智圖',
 | 
			
		||||
		funQrcode: 'qrcode 二維碼生成',
 | 
			
		||||
		funEchartsMap: '地理座標/地圖',
 | 
			
		||||
		funPrintJs: '頁面列印',
 | 
			
		||||
		funClipboard: '複製剪切',
 | 
			
		||||
		funScreenShort: '自定義截圖',
 | 
			
		||||
		pagesIndex: '頁面',
 | 
			
		||||
		pagesFiltering: '過濾篩選組件',
 | 
			
		||||
		pagesFilteringDetails: '過濾篩選組件詳情',
 | 
			
		||||
		pagesFilteringDetails1: '過濾篩選組件詳情111',
 | 
			
		||||
		pagesIocnfont: 'iconfont 字體圖標',
 | 
			
		||||
		pagesElement: 'element 字體圖標',
 | 
			
		||||
		pagesAwesome: 'awesome 字體圖標',
 | 
			
		||||
		pagesCityLinkage: '都市多級聯動',
 | 
			
		||||
		pagesFormAdapt: '表單自我調整',
 | 
			
		||||
		pagesListAdapt: '清單自我調整',
 | 
			
		||||
		pagesWaterfall: '瀑布屏',
 | 
			
		||||
		pagesSteps: '步驟條',
 | 
			
		||||
		chartIndex: '大資料圖表',
 | 
			
		||||
		personal: '個人中心',
 | 
			
		||||
		tools: '工具類集合',
 | 
			
		||||
		layoutLinkView: '外鏈',
 | 
			
		||||
		layoutIfameView: '内嵌 iframe',
 | 
			
		||||
	},
 | 
			
		||||
	staticRoutes: {
 | 
			
		||||
		signIn: '登入',
 | 
			
		||||
		notFound: '找不到此頁面',
 | 
			
		||||
		noPower: '沒有許可權',
 | 
			
		||||
	},
 | 
			
		||||
	user: {
 | 
			
		||||
		title0: '組件大小',
 | 
			
		||||
		title1: '語言切換',
 | 
			
		||||
		title2: '選單蒐索',
 | 
			
		||||
		title3: '佈局配寘',
 | 
			
		||||
		title4: '消息',
 | 
			
		||||
		title5: '開全屏',
 | 
			
		||||
		title6: '關全屏',
 | 
			
		||||
		dropdownDefault: '默認',
 | 
			
		||||
		dropdownMedium: '中等',
 | 
			
		||||
		dropdownSmall: '小型',
 | 
			
		||||
		dropdownMini: '超小',
 | 
			
		||||
		dropdown1: '首頁',
 | 
			
		||||
		dropdown2: '個人中心',
 | 
			
		||||
		dropdown3: '404',
 | 
			
		||||
		dropdown4: '401',
 | 
			
		||||
		dropdown5: '登出',
 | 
			
		||||
		dropdown6: '程式碼倉庫',
 | 
			
		||||
		searchPlaceholder: '選單蒐索:支援中文、路由路徑',
 | 
			
		||||
		newTitle: '通知',
 | 
			
		||||
		newBtn: '全部已讀',
 | 
			
		||||
		newGo: '前往通知中心',
 | 
			
		||||
		newDesc: '暫無通知',
 | 
			
		||||
		logOutTitle: '提示',
 | 
			
		||||
		logOutMessage: '此操作將登出,是否繼續?',
 | 
			
		||||
		logOutConfirm: '確定',
 | 
			
		||||
		logOutCancel: '取消',
 | 
			
		||||
		logOutExit: '退出中',
 | 
			
		||||
		logOutSuccess: '安全退出成功!',
 | 
			
		||||
	},
 | 
			
		||||
	tagsView: {
 | 
			
		||||
		refresh: '重繪',
 | 
			
		||||
		close: '關閉',
 | 
			
		||||
		closeOther: '關閉其它',
 | 
			
		||||
		closeAll: '全部關閉',
 | 
			
		||||
		fullscreen: '當前頁全屏',
 | 
			
		||||
	},
 | 
			
		||||
	notFound: {
 | 
			
		||||
		foundTitle: '地址輸入錯誤,請重新輸入地址~',
 | 
			
		||||
		foundMsg: '您可以先檢查網址,然後重新輸入或給我們迴響問題。',
 | 
			
		||||
		foundBtn: '返回首頁',
 | 
			
		||||
	},
 | 
			
		||||
	noAccess: {
 | 
			
		||||
		accessTitle: '您未被授權,沒有操作許可權~',
 | 
			
		||||
		accessMsg: '聯繫方式:加QQ群探討665452019',
 | 
			
		||||
		accessBtn: '重新授權',
 | 
			
		||||
	},
 | 
			
		||||
	layout: {
 | 
			
		||||
		configTitle: '佈局配寘',
 | 
			
		||||
		oneTitle: '全域主題',
 | 
			
		||||
		twoTitle: '選單 / 頂欄',
 | 
			
		||||
		twoTopBar: '頂欄背景',
 | 
			
		||||
		twoMenuBar: '選單背景',
 | 
			
		||||
		twoColumnsMenuBar: '分欄選單背景',
 | 
			
		||||
		twoTopBarColor: '頂欄默認字體顏色',
 | 
			
		||||
		twoMenuBarColor: '選單默認字體顏色',
 | 
			
		||||
		twoColumnsMenuBarColor: '分欄選單默認字體顏色',
 | 
			
		||||
		twoIsTopBarColorGradual: '頂欄背景漸變',
 | 
			
		||||
		twoIsMenuBarColorGradual: '選單背景漸變',
 | 
			
		||||
		twoIsMenuBarColorHighlight: '選單字體背景高亮',
 | 
			
		||||
		threeTitle: '介面設定',
 | 
			
		||||
		threeIsCollapse: '選單水准折疊',
 | 
			
		||||
		threeIsUniqueOpened: '選單手風琴',
 | 
			
		||||
		threeIsFixedHeader: '固定 Header',
 | 
			
		||||
		threeIsClassicSplitMenu: '經典佈局分割選單',
 | 
			
		||||
		threeIsLockScreen: '開啟鎖屏',
 | 
			
		||||
		threeLockScreenTime: '自動鎖屏(s/秒)',
 | 
			
		||||
		fourTitle: '介面顯示',
 | 
			
		||||
		fourIsShowLogo: '側邊欄 Logo',
 | 
			
		||||
		fourIsBreadcrumb: '開啟 Breadcrumb',
 | 
			
		||||
		fourIsBreadcrumbIcon: '開啟 Breadcrumb 圖標',
 | 
			
		||||
		fourIsTagsview: '開啟 Tagsview',
 | 
			
		||||
		fourIsTagsviewIcon: '開啟 Tagsview 圖標',
 | 
			
		||||
		fourIsCacheTagsView: '開啟 TagsView 緩存',
 | 
			
		||||
		fourIsSortableTagsView: '開啟 TagsView 拖拽',
 | 
			
		||||
		fourIsFooter: '開啟 Footer',
 | 
			
		||||
		fourIsGrayscale: '灰色模式',
 | 
			
		||||
		fourIsInvert: '色弱模式',
 | 
			
		||||
		fourIsDark: '深色模式',
 | 
			
		||||
		fourIsWartermark: '開啟浮水印',
 | 
			
		||||
		fourWartermarkText: '浮水印文案',
 | 
			
		||||
		fiveTitle: '其它設定',
 | 
			
		||||
		fiveTagsStyle: 'Tagsview 風格',
 | 
			
		||||
		fiveAnimation: '主頁面切換動畫',
 | 
			
		||||
		fiveColumnsAsideStyle: '分欄高亮風格',
 | 
			
		||||
		fiveColumnsAsideLayout: '分欄佈局風格',
 | 
			
		||||
		sixTitle: '佈局切換',
 | 
			
		||||
		sixDefaults: '默認',
 | 
			
		||||
		sixClassic: '經典',
 | 
			
		||||
		sixTransverse: '橫向',
 | 
			
		||||
		sixColumns: '分欄',
 | 
			
		||||
		tipText: '點擊下方按鈕,複製佈局配寘去`src/store/modules/themeConfig.js`中修改。',
 | 
			
		||||
		copyText: '一鍵複製配寘',
 | 
			
		||||
		resetText: '一鍵恢復默認',
 | 
			
		||||
		copyTextSuccess: '複製成功!',
 | 
			
		||||
		copyTextError: '複製失敗!',
 | 
			
		||||
	},
 | 
			
		||||
	upgrade: {
 | 
			
		||||
		title: '新版本陞級',
 | 
			
		||||
		msg: '新版本來啦,馬上更新嘗鮮吧! 不用擔心,更新很快的哦!',
 | 
			
		||||
		desc: '提示:更新會還原默認配寘',
 | 
			
		||||
		btnOne: '殘忍拒絕',
 | 
			
		||||
		btnTwo: '馬上更新',
 | 
			
		||||
		btnTwoLoading: '更新中',
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										14
									
								
								src/i18n/pages/home/en.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/i18n/pages/home/en.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
// 定义内容
 | 
			
		||||
export default {
 | 
			
		||||
	card: {
 | 
			
		||||
		title1: 'My desk',
 | 
			
		||||
		title2: 'Message notification',
 | 
			
		||||
		title3: 'more',
 | 
			
		||||
		title4: 'Marketing recommendation',
 | 
			
		||||
		title5: 'more',
 | 
			
		||||
		title6: 'Inventory operations',
 | 
			
		||||
		title7: 'Performance',
 | 
			
		||||
		title8: 'Out of stock monitoring',
 | 
			
		||||
		title9: 'Performance overtime warning',
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										14
									
								
								src/i18n/pages/home/zh-cn.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/i18n/pages/home/zh-cn.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
// 定义内容
 | 
			
		||||
export default {
 | 
			
		||||
	card: {
 | 
			
		||||
		title1: '我的工作台',
 | 
			
		||||
		title2: '消息通知',
 | 
			
		||||
		title3: '更多',
 | 
			
		||||
		title4: '营销推荐',
 | 
			
		||||
		title5: '更多',
 | 
			
		||||
		title6: '库存作业',
 | 
			
		||||
		title7: '履约情况',
 | 
			
		||||
		title8: '缺货监控',
 | 
			
		||||
		title9: '履约超时预警',
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										14
									
								
								src/i18n/pages/home/zh-tw.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/i18n/pages/home/zh-tw.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
// 定义内容
 | 
			
		||||
export default {
 | 
			
		||||
	card: {
 | 
			
		||||
		title1: '我的工作臺',
 | 
			
		||||
		title2: '消息通知',
 | 
			
		||||
		title3: '更多',
 | 
			
		||||
		title4: '行銷推薦',
 | 
			
		||||
		title5: '更多',
 | 
			
		||||
		title6: '庫存工作',
 | 
			
		||||
		title7: '履約情况',
 | 
			
		||||
		title8: '缺貨監控',
 | 
			
		||||
		title9: '履約超時預警',
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										18
									
								
								src/i18n/pages/login/en.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/i18n/pages/login/en.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
// 定义内容
 | 
			
		||||
export default {
 | 
			
		||||
	login: {
 | 
			
		||||
		placeholder1: 'The user name admin or not is test',
 | 
			
		||||
		placeholder2: 'Password: 123456',
 | 
			
		||||
		placeholder3: 'Please enter the verification code',
 | 
			
		||||
		btnText: 'Sign in',
 | 
			
		||||
		link: {
 | 
			
		||||
			one1: 'Third party login',
 | 
			
		||||
			one2: 'Links',
 | 
			
		||||
		},
 | 
			
		||||
		signInText: 'welcome back!',
 | 
			
		||||
		copyright: {
 | 
			
		||||
			one5: 'Copyright: Shenzhen XXX Software Technology Co., Ltd',
 | 
			
		||||
			two6: 'Copyright: Shenzhen XXX software technology Guangdong ICP preparation no.05010000',
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										18
									
								
								src/i18n/pages/login/zh-cn.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/i18n/pages/login/zh-cn.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
// 定义内容
 | 
			
		||||
export default {
 | 
			
		||||
	login: {
 | 
			
		||||
		placeholder1: '用户名 admin 或不输均为 test',
 | 
			
		||||
		placeholder2: '密码:123456',
 | 
			
		||||
		placeholder3: '请输入验证码',
 | 
			
		||||
		btnText: '登 录',
 | 
			
		||||
		link: {
 | 
			
		||||
			one1: '第三方登录',
 | 
			
		||||
			one2: '友情链接',
 | 
			
		||||
		},
 | 
			
		||||
		signInText: '欢迎回来!',
 | 
			
		||||
		copyright: {
 | 
			
		||||
			one5: '版权所有:深圳市xxx软件科技有限公司',
 | 
			
		||||
			two6: 'Copyright: Shenzhen XXX Software Technology 粤ICP备05010000号',
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										18
									
								
								src/i18n/pages/login/zh-tw.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/i18n/pages/login/zh-tw.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
// 定义内容
 | 
			
		||||
export default {
 | 
			
		||||
	login: {
 | 
			
		||||
		placeholder1: '用戶名admin或不輸均為test',
 | 
			
		||||
		placeholder2: '密碼:123456',
 | 
			
		||||
		placeholder3: '請輸入驗證碼',
 | 
			
		||||
		btnText: '登 录',
 | 
			
		||||
		link: {
 | 
			
		||||
			one1: '協力廠商登入',
 | 
			
		||||
			one2: '友情連結',
 | 
			
		||||
		},
 | 
			
		||||
		signInText: '歡迎回來!',
 | 
			
		||||
		copyright: {
 | 
			
		||||
			one5: '版權所有:深圳市xxx軟件科技有限公司',
 | 
			
		||||
			two6: 'Copyright: Shenzhen XXX Software Technology 粵ICP備05010000號',
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										106
									
								
								src/layout/component/aside.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								src/layout/component/aside.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,106 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<el-aside class="layout-aside" :class="setCollapseWidth" v-if="clientWidth > 1000">
 | 
			
		||||
		<Logo v-if="setShowLogo" />
 | 
			
		||||
		<el-scrollbar class="flex-auto" ref="layoutAsideRef">
 | 
			
		||||
			<Vertical :menuList="menuList" :class="setCollapseWidth" />
 | 
			
		||||
		</el-scrollbar>
 | 
			
		||||
	</el-aside>
 | 
			
		||||
	<el-drawer :visible.sync="getThemeConfig.isCollapse" :with-header="false" direction="ltr" size="220px" v-else>
 | 
			
		||||
		<el-aside class="layout-aside w100 h100">
 | 
			
		||||
			<Logo v-if="setShowLogo" />
 | 
			
		||||
			<el-scrollbar class="flex-auto" ref="layoutAsideRef">
 | 
			
		||||
				<Vertical :menuList="menuList" />
 | 
			
		||||
			</el-scrollbar>
 | 
			
		||||
		</el-aside>
 | 
			
		||||
	</el-drawer>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import Vertical from '@/layout/navMenu/vertical.vue';
 | 
			
		||||
import Logo from '@/layout/logo/index.vue';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layoutAside',
 | 
			
		||||
	components: { Vertical, Logo },
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			menuList: [],
 | 
			
		||||
			clientWidth: '',
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		// 设置左侧菜单的具体宽度
 | 
			
		||||
		setCollapseWidth() {
 | 
			
		||||
			let { layout, isCollapse } = this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
			let asideBrColor = '';
 | 
			
		||||
			layout === 'classic' || layout === 'columns' ? (asideBrColor = 'layout-el-aside-br-color') : '';
 | 
			
		||||
 | 
			
		||||
			if (layout === 'columns') {
 | 
			
		||||
				// 分栏布局,菜单收起时宽度给 1px
 | 
			
		||||
				if (isCollapse) {
 | 
			
		||||
					return ['layout-aside-width1', asideBrColor];
 | 
			
		||||
				} else {
 | 
			
		||||
					return ['layout-aside-width-default', asideBrColor];
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				// 其它布局给 64px
 | 
			
		||||
				if (isCollapse) {
 | 
			
		||||
					return ['layout-aside-width64', asideBrColor];
 | 
			
		||||
				} else {
 | 
			
		||||
					return ['layout-aside-width-default', asideBrColor];
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		// 设置 logo 是否显示
 | 
			
		||||
		setShowLogo() {
 | 
			
		||||
			let { layout, isShowLogo } = this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
			return (isShowLogo && layout === 'defaults') || (isShowLogo && layout === 'columns');
 | 
			
		||||
		},
 | 
			
		||||
		// 获取布局配置信息
 | 
			
		||||
		getThemeConfig() {
 | 
			
		||||
			return this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	created() {
 | 
			
		||||
		this.initMenuFixed(document.body.clientWidth);
 | 
			
		||||
		this.setFilterRoutes();
 | 
			
		||||
		this.bus.$on('setSendColumnsChildren', (res) => {
 | 
			
		||||
			this.menuList = res.children;
 | 
			
		||||
		});
 | 
			
		||||
		this.bus.$on('layoutMobileResize', (res) => {
 | 
			
		||||
			this.initMenuFixed(res.clientWidth);
 | 
			
		||||
		});
 | 
			
		||||
		// 菜单滚动条监听
 | 
			
		||||
		this.bus.$on('updateElScrollBar', () => {
 | 
			
		||||
			setTimeout(() => {
 | 
			
		||||
				this.$refs.layoutAsideRef.update();
 | 
			
		||||
			}, 300);
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 设置/过滤路由(非静态路由/是否显示在菜单中)
 | 
			
		||||
		setFilterRoutes() {
 | 
			
		||||
			if (this.$store.state.themeConfig.themeConfig.layout === 'columns') return false;
 | 
			
		||||
			this.menuList = this.filterRoutesFun(this.$store.state.routesList.routesList);
 | 
			
		||||
		},
 | 
			
		||||
		// 设置/过滤路由 递归函数
 | 
			
		||||
		filterRoutesFun(arr) {
 | 
			
		||||
			return arr
 | 
			
		||||
				.filter((item) => !item.meta.isHide)
 | 
			
		||||
				.map((item) => {
 | 
			
		||||
					item = Object.assign({}, item);
 | 
			
		||||
					if (item.children) item.children = this.filterRoutesFun(item.children);
 | 
			
		||||
					return item;
 | 
			
		||||
				});
 | 
			
		||||
		},
 | 
			
		||||
		// 设置菜单导航是否固定(移动端)
 | 
			
		||||
		initMenuFixed(clientWidth) {
 | 
			
		||||
			this.clientWidth = clientWidth;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	// 页面销毁时
 | 
			
		||||
	destroyed() {
 | 
			
		||||
		// 取消菜单滚动条监听
 | 
			
		||||
		this.bus.$off('updateElScrollBar', () => {});
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										223
									
								
								src/layout/component/columnsAside.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								src/layout/component/columnsAside.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,223 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="layout-columns-aside">
 | 
			
		||||
		<el-scrollbar>
 | 
			
		||||
			<ul>
 | 
			
		||||
				<li
 | 
			
		||||
					v-for="(v, k) in columnsAsideList"
 | 
			
		||||
					:key="k"
 | 
			
		||||
					@click="onColumnsAsideMenuClick(v, k)"
 | 
			
		||||
					ref="columnsAsideOffsetTopRefs"
 | 
			
		||||
					:class="{ 'layout-columns-active': liIndex === k }"
 | 
			
		||||
					:title="$t(v.meta.title)"
 | 
			
		||||
				>
 | 
			
		||||
					<div :class="setColumnsAsidelayout" v-if="!v.meta.isLink || (v.meta.isLink && v.meta.isIframe)">
 | 
			
		||||
						<i :class="v.meta.icon"></i>
 | 
			
		||||
						<div class="font12">
 | 
			
		||||
							{{
 | 
			
		||||
								$t(v.meta.title) && $t(v.meta.title).length >= 4
 | 
			
		||||
									? $t(v.meta.title).substr(0, setColumnsAsidelayout === 'columns-vertical' ? 4 : 3)
 | 
			
		||||
									: $t(v.meta.title)
 | 
			
		||||
							}}
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div :class="setColumnsAsidelayout" v-else>
 | 
			
		||||
						<a :href="v.meta.isLink" target="_blank">
 | 
			
		||||
							<i :class="v.meta.icon"></i>
 | 
			
		||||
							<div class="font12">
 | 
			
		||||
								{{
 | 
			
		||||
									$t(v.meta.title) && $t(v.meta.title).length >= 4
 | 
			
		||||
										? $t(v.meta.title).substr(0, setColumnsAsidelayout === 'columns-vertical' ? 4 : 3)
 | 
			
		||||
										: $t(v.meta.title)
 | 
			
		||||
								}}
 | 
			
		||||
							</div>
 | 
			
		||||
						</a>
 | 
			
		||||
					</div>
 | 
			
		||||
				</li>
 | 
			
		||||
				<div ref="columnsAsideActiveRef" :class="setColumnsAsideStyle"></div>
 | 
			
		||||
			</ul>
 | 
			
		||||
		</el-scrollbar>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layoutColumnsAside',
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			columnsAsideList: [],
 | 
			
		||||
			liIndex: 0,
 | 
			
		||||
			difference: 0,
 | 
			
		||||
			routeSplit: [],
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		// 设置分栏高亮风格
 | 
			
		||||
		setColumnsAsideStyle() {
 | 
			
		||||
			return this.$store.state.themeConfig.themeConfig.columnsAsideStyle;
 | 
			
		||||
		},
 | 
			
		||||
		// 设置分栏布局风格
 | 
			
		||||
		setColumnsAsidelayout() {
 | 
			
		||||
			return this.$store.state.themeConfig.themeConfig.columnsAsideLayout;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.setFilterRoutes();
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 设置菜单高亮位置移动
 | 
			
		||||
		setColumnsAsideMove(k) {
 | 
			
		||||
			const els = this.$refs.columnsAsideOffsetTopRefs;
 | 
			
		||||
			this.liIndex = k;
 | 
			
		||||
			this.$refs.columnsAsideActiveRef.style.top = `${els[k].offsetTop + this.difference}px`;
 | 
			
		||||
		},
 | 
			
		||||
		// 菜单高亮点击事件
 | 
			
		||||
		onColumnsAsideMenuClick(v, k) {
 | 
			
		||||
			this.setColumnsAsideMove(k);
 | 
			
		||||
			let { path, redirect } = v;
 | 
			
		||||
			if (redirect) this.$router.push(redirect);
 | 
			
		||||
			else this.$router.push(path);
 | 
			
		||||
		},
 | 
			
		||||
		// 设置高亮动态位置
 | 
			
		||||
		onColumnsAsideDown(k) {
 | 
			
		||||
			this.$nextTick(() => {
 | 
			
		||||
				this.setColumnsAsideMove(k);
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		// 设置/过滤路由(非静态路由/是否显示在菜单中)
 | 
			
		||||
		setFilterRoutes() {
 | 
			
		||||
			if (this.$store.state.routesList.routesList.length <= 0) return false;
 | 
			
		||||
			this.columnsAsideList = this.filterRoutesFun(this.$store.state.routesList.routesList);
 | 
			
		||||
			const resData = this.setSendChildren(this.$route.path);
 | 
			
		||||
			if (Object.keys(resData).length <= 0) return false;
 | 
			
		||||
			this.onColumnsAsideDown(resData.item[0].k);
 | 
			
		||||
			this.bus.$emit('setSendColumnsChildren', resData);
 | 
			
		||||
		},
 | 
			
		||||
		// 传送当前子级数据到菜单中
 | 
			
		||||
		setSendChildren(path) {
 | 
			
		||||
			const currentPathSplit = path.split('/');
 | 
			
		||||
			let currentData = {};
 | 
			
		||||
			this.columnsAsideList.map((v, k) => {
 | 
			
		||||
				if (v.path === `/${currentPathSplit[1]}`) {
 | 
			
		||||
					v['k'] = k;
 | 
			
		||||
					currentData['item'] = [{ ...v }];
 | 
			
		||||
					currentData['children'] = [{ ...v }];
 | 
			
		||||
					if (v.children) currentData['children'] = v.children;
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
			return currentData;
 | 
			
		||||
		},
 | 
			
		||||
		// 路由过滤递归函数
 | 
			
		||||
		filterRoutesFun(arr) {
 | 
			
		||||
			return arr
 | 
			
		||||
				.filter((item) => !item.meta.isHide)
 | 
			
		||||
				.map((item) => {
 | 
			
		||||
					item = Object.assign({}, item);
 | 
			
		||||
					if (item.children) item.children = this.filterRoutesFun(item.children);
 | 
			
		||||
					return item;
 | 
			
		||||
				});
 | 
			
		||||
		},
 | 
			
		||||
		// tagsView 点击时,根据路由查找下标 columnsAsideList,实现左侧菜单高亮
 | 
			
		||||
		setColumnsMenuHighlight(path) {
 | 
			
		||||
			this.routeSplit = path.split('/');
 | 
			
		||||
			this.routeSplit.shift();
 | 
			
		||||
			const routeFirst = `/${this.routeSplit[0]}`;
 | 
			
		||||
			const currentSplitRoute = this.columnsAsideList.find((v) => v.path === routeFirst);
 | 
			
		||||
			if (!currentSplitRoute) return false;
 | 
			
		||||
			// 延迟拿值,防止取不到
 | 
			
		||||
			setTimeout(() => {
 | 
			
		||||
				this.onColumnsAsideDown(currentSplitRoute.k);
 | 
			
		||||
			}, 0);
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	watch: {
 | 
			
		||||
		// 监听 vuex 数据变化
 | 
			
		||||
		'$store.state': {
 | 
			
		||||
			handler(val) {
 | 
			
		||||
				val.themeConfig.themeConfig.columnsAsideStyle === 'columnsRound' ? (this.difference = 3) : (this.difference = 0);
 | 
			
		||||
				if (val.routesList.routesList.length === this.columnsAsideList.length) return false;
 | 
			
		||||
				this.setFilterRoutes();
 | 
			
		||||
			},
 | 
			
		||||
			deep: true,
 | 
			
		||||
		},
 | 
			
		||||
		// 监听路由的变化
 | 
			
		||||
		$route: {
 | 
			
		||||
			handler(to) {
 | 
			
		||||
				this.setColumnsMenuHighlight(to.path);
 | 
			
		||||
				this.bus.$emit('setSendColumnsChildren', this.setSendChildren(to.path));
 | 
			
		||||
			},
 | 
			
		||||
			deep: true,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.layout-columns-aside {
 | 
			
		||||
	width: 70px;
 | 
			
		||||
	height: 100%;
 | 
			
		||||
	background: var(--prev-bg-columnsMenuBar);
 | 
			
		||||
	ul {
 | 
			
		||||
		position: relative;
 | 
			
		||||
		li {
 | 
			
		||||
			color: var(--prev-bg-columnsMenuBarColor);
 | 
			
		||||
			width: 100%;
 | 
			
		||||
			height: 50px;
 | 
			
		||||
			text-align: center;
 | 
			
		||||
			display: flex;
 | 
			
		||||
			cursor: pointer;
 | 
			
		||||
			position: relative;
 | 
			
		||||
			z-index: 1;
 | 
			
		||||
			.columns-vertical {
 | 
			
		||||
				margin: auto;
 | 
			
		||||
				.columns-vertical-title {
 | 
			
		||||
					padding-top: 1px;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			.columns-horizontal {
 | 
			
		||||
				display: flex;
 | 
			
		||||
				height: 50px;
 | 
			
		||||
				width: 100%;
 | 
			
		||||
				align-items: center;
 | 
			
		||||
				padding: 0 5px;
 | 
			
		||||
				i {
 | 
			
		||||
					margin-right: 3px;
 | 
			
		||||
				}
 | 
			
		||||
				a {
 | 
			
		||||
					display: flex;
 | 
			
		||||
					.columns-horizontal-title {
 | 
			
		||||
						padding-top: 1px;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			a {
 | 
			
		||||
				text-decoration: none;
 | 
			
		||||
				color: var(--prev-bg-columnsMenuBarColor);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		.layout-columns-active {
 | 
			
		||||
			color: var(--prev-color-text-white);
 | 
			
		||||
			transition: 0.3s ease-in-out;
 | 
			
		||||
		}
 | 
			
		||||
		.columns-round {
 | 
			
		||||
			background: var(--prev-color-primary);
 | 
			
		||||
			color: var(--prev-color-text-white);
 | 
			
		||||
			position: absolute;
 | 
			
		||||
			left: 50%;
 | 
			
		||||
			top: 2px;
 | 
			
		||||
			height: 50px;
 | 
			
		||||
			width: 65px;
 | 
			
		||||
			transform: translateX(-50%);
 | 
			
		||||
			z-index: 0;
 | 
			
		||||
			transition: 0.3s ease-in-out;
 | 
			
		||||
			border-radius: 5px;
 | 
			
		||||
		}
 | 
			
		||||
		.columns-card {
 | 
			
		||||
			@extend .columns-round;
 | 
			
		||||
			top: 0;
 | 
			
		||||
			height: 50px;
 | 
			
		||||
			width: 100%;
 | 
			
		||||
			border-radius: 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										24
									
								
								src/layout/component/header.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/layout/component/header.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<el-header class="layout-header" :height="setHeaderHeight">
 | 
			
		||||
		<NavBarsIndex />
 | 
			
		||||
	</el-header>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import NavBarsIndex from '@/layout/navBars/index.vue';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layoutHeader',
 | 
			
		||||
	components: { NavBarsIndex },
 | 
			
		||||
	data() {
 | 
			
		||||
		return {};
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		// 设置顶部 header 的具体高度
 | 
			
		||||
		setHeaderHeight() {
 | 
			
		||||
			let { isTagsview, layout } = this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
			if (isTagsview && layout !== 'classic') return '84px';
 | 
			
		||||
			else return '50px';
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										93
									
								
								src/layout/component/main.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/layout/component/main.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,93 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<el-main class="layout-main">
 | 
			
		||||
		<el-scrollbar
 | 
			
		||||
			class="layout-scrollbar"
 | 
			
		||||
			ref="layoutScrollbarRef"
 | 
			
		||||
			v-show="!currentRouteMeta.isLink && !currentRouteMeta.isIframe"
 | 
			
		||||
			:style="{ minHeight: `calc(100vh - ${headerHeight}` }"
 | 
			
		||||
		>
 | 
			
		||||
			<LayoutParentView />
 | 
			
		||||
			<Footers v-if="getThemeConfig.isFooter" />
 | 
			
		||||
		</el-scrollbar>
 | 
			
		||||
		<Links
 | 
			
		||||
			:style="{ height: `calc(100vh - ${headerHeight}` }"
 | 
			
		||||
			:meta="currentRouteMeta"
 | 
			
		||||
			v-if="currentRouteMeta.isLink && !currentRouteMeta.isIframe"
 | 
			
		||||
		/>
 | 
			
		||||
		<Iframes
 | 
			
		||||
			:style="{ height: `calc(100vh - ${headerHeight}` }"
 | 
			
		||||
			:meta="currentRouteMeta"
 | 
			
		||||
			v-if="currentRouteMeta.isLink && currentRouteMeta.isIframe && isShowLink"
 | 
			
		||||
			@getCurrentRouteMeta="onGetCurrentRouteMeta"
 | 
			
		||||
		/>
 | 
			
		||||
	</el-main>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import LayoutParentView from '@/layout/routerView/parent.vue';
 | 
			
		||||
import Footers from '@/layout/footer/index.vue';
 | 
			
		||||
import Links from '@/layout/routerView/link.vue';
 | 
			
		||||
import Iframes from '@/layout/routerView/iframes.vue';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layoutMain',
 | 
			
		||||
	components: { LayoutParentView, Footers, Links, Iframes },
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			headerHeight: '',
 | 
			
		||||
			currentRouteMeta: {},
 | 
			
		||||
			isShowLink: false,
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		// 获取布局配置信息
 | 
			
		||||
		getThemeConfig() {
 | 
			
		||||
			return this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.initHeaderHeight();
 | 
			
		||||
		this.initCurrentRouteMeta(this.$route.meta);
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 初始化当前路由 meta 信息
 | 
			
		||||
		initCurrentRouteMeta(meta) {
 | 
			
		||||
			this.isShowLink = false;
 | 
			
		||||
			this.currentRouteMeta = meta;
 | 
			
		||||
			setTimeout(() => {
 | 
			
		||||
				this.isShowLink = true;
 | 
			
		||||
			}, 100);
 | 
			
		||||
		},
 | 
			
		||||
		// 设置 main 的高度
 | 
			
		||||
		initHeaderHeight() {
 | 
			
		||||
			let { isTagsview } = this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
			if (isTagsview) return (this.headerHeight = `84px`);
 | 
			
		||||
			else return (this.headerHeight = `50px`);
 | 
			
		||||
		},
 | 
			
		||||
		// 子组件触发更新
 | 
			
		||||
		onGetCurrentRouteMeta() {
 | 
			
		||||
			this.initCurrentRouteMeta(this.$route.meta);
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	watch: {
 | 
			
		||||
		// 监听 vuex 数据变化
 | 
			
		||||
		'$store.state.themeConfig.themeConfig': {
 | 
			
		||||
			handler(val) {
 | 
			
		||||
				this.headerHeight = val.isTagsview ? '84px' : '50px';
 | 
			
		||||
				if (val.isFixedHeaderChange !== val.isFixedHeader) {
 | 
			
		||||
					if (!this.$refs.layoutScrollbarRef) return false;
 | 
			
		||||
					this.$refs.layoutScrollbarRef.update();
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			deep: true,
 | 
			
		||||
		},
 | 
			
		||||
		// 监听路由的变化
 | 
			
		||||
		$route: {
 | 
			
		||||
			handler(to) {
 | 
			
		||||
				this.initCurrentRouteMeta(to.meta);
 | 
			
		||||
				this.$refs.layoutScrollbarRef.wrap.scrollTop = 0;
 | 
			
		||||
			},
 | 
			
		||||
			deep: true,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										29
									
								
								src/layout/footer/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/layout/footer/index.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="layout-footer mt15">
 | 
			
		||||
		<div class="layout-footer-warp">
 | 
			
		||||
			<div>vue-prev-admin,Made by lyt with ❤️</div>
 | 
			
		||||
			<div class="mt5">{{ $t('message.login.copyright.one5') }}</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layoutFooter',
 | 
			
		||||
	data() {
 | 
			
		||||
		return {};
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.layout-footer {
 | 
			
		||||
	width: 100%;
 | 
			
		||||
	display: flex;
 | 
			
		||||
	&-warp {
 | 
			
		||||
		margin: auto;
 | 
			
		||||
		color: var(--prev-color-text-secondary);
 | 
			
		||||
		text-align: center;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										51
									
								
								src/layout/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/layout/index.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<Defaults v-if="getThemeConfig.layout === 'defaults'" />
 | 
			
		||||
	<Classic v-else-if="getThemeConfig.layout === 'classic'" />
 | 
			
		||||
	<Transverse v-else-if="getThemeConfig.layout === 'transverse'" />
 | 
			
		||||
	<Columns v-else-if="getThemeConfig.layout === 'columns'" />
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { Local } from '@/utils/storage.js';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layout',
 | 
			
		||||
	components: {
 | 
			
		||||
		Defaults: () => import('@/layout/main/defaults.vue'),
 | 
			
		||||
		Classic: () => import('@/layout/main/classic.vue'),
 | 
			
		||||
		Transverse: () => import('@/layout/main/transverse.vue'),
 | 
			
		||||
		Columns: () => import('@/layout/main/columns.vue'),
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		// 获取布局配置信息
 | 
			
		||||
		getThemeConfig() {
 | 
			
		||||
			return this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	created() {
 | 
			
		||||
		this.onLayoutResize();
 | 
			
		||||
		window.addEventListener('resize', this.onLayoutResize);
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 窗口大小改变时(适配移动端)
 | 
			
		||||
		onLayoutResize() {
 | 
			
		||||
			if (!Local.get('oldLayout')) Local.set('oldLayout', this.$store.state.themeConfig.themeConfig.layout);
 | 
			
		||||
			const clientWidth = document.body.clientWidth;
 | 
			
		||||
			if (clientWidth < 1000) {
 | 
			
		||||
				this.$store.state.themeConfig.themeConfig.isCollapse = false;
 | 
			
		||||
				this.bus.$emit('layoutMobileResize', {
 | 
			
		||||
					layout: 'defaults',
 | 
			
		||||
					clientWidth,
 | 
			
		||||
				});
 | 
			
		||||
			} else {
 | 
			
		||||
				this.bus.$emit('layoutMobileResize', {
 | 
			
		||||
					layout: Local.get('oldLayout') ? Local.get('oldLayout') : this.$store.state.themeConfig.themeConfig.layout,
 | 
			
		||||
					clientWidth,
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	distroyed() {
 | 
			
		||||
		window.removeEventListener('resize', this.onLayoutResize);
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										70
									
								
								src/layout/logo/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/layout/logo/index.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="layout-logo" v-if="setShowLogo" @click="onThemeConfigChange">
 | 
			
		||||
		<img src="https://gitee.com/lyt-top/vue-next-admin-images/raw/master/vue2/logo-mini.svg" class="layout-logo-medium-img" />
 | 
			
		||||
		<span>{{ getThemeConfig.globalTitle }}</span>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div class="layout-logo-size" v-else @click="onThemeConfigChange">
 | 
			
		||||
		<img src="https://gitee.com/lyt-top/vue-next-admin-images/raw/master/vue2/logo-mini.svg" class="layout-logo-size-img" />
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layoutLogo',
 | 
			
		||||
	computed: {
 | 
			
		||||
		// 获取布局配置信息
 | 
			
		||||
		getThemeConfig() {
 | 
			
		||||
			return this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
		},
 | 
			
		||||
		// 设置 logo 是否显示
 | 
			
		||||
		setShowLogo() {
 | 
			
		||||
			let { isCollapse, layout } = this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
			return !isCollapse || layout === 'classic' || document.body.clientWidth < 1000;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// logo 点击实现菜单展开/收起
 | 
			
		||||
		onThemeConfigChange() {
 | 
			
		||||
			if (this.$store.state.themeConfig.themeConfig.layout === 'transverse') return false;
 | 
			
		||||
			this.$store.state.themeConfig.themeConfig.isCollapse = !this.$store.state.themeConfig.themeConfig.isCollapse;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.layout-logo {
 | 
			
		||||
	width: 220px;
 | 
			
		||||
	height: 50px;
 | 
			
		||||
	display: flex;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	justify-content: center;
 | 
			
		||||
	box-shadow: rgb(0 21 41 / 2%) 0px 1px 4px;
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
	font-size: 16px;
 | 
			
		||||
	cursor: pointer;
 | 
			
		||||
	animation: logoAnimation 0.3s ease-in-out;
 | 
			
		||||
	&:hover {
 | 
			
		||||
		span {
 | 
			
		||||
			opacity: 0.9;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	&-medium-img {
 | 
			
		||||
		width: 20px;
 | 
			
		||||
		margin-right: 5px;
 | 
			
		||||
		position: relative;
 | 
			
		||||
		top: 2px;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
.layout-logo-size {
 | 
			
		||||
	width: 100%;
 | 
			
		||||
	height: 50px;
 | 
			
		||||
	display: flex;
 | 
			
		||||
	cursor: pointer;
 | 
			
		||||
	&-img {
 | 
			
		||||
		width: 20px;
 | 
			
		||||
		margin: auto;
 | 
			
		||||
		animation: logoAnimation 0.3s ease-in-out;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										30
									
								
								src/layout/main/classic.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/layout/main/classic.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<el-container class="layout-container flex-center">
 | 
			
		||||
		<Headers />
 | 
			
		||||
		<el-container class="layout-mian-height-50">
 | 
			
		||||
			<Asides />
 | 
			
		||||
			<div class="flex-center layout-backtop">
 | 
			
		||||
				<TagsView v-if="getThemeConfig.isTagsview" />
 | 
			
		||||
				<Mains />
 | 
			
		||||
			</div>
 | 
			
		||||
		</el-container>
 | 
			
		||||
		<el-backtop target=".layout-backtop .el-main .el-scrollbar__wrap"></el-backtop>
 | 
			
		||||
	</el-container>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import Asides from '@/layout/component/aside.vue';
 | 
			
		||||
import Headers from '@/layout/component/header.vue';
 | 
			
		||||
import Mains from '@/layout/component/main.vue';
 | 
			
		||||
import TagsView from '@/layout/navBars/tagsView/tagsView.vue';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layoutClassic',
 | 
			
		||||
	components: { Asides, Headers, Mains, TagsView },
 | 
			
		||||
	computed: {
 | 
			
		||||
		// 获取布局配置信息
 | 
			
		||||
		getThemeConfig() {
 | 
			
		||||
			return this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										33
									
								
								src/layout/main/columns.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/layout/main/columns.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<el-container class="layout-container">
 | 
			
		||||
		<ColumnsAside />
 | 
			
		||||
		<div class="layout-columns-warp">
 | 
			
		||||
			<Asides />
 | 
			
		||||
			<el-container class="flex-center layout-backtop">
 | 
			
		||||
				<Headers v-if="isFixedHeader" />
 | 
			
		||||
				<el-scrollbar>
 | 
			
		||||
					<Headers v-if="!isFixedHeader" />
 | 
			
		||||
					<Mains />
 | 
			
		||||
				</el-scrollbar>
 | 
			
		||||
			</el-container>
 | 
			
		||||
		</div>
 | 
			
		||||
		<el-backtop target=".layout-backtop .el-scrollbar__wrap"></el-backtop>
 | 
			
		||||
	</el-container>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import Asides from '@/layout/component/aside.vue';
 | 
			
		||||
import Headers from '@/layout/component/header.vue';
 | 
			
		||||
import Mains from '@/layout/component/main.vue';
 | 
			
		||||
import ColumnsAside from '@/layout/component/columnsAside.vue';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layoutColumns',
 | 
			
		||||
	components: { Asides, Headers, Mains, ColumnsAside },
 | 
			
		||||
	computed: {
 | 
			
		||||
		// 是否开启固定 header
 | 
			
		||||
		isFixedHeader() {
 | 
			
		||||
			return this.$store.state.themeConfig.themeConfig.isFixedHeader;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										41
									
								
								src/layout/main/defaults.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/layout/main/defaults.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<el-container class="layout-container">
 | 
			
		||||
		<Asides />
 | 
			
		||||
		<el-container class="flex-center layout-backtop">
 | 
			
		||||
			<Headers v-if="isFixedHeader" />
 | 
			
		||||
			<el-scrollbar ref="layoutDefaultsScrollbarRef">
 | 
			
		||||
				<Headers v-if="!isFixedHeader" />
 | 
			
		||||
				<Mains />
 | 
			
		||||
			</el-scrollbar>
 | 
			
		||||
		</el-container>
 | 
			
		||||
		<el-backtop target=".layout-backtop .el-scrollbar__wrap"></el-backtop>
 | 
			
		||||
	</el-container>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import Asides from '@/layout/component/aside.vue';
 | 
			
		||||
import Headers from '@/layout/component/header.vue';
 | 
			
		||||
import Mains from '@/layout/component/main.vue';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layoutDefaults',
 | 
			
		||||
	components: { Asides, Headers, Mains },
 | 
			
		||||
	data() {
 | 
			
		||||
		return {};
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		// 是否开启固定 header
 | 
			
		||||
		isFixedHeader() {
 | 
			
		||||
			return this.$store.state.themeConfig.themeConfig.isFixedHeader;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	watch: {
 | 
			
		||||
		// 监听路由的变化
 | 
			
		||||
		$route: {
 | 
			
		||||
			handler() {
 | 
			
		||||
				this.$refs.layoutDefaultsScrollbarRef.wrap.scrollTop = 0;
 | 
			
		||||
			},
 | 
			
		||||
			deep: true,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										16
									
								
								src/layout/main/transverse.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/layout/main/transverse.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<el-container class="layout-container flex-center layout-backtop">
 | 
			
		||||
		<Headers />
 | 
			
		||||
		<Mains />
 | 
			
		||||
		<el-backtop target=".layout-backtop .el-main .el-scrollbar__wrap"></el-backtop>
 | 
			
		||||
	</el-container>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import Headers from '@/layout/component/header.vue';
 | 
			
		||||
import Mains from '@/layout/component/main.vue';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layoutTransverse',
 | 
			
		||||
	components: { Headers, Mains },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										139
									
								
								src/layout/navBars/breadcrumb/breadcrumb.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								src/layout/navBars/breadcrumb/breadcrumb.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,139 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="layout-navbars-breadcrumb" :style="{ display: isShowBreadcrumb }">
 | 
			
		||||
		<i
 | 
			
		||||
			class="layout-navbars-breadcrumb-icon"
 | 
			
		||||
			:class="getThemeConfig.isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold'"
 | 
			
		||||
			@click="onThemeConfigChange"
 | 
			
		||||
		></i>
 | 
			
		||||
		<el-breadcrumb class="layout-navbars-breadcrumb-hide">
 | 
			
		||||
			<transition-group name="breadcrumb" mode="out-in">
 | 
			
		||||
				<el-breadcrumb-item v-for="(v, k) in breadcrumbList" :key="v.path">
 | 
			
		||||
					<span v-if="k === breadcrumbList.length - 1" class="layout-navbars-breadcrumb-span">
 | 
			
		||||
						<i :class="v.meta.icon" class="layout-navbars-breadcrumb-iconfont" v-if="getThemeConfig.isBreadcrumbIcon"></i>{{ $t(v.meta.title) }}
 | 
			
		||||
					</span>
 | 
			
		||||
					<a v-else @click.prevent="onBreadcrumbClick(v)">
 | 
			
		||||
						<i :class="v.meta.icon" class="layout-navbars-breadcrumb-iconfont" v-if="getThemeConfig.isBreadcrumbIcon"></i>{{ $t(v.meta.title) }}
 | 
			
		||||
					</a>
 | 
			
		||||
				</el-breadcrumb-item>
 | 
			
		||||
			</transition-group>
 | 
			
		||||
		</el-breadcrumb>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { Local } from '@/utils/storage.js';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layoutBreadcrumb',
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			breadcrumbList: [],
 | 
			
		||||
			routeSplit: [],
 | 
			
		||||
			routeSplitFirst: '',
 | 
			
		||||
			routeSplitIndex: 1,
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		// 获取布局配置信息
 | 
			
		||||
		getThemeConfig() {
 | 
			
		||||
			return this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
		},
 | 
			
		||||
		// 动态设置经典、横向布局不显示
 | 
			
		||||
		isShowBreadcrumb() {
 | 
			
		||||
			const { layout, isBreadcrumb } = this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
			if (layout === 'classic' || layout === 'transverse') {
 | 
			
		||||
				return 'none';
 | 
			
		||||
			} else {
 | 
			
		||||
				return isBreadcrumb ? '' : 'none';
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.initRouteSplit(this.$route.path);
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// breadcrumb 当前项点击时
 | 
			
		||||
		onBreadcrumbClick(v) {
 | 
			
		||||
			const { redirect, path } = v;
 | 
			
		||||
			if (redirect) this.$router.push(redirect);
 | 
			
		||||
			else this.$router.push(path);
 | 
			
		||||
		},
 | 
			
		||||
		// breadcrumb icon 点击菜单展开与收起
 | 
			
		||||
		onThemeConfigChange() {
 | 
			
		||||
			this.$store.state.themeConfig.themeConfig.isCollapse = !this.$store.state.themeConfig.themeConfig.isCollapse;
 | 
			
		||||
			this.setLocalThemeConfig();
 | 
			
		||||
		},
 | 
			
		||||
		// 存储布局配置
 | 
			
		||||
		setLocalThemeConfig() {
 | 
			
		||||
			Local.remove('themeConfigPrev');
 | 
			
		||||
			Local.set('themeConfigPrev', this.$store.state.themeConfig.themeConfig);
 | 
			
		||||
		},
 | 
			
		||||
		// 递归设置 breadcrumb
 | 
			
		||||
		getBreadcrumbList(arr) {
 | 
			
		||||
			arr.map((item) => {
 | 
			
		||||
				this.routeSplit.map((v, k, arrs) => {
 | 
			
		||||
					if (this.routeSplitFirst === item.path) {
 | 
			
		||||
						this.routeSplitFirst += `/${arrs[this.routeSplitIndex]}`;
 | 
			
		||||
						this.breadcrumbList.push(item);
 | 
			
		||||
						this.routeSplitIndex++;
 | 
			
		||||
						if (item.children) this.getBreadcrumbList(item.children);
 | 
			
		||||
					}
 | 
			
		||||
				});
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		// 当前路由分割处理
 | 
			
		||||
		initRouteSplit(path) {
 | 
			
		||||
			this.breadcrumbList = [
 | 
			
		||||
				{
 | 
			
		||||
					path: '/',
 | 
			
		||||
					meta: {
 | 
			
		||||
						title: this.$store.state.routesList.routesList[0].meta.title,
 | 
			
		||||
						icon: this.$store.state.routesList.routesList[0].meta.icon,
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			];
 | 
			
		||||
			this.routeSplit = path.split('/');
 | 
			
		||||
			this.routeSplit.shift();
 | 
			
		||||
			this.routeSplitFirst = `/${this.routeSplit[0]}`;
 | 
			
		||||
			this.routeSplitIndex = 1;
 | 
			
		||||
			this.getBreadcrumbList(this.$store.state.routesList.routesList);
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	// 监听路由的变化
 | 
			
		||||
	watch: {
 | 
			
		||||
		$route: {
 | 
			
		||||
			handler(newVal) {
 | 
			
		||||
				this.initRouteSplit(newVal.path);
 | 
			
		||||
			},
 | 
			
		||||
			deep: true,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.layout-navbars-breadcrumb {
 | 
			
		||||
	flex: 1;
 | 
			
		||||
	height: inherit;
 | 
			
		||||
	display: flex;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	padding-left: 15px;
 | 
			
		||||
	.layout-navbars-breadcrumb-icon {
 | 
			
		||||
		cursor: pointer;
 | 
			
		||||
		font-size: 18px;
 | 
			
		||||
		margin-right: 15px;
 | 
			
		||||
		color: var(--prev-bg-topBarColor);
 | 
			
		||||
		opacity: 0.8;
 | 
			
		||||
		&:hover {
 | 
			
		||||
			opacity: 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	.layout-navbars-breadcrumb-span {
 | 
			
		||||
		opacity: 0.7;
 | 
			
		||||
		color: var(--prev-bg-topBarColor);
 | 
			
		||||
	}
 | 
			
		||||
	.layout-navbars-breadcrumb-iconfont {
 | 
			
		||||
		font-size: 14px;
 | 
			
		||||
		margin-right: 5px;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										77
									
								
								src/layout/navBars/breadcrumb/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/layout/navBars/breadcrumb/index.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="layout-navbars-breadcrumb-index">
 | 
			
		||||
		<Logo v-if="setIsShowLogo" />
 | 
			
		||||
		<Breadcrumb />
 | 
			
		||||
		<Horizontal :menuList="menuList" v-if="isLayoutTransverse" />
 | 
			
		||||
		<User />
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import Breadcrumb from '@/layout/navBars/breadcrumb/breadcrumb.vue';
 | 
			
		||||
import User from '@/layout/navBars/breadcrumb/user.vue';
 | 
			
		||||
import Logo from '@/layout/logo/index.vue';
 | 
			
		||||
import Horizontal from '@/layout/navMenu/horizontal.vue';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layoutNavBars',
 | 
			
		||||
	components: { Breadcrumb, User, Logo, Horizontal },
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			menuList: [],
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		// 设置 logo 是否显示
 | 
			
		||||
		setIsShowLogo() {
 | 
			
		||||
			let { isShowLogo, layout } = this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
			return (isShowLogo && layout === 'classic') || (isShowLogo && layout === 'transverse');
 | 
			
		||||
		},
 | 
			
		||||
		// 设置是否显示横向菜单
 | 
			
		||||
		isLayoutTransverse() {
 | 
			
		||||
			let { layout, isClassicSplitMenu } = this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
			return layout === 'transverse' || (isClassicSplitMenu && layout === 'classic');
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.setFilterRoutes();
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 设置路由的过滤
 | 
			
		||||
		setFilterRoutes() {
 | 
			
		||||
			this.menuList = this.filterRoutesFun(this.$store.state.routesList.routesList);
 | 
			
		||||
		},
 | 
			
		||||
		// 设置路由的过滤递归函数
 | 
			
		||||
		filterRoutesFun(arr) {
 | 
			
		||||
			return arr
 | 
			
		||||
				.filter((item) => !item.meta.isHide)
 | 
			
		||||
				.map((item) => {
 | 
			
		||||
					item = Object.assign({}, item);
 | 
			
		||||
					if (item.children) item.children = this.filterRoutesFun(item.children);
 | 
			
		||||
					return item;
 | 
			
		||||
				});
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	watch: {
 | 
			
		||||
		// 监听 vuex 数据变化
 | 
			
		||||
		'$store.state': {
 | 
			
		||||
			handler(val) {
 | 
			
		||||
				if (val.routesList.routesList.length === this.menuList.length) return false;
 | 
			
		||||
				this.setFilterRoutes();
 | 
			
		||||
			},
 | 
			
		||||
			deep: true,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.layout-navbars-breadcrumb-index {
 | 
			
		||||
	height: 50px;
 | 
			
		||||
	display: flex;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	padding-right: 15px;
 | 
			
		||||
	overflow: hidden;
 | 
			
		||||
	background: var(--prev-bg-topBar);
 | 
			
		||||
	border-bottom: 1px solid var(--prev-border-color-lighter);
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										100
									
								
								src/layout/navBars/breadcrumb/search.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/layout/navBars/breadcrumb/search.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,100 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="layout-search-dialog">
 | 
			
		||||
		<el-dialog :visible.sync="isShowSearch" width="300px" destroy-on-close :modal="false" fullscreen :show-close="false">
 | 
			
		||||
			<el-autocomplete
 | 
			
		||||
				v-model="menuQuery"
 | 
			
		||||
				:fetch-suggestions="menuSearch"
 | 
			
		||||
				:placeholder="$t('message.user.searchPlaceholder')"
 | 
			
		||||
				prefix-icon="el-icon-search"
 | 
			
		||||
				ref="layoutMenuAutocompleteRef"
 | 
			
		||||
				@select="onHandleSelect"
 | 
			
		||||
				@blur="onSearchBlur"
 | 
			
		||||
			>
 | 
			
		||||
				<template slot-scope="{ item }">
 | 
			
		||||
					<div><i :class="item.meta.icon" class="mr10"></i>{{ $t(item.meta.title) }}</div>
 | 
			
		||||
				</template>
 | 
			
		||||
			</el-autocomplete>
 | 
			
		||||
		</el-dialog>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layoutBreadcrumbSearch',
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			isShowSearch: false,
 | 
			
		||||
			menuQuery: '',
 | 
			
		||||
			tagsViewList: [],
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 搜索弹窗打开
 | 
			
		||||
		openSearch() {
 | 
			
		||||
			this.menuQuery = '';
 | 
			
		||||
			this.isShowSearch = true;
 | 
			
		||||
			this.initTageView();
 | 
			
		||||
			this.$nextTick(() => {
 | 
			
		||||
				this.$refs.layoutMenuAutocompleteRef.focus();
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		// 搜索弹窗关闭
 | 
			
		||||
		closeSearch() {
 | 
			
		||||
			setTimeout(() => {
 | 
			
		||||
				this.isShowSearch = false;
 | 
			
		||||
			}, 150);
 | 
			
		||||
		},
 | 
			
		||||
		// 菜单搜索数据过滤
 | 
			
		||||
		menuSearch(queryString, cb) {
 | 
			
		||||
			let results = queryString ? this.tagsViewList.filter(this.createFilter(queryString)) : this.tagsViewList;
 | 
			
		||||
			cb(results);
 | 
			
		||||
		},
 | 
			
		||||
		// 菜单搜索过滤
 | 
			
		||||
		createFilter(queryString) {
 | 
			
		||||
			return (restaurant) => {
 | 
			
		||||
				return (
 | 
			
		||||
					restaurant.path.toLowerCase().indexOf(queryString.toLowerCase()) > -1 ||
 | 
			
		||||
					restaurant.meta.title.toLowerCase().indexOf(queryString.toLowerCase()) > -1 ||
 | 
			
		||||
					this.$t(restaurant.meta.title).toLowerCase().indexOf(queryString.toLowerCase()) > -1
 | 
			
		||||
				);
 | 
			
		||||
			};
 | 
			
		||||
		},
 | 
			
		||||
		// 初始化菜单数据
 | 
			
		||||
		initTageView() {
 | 
			
		||||
			if (this.tagsViewList.length > 0) return false;
 | 
			
		||||
			this.$store.state.tagsViewRoutes.tagsViewRoutes.map((v) => {
 | 
			
		||||
				if (!v.meta.isHide) this.tagsViewList.push({ ...v });
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		// 当前菜单选中时
 | 
			
		||||
		onHandleSelect(item) {
 | 
			
		||||
			let { path, redirect } = item;
 | 
			
		||||
			if (item.meta.isLink && !item.meta.isIframe) window.open(item.meta.isLink);
 | 
			
		||||
			else if (redirect) this.$router.push(redirect);
 | 
			
		||||
			else this.$router.push(path);
 | 
			
		||||
			this.closeSearch();
 | 
			
		||||
		},
 | 
			
		||||
		// input 失去焦点时
 | 
			
		||||
		onSearchBlur() {
 | 
			
		||||
			this.closeSearch();
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.layout-search-dialog {
 | 
			
		||||
	::v-deep .el-dialog {
 | 
			
		||||
		box-shadow: unset !important;
 | 
			
		||||
		border-radius: 0 !important;
 | 
			
		||||
		background: rgba(0, 0, 0, 0.5);
 | 
			
		||||
	}
 | 
			
		||||
	::v-deep .el-autocomplete {
 | 
			
		||||
		width: 560px;
 | 
			
		||||
		position: absolute;
 | 
			
		||||
		top: 100px;
 | 
			
		||||
		left: 50%;
 | 
			
		||||
		transform: translateX(-50%);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										538
									
								
								src/layout/navBars/breadcrumb/setings.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										538
									
								
								src/layout/navBars/breadcrumb/setings.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,538 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="layout-breadcrumb-seting">
 | 
			
		||||
		<el-drawer
 | 
			
		||||
			:title="$t('message.layout.configTitle')"
 | 
			
		||||
			:visible.sync="getThemeConfig.isDrawer"
 | 
			
		||||
			direction="rtl"
 | 
			
		||||
			destroy-on-close
 | 
			
		||||
			size="240px"
 | 
			
		||||
			@close="onDrawerClose"
 | 
			
		||||
		>
 | 
			
		||||
			<el-scrollbar class="layout-breadcrumb-seting-bar">
 | 
			
		||||
				<!-- 全局主题 -->
 | 
			
		||||
				<el-divider content-position="left">{{ $t('message.layout.oneTitle') }}</el-divider>
 | 
			
		||||
				<div class="layout-breadcrumb-seting-bar-flex">
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-label">primary</div>
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-value">
 | 
			
		||||
						<el-color-picker v-model="getThemeConfig.primary" size="small" @change="onColorPickerChange"> </el-color-picker>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="layout-breadcrumb-seting-bar-flex mt15">
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsDark') }}</div>
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-value">
 | 
			
		||||
						<el-switch v-model="getThemeConfig.isIsDark" :width="35" @change="onAddDarkChange"></el-switch>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
 | 
			
		||||
				<!-- 界面设置 -->
 | 
			
		||||
				<el-divider content-position="left">{{ $t('message.layout.threeTitle') }}</el-divider>
 | 
			
		||||
				<div class="layout-breadcrumb-seting-bar-flex">
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.threeIsCollapse') }}</div>
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-value">
 | 
			
		||||
						<el-switch v-model="getThemeConfig.isCollapse" :width="35" @change="setLocalThemeConfig"></el-switch>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="layout-breadcrumb-seting-bar-flex mt15">
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.threeIsUniqueOpened') }}</div>
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-value">
 | 
			
		||||
						<el-switch v-model="getThemeConfig.isUniqueOpened" :width="35" @change="setLocalThemeConfig"></el-switch>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="layout-breadcrumb-seting-bar-flex mt15">
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.threeIsFixedHeader') }}</div>
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-value">
 | 
			
		||||
						<el-switch v-model="getThemeConfig.isFixedHeader" :width="35" @change="setLocalThemeConfig"></el-switch>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
 | 
			
		||||
				<!-- 界面显示 -->
 | 
			
		||||
				<el-divider content-position="left">{{ $t('message.layout.fourTitle') }}</el-divider>
 | 
			
		||||
				<div class="layout-breadcrumb-seting-bar-flex">
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsShowLogo') }}</div>
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-value">
 | 
			
		||||
						<el-switch v-model="getThemeConfig.isShowLogo" :width="35" @change="setLocalThemeConfig"></el-switch>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div
 | 
			
		||||
					class="layout-breadcrumb-seting-bar-flex mt15"
 | 
			
		||||
					:style="{ opacity: getThemeConfig.layout === 'classic' || getThemeConfig.layout === 'transverse' ? 0.5 : 1 }"
 | 
			
		||||
				>
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsBreadcrumb') }}</div>
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-value">
 | 
			
		||||
						<el-switch
 | 
			
		||||
							v-model="getThemeConfig.isBreadcrumb"
 | 
			
		||||
							:disabled="getThemeConfig.layout === 'classic' || getThemeConfig.layout === 'transverse'"
 | 
			
		||||
							:width="35"
 | 
			
		||||
							@change="setLocalThemeConfig"
 | 
			
		||||
						></el-switch>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="layout-breadcrumb-seting-bar-flex mt15">
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsBreadcrumbIcon') }}</div>
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-value">
 | 
			
		||||
						<el-switch v-model="getThemeConfig.isBreadcrumbIcon" :width="35" @change="setLocalThemeConfig"></el-switch>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="layout-breadcrumb-seting-bar-flex mt15">
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsTagsview') }}</div>
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-value">
 | 
			
		||||
						<el-switch v-model="getThemeConfig.isTagsview" :width="35" @change="setLocalThemeConfig"></el-switch>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="layout-breadcrumb-seting-bar-flex mt15">
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsTagsviewIcon') }}</div>
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-value">
 | 
			
		||||
						<el-switch v-model="getThemeConfig.isTagsviewIcon" :width="35" @change="setLocalThemeConfig"></el-switch>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="layout-breadcrumb-seting-bar-flex mt15">
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsCacheTagsView') }}</div>
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-value">
 | 
			
		||||
						<el-switch v-model="getThemeConfig.isCacheTagsView" :width="35" @change="setLocalThemeConfig"></el-switch>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="layout-breadcrumb-seting-bar-flex mt15">
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsFooter') }}</div>
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-value">
 | 
			
		||||
						<el-switch v-model="getThemeConfig.isFooter" :width="35" @change="setLocalThemeConfig"></el-switch>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="layout-breadcrumb-seting-bar-flex mt15">
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsGrayscale') }}</div>
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-value">
 | 
			
		||||
						<el-switch v-model="getThemeConfig.isGrayscale" :width="35" @change="onAddFilterChange('grayscale')"></el-switch>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="layout-breadcrumb-seting-bar-flex mt15">
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fourIsInvert') }}</div>
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-value">
 | 
			
		||||
						<el-switch v-model="getThemeConfig.isInvert" :width="35" @change="onAddFilterChange('invert')"></el-switch>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
 | 
			
		||||
				<!-- 其它设置 -->
 | 
			
		||||
				<el-divider content-position="left">{{ $t('message.layout.fiveTitle') }}</el-divider>
 | 
			
		||||
				<div class="layout-breadcrumb-seting-bar-flex mt15">
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fiveTagsStyle') }}</div>
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-value">
 | 
			
		||||
						<el-select v-model="getThemeConfig.tagsStyle" placeholder="请选择" size="mini" style="width: 90px" @change="setLocalThemeConfig">
 | 
			
		||||
							<el-option label="风格1" value="tags-style-one"></el-option>
 | 
			
		||||
						</el-select>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="layout-breadcrumb-seting-bar-flex mt15">
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fiveAnimation') }}</div>
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-value">
 | 
			
		||||
						<el-select v-model="getThemeConfig.animation" placeholder="请选择" size="mini" style="width: 90px" @change="setLocalThemeConfig">
 | 
			
		||||
							<el-option label="slide-right" value="slide-right"></el-option>
 | 
			
		||||
							<el-option label="slide-left" value="slide-left"></el-option>
 | 
			
		||||
							<el-option label="opacitys" value="opacitys"></el-option>
 | 
			
		||||
						</el-select>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="layout-breadcrumb-seting-bar-flex mt15">
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fiveColumnsAsideStyle') }}</div>
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-value">
 | 
			
		||||
						<el-select v-model="getThemeConfig.columnsAsideStyle" placeholder="请选择" size="mini" style="width: 90px" @change="setLocalThemeConfig">
 | 
			
		||||
							<el-option label="圆角" value="columns-round"></el-option>
 | 
			
		||||
							<el-option label="卡片" value="columns-card"></el-option>
 | 
			
		||||
						</el-select>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="layout-breadcrumb-seting-bar-flex mt15 mb28">
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.fiveColumnsAsideLayout') }}</div>
 | 
			
		||||
					<div class="layout-breadcrumb-seting-bar-flex-value">
 | 
			
		||||
						<el-select v-model="getThemeConfig.columnsAsideLayout" placeholder="请选择" size="mini" style="width: 90px" @change="setLocalThemeConfig">
 | 
			
		||||
							<el-option label="水平" value="columns-horizontal"></el-option>
 | 
			
		||||
							<el-option label="垂直" value="columns-vertical"></el-option>
 | 
			
		||||
						</el-select>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
 | 
			
		||||
				<!-- 布局切换 -->
 | 
			
		||||
				<el-divider content-position="left">{{ $t('message.layout.sixTitle') }}</el-divider>
 | 
			
		||||
				<div class="layout-drawer-content-flex">
 | 
			
		||||
					<!-- defaults 布局 -->
 | 
			
		||||
					<div class="layout-drawer-content-item" @click="onSetLayout('defaults')">
 | 
			
		||||
						<section class="el-container el-circular" :class="{ 'drawer-layout-active': getThemeConfig.layout === 'defaults' }">
 | 
			
		||||
							<aside class="el-aside" style="width: 20px"></aside>
 | 
			
		||||
							<section class="el-container is-vertical">
 | 
			
		||||
								<header class="el-header" style="height: 10px"></header>
 | 
			
		||||
								<main class="el-main"></main>
 | 
			
		||||
							</section>
 | 
			
		||||
						</section>
 | 
			
		||||
						<div class="layout-tips-warp" :class="{ 'layout-tips-warp-active': getThemeConfig.layout === 'defaults' }">
 | 
			
		||||
							<div class="layout-tips-box">
 | 
			
		||||
								<p class="layout-tips-txt">{{ $t('message.layout.sixDefaults') }}</p>
 | 
			
		||||
							</div>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
					<!-- classic 布局 -->
 | 
			
		||||
					<div class="layout-drawer-content-item" @click="onSetLayout('classic')">
 | 
			
		||||
						<section class="el-container is-vertical el-circular" :class="{ 'drawer-layout-active': getThemeConfig.layout === 'classic' }">
 | 
			
		||||
							<header class="el-header" style="height: 10px"></header>
 | 
			
		||||
							<section class="el-container">
 | 
			
		||||
								<aside class="el-aside" style="width: 20px"></aside>
 | 
			
		||||
								<section class="el-container is-vertical">
 | 
			
		||||
									<main class="el-main"></main>
 | 
			
		||||
								</section>
 | 
			
		||||
							</section>
 | 
			
		||||
						</section>
 | 
			
		||||
						<div class="layout-tips-warp" :class="{ 'layout-tips-warp-active': getThemeConfig.layout === 'classic' }">
 | 
			
		||||
							<div class="layout-tips-box">
 | 
			
		||||
								<p class="layout-tips-txt">{{ $t('message.layout.sixClassic') }}</p>
 | 
			
		||||
							</div>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
					<!-- transverse 布局 -->
 | 
			
		||||
					<div class="layout-drawer-content-item" @click="onSetLayout('transverse')">
 | 
			
		||||
						<section class="el-container is-vertical el-circular" :class="{ 'drawer-layout-active': getThemeConfig.layout === 'transverse' }">
 | 
			
		||||
							<header class="el-header" style="height: 10px"></header>
 | 
			
		||||
							<section class="el-container">
 | 
			
		||||
								<section class="el-container is-vertical">
 | 
			
		||||
									<main class="el-main"></main>
 | 
			
		||||
								</section>
 | 
			
		||||
							</section>
 | 
			
		||||
						</section>
 | 
			
		||||
						<div class="layout-tips-warp" :class="{ 'layout-tips-warp-active': getThemeConfig.layout === 'transverse' }">
 | 
			
		||||
							<div class="layout-tips-box">
 | 
			
		||||
								<p class="layout-tips-txt">{{ $t('message.layout.sixTransverse') }}</p>
 | 
			
		||||
							</div>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
					<!-- columns 布局 -->
 | 
			
		||||
					<div class="layout-drawer-content-item" @click="onSetLayout('columns')">
 | 
			
		||||
						<section class="el-container el-circular" :class="{ 'drawer-layout-active': getThemeConfig.layout === 'columns' }">
 | 
			
		||||
							<aside class="el-aside-dark" style="width: 10px"></aside>
 | 
			
		||||
							<aside class="el-aside" style="width: 20px"></aside>
 | 
			
		||||
							<section class="el-container is-vertical">
 | 
			
		||||
								<header class="el-header" style="height: 10px"></header>
 | 
			
		||||
								<main class="el-main"></main>
 | 
			
		||||
							</section>
 | 
			
		||||
						</section>
 | 
			
		||||
						<div class="layout-tips-warp" :class="{ 'layout-tips-warp-active': getThemeConfig.layout === 'columns' }">
 | 
			
		||||
							<div class="layout-tips-box">
 | 
			
		||||
								<p class="layout-tips-txt">{{ $t('message.layout.sixColumns') }}</p>
 | 
			
		||||
							</div>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="copy-config">
 | 
			
		||||
					<el-alert :title="$t('message.layout.tipText')" type="warning" :closable="false"> </el-alert>
 | 
			
		||||
					<el-button
 | 
			
		||||
						size="small"
 | 
			
		||||
						class="copy-config-btn"
 | 
			
		||||
						icon="el-icon-document-copy"
 | 
			
		||||
						type="primary"
 | 
			
		||||
						ref="copyConfigBtnRef"
 | 
			
		||||
						@click="onCopyConfigClick"
 | 
			
		||||
						>{{ $t('message.layout.copyText') }}
 | 
			
		||||
					</el-button>
 | 
			
		||||
					<el-button size="small" class="copy-config-btn-reset" type="info" icon="el-icon-refresh-right" @click="onResetConfigClick">
 | 
			
		||||
						{{ $t('message.layout.resetText') }}
 | 
			
		||||
					</el-button>
 | 
			
		||||
				</div>
 | 
			
		||||
			</el-scrollbar>
 | 
			
		||||
		</el-drawer>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import ClipboardJS from 'clipboard';
 | 
			
		||||
import { Local } from '@/utils/storage.js';
 | 
			
		||||
import { useChangeColor } from '@/utils/theme.js';
 | 
			
		||||
import config from '/package.json';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layoutBreadcrumbSeting',
 | 
			
		||||
	computed: {
 | 
			
		||||
		// 获取布局配置信息
 | 
			
		||||
		getThemeConfig() {
 | 
			
		||||
			return this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	created() {
 | 
			
		||||
		// 判断当前布局是否不相同,不相同则初始化当前布局的样式,防止监听窗口大小改变时,布局配置logo、菜单背景等部分布局失效问题
 | 
			
		||||
		if (!Local.get('frequency')) this.initSetLayoutChange();
 | 
			
		||||
		Local.set('frequency', 1);
 | 
			
		||||
		// 监听窗口大小改变,非默认布局,设置成默认布局(适配移动端)
 | 
			
		||||
		this.bus.$on('layoutMobileResize', (res) => {
 | 
			
		||||
			if (this.$store.state.themeConfig.themeConfig.layout === res.layout) return false;
 | 
			
		||||
			this.$store.state.themeConfig.themeConfig.layout = res.layout;
 | 
			
		||||
			this.$store.state.themeConfig.themeConfig.isDrawer = false;
 | 
			
		||||
			this.$store.state.themeConfig.themeConfig.isCollapse = false;
 | 
			
		||||
			this.initSetLayoutChange();
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.initLayoutConfig();
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 全局主题
 | 
			
		||||
		onColorPickerChange() {
 | 
			
		||||
			if (!this.getThemeConfig.primary) return;
 | 
			
		||||
			// 颜色加深
 | 
			
		||||
			document.documentElement.style.setProperty('--prev-color-primary', this.getThemeConfig.primary);
 | 
			
		||||
			// 颜色变浅
 | 
			
		||||
			for (let i = 1; i <= 9; i++) {
 | 
			
		||||
				document.documentElement.style.setProperty(
 | 
			
		||||
					`--prev-color-primary-light-${i}`,
 | 
			
		||||
					`${useChangeColor().getLightColor(this.getThemeConfig.primary, i / 10)}`
 | 
			
		||||
				);
 | 
			
		||||
			}
 | 
			
		||||
			this.setLocalThemeConfig();
 | 
			
		||||
		},
 | 
			
		||||
		// 深色模式
 | 
			
		||||
		onAddDarkChange() {
 | 
			
		||||
			const body = document.documentElement;
 | 
			
		||||
			if (this.getThemeConfig.isIsDark) body.setAttribute('data-theme', 'dark');
 | 
			
		||||
			else body.setAttribute('data-theme', '');
 | 
			
		||||
			this.setLocalThemeConfig();
 | 
			
		||||
		},
 | 
			
		||||
		// 初始化:刷新页面时,设置了值,直接取缓存中的值进行初始化
 | 
			
		||||
		initLayoutConfig() {
 | 
			
		||||
			window.addEventListener('load', () => {
 | 
			
		||||
				// 默认样式
 | 
			
		||||
				this.onColorPickerChange();
 | 
			
		||||
				// 灰色模式
 | 
			
		||||
				if (this.$store.state.themeConfig.themeConfig.isGrayscale) this.onAddFilterChange('grayscale');
 | 
			
		||||
				// 色弱模式
 | 
			
		||||
				if (this.$store.state.themeConfig.themeConfig.isInvert) this.onAddFilterChange('invert');
 | 
			
		||||
				// 深色模式
 | 
			
		||||
				if (this.$store.state.themeConfig.themeConfig.isIsDark) this.onAddDarkChange();
 | 
			
		||||
				// 语言国际化
 | 
			
		||||
				if (Local.get('themeConfigPrev')) this.$i18n.locale = Local.get('themeConfigPrev').globalI18n;
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		// 存储布局配置
 | 
			
		||||
		setLocalThemeConfig() {
 | 
			
		||||
			Local.remove('themeConfigPrev');
 | 
			
		||||
			Local.set('themeConfigPrev', this.$store.state.themeConfig.themeConfig);
 | 
			
		||||
			this.setLocalThemeConfigStyle();
 | 
			
		||||
		},
 | 
			
		||||
		// 存储布局配置全局主题样式(html根标签)
 | 
			
		||||
		setLocalThemeConfigStyle() {
 | 
			
		||||
			Local.set('themeConfigStyle', document.documentElement.style.cssText);
 | 
			
		||||
		},
 | 
			
		||||
		// 布局配置弹窗打开
 | 
			
		||||
		openDrawer() {
 | 
			
		||||
			this.$store.state.themeConfig.themeConfig.isDrawer = true;
 | 
			
		||||
		},
 | 
			
		||||
		// 关闭弹窗时,初始化变量
 | 
			
		||||
		onDrawerClose() {
 | 
			
		||||
			this.$store.state.themeConfig.themeConfig.isDrawer = false;
 | 
			
		||||
			this.setLocalThemeConfig();
 | 
			
		||||
		},
 | 
			
		||||
		// 灰色模式/色弱模式
 | 
			
		||||
		onAddFilterChange(attr) {
 | 
			
		||||
			if (attr === 'grayscale') {
 | 
			
		||||
				if (this.$store.state.themeConfig.themeConfig.isGrayscale) this.$store.state.themeConfig.themeConfig.isInvert = false;
 | 
			
		||||
			} else {
 | 
			
		||||
				if (this.$store.state.themeConfig.themeConfig.isInvert) this.$store.state.themeConfig.themeConfig.isGrayscale = false;
 | 
			
		||||
			}
 | 
			
		||||
			const cssAttr =
 | 
			
		||||
				attr === 'grayscale'
 | 
			
		||||
					? `grayscale(${this.$store.state.themeConfig.themeConfig.isGrayscale ? 1 : 0})`
 | 
			
		||||
					: `invert(${this.$store.state.themeConfig.themeConfig.isInvert ? '80%' : '0%'})`;
 | 
			
		||||
			const appEle = document.body;
 | 
			
		||||
			appEle.setAttribute('style', `filter: ${cssAttr};`);
 | 
			
		||||
			this.setLocalThemeConfig();
 | 
			
		||||
		},
 | 
			
		||||
		// 布局切换
 | 
			
		||||
		onSetLayout(layout) {
 | 
			
		||||
			Local.set('oldLayout', layout);
 | 
			
		||||
			if (this.$store.state.themeConfig.themeConfig.layout === layout) return false;
 | 
			
		||||
			this.$store.state.themeConfig.themeConfig.layout = layout;
 | 
			
		||||
			this.$store.state.themeConfig.themeConfig.isDrawer = false;
 | 
			
		||||
			this.initSetLayoutChange();
 | 
			
		||||
		},
 | 
			
		||||
		// 设置布局切换,重置主题样式
 | 
			
		||||
		initSetLayoutChange() {
 | 
			
		||||
			if (this.$store.state.themeConfig.themeConfig.layout === 'classic') {
 | 
			
		||||
				this.onBgColorPickerChange('menuBar', '#ffffff');
 | 
			
		||||
				this.onBgColorPickerChange('menuBarColor', '#606266');
 | 
			
		||||
				this.onBgColorPickerChange('topBar', '#ffffff');
 | 
			
		||||
				this.onBgColorPickerChange('topBarColor', '#606266');
 | 
			
		||||
			} else if (this.$store.state.themeConfig.themeConfig.layout === 'transverse') {
 | 
			
		||||
				this.onBgColorPickerChange('menuBarColor', '#ffffff');
 | 
			
		||||
				this.onBgColorPickerChange('topBar', '#545c64');
 | 
			
		||||
				this.onBgColorPickerChange('topBarColor', '#ffffff');
 | 
			
		||||
			} else if (this.$store.state.themeConfig.themeConfig.layout === 'columns') {
 | 
			
		||||
				this.onBgColorPickerChange('menuBar', '#ffffff');
 | 
			
		||||
				this.onBgColorPickerChange('menuBarColor', '#606266');
 | 
			
		||||
				this.onBgColorPickerChange('topBar', '#ffffff');
 | 
			
		||||
				this.onBgColorPickerChange('topBarColor', '#606266');
 | 
			
		||||
			} else {
 | 
			
		||||
				this.onBgColorPickerChange('menuBar', '#545c64');
 | 
			
		||||
				this.onBgColorPickerChange('menuBarColor', '#eaeaea');
 | 
			
		||||
				this.onBgColorPickerChange('topBar', '#ffffff');
 | 
			
		||||
				this.onBgColorPickerChange('topBarColor', '#606266');
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		// 菜单 / 顶栏背景等
 | 
			
		||||
		onBgColorPickerChange(bg, rgb) {
 | 
			
		||||
			document.documentElement.style.setProperty(`--prev-bg-${bg}`, rgb);
 | 
			
		||||
			this.setLocalThemeConfigStyle();
 | 
			
		||||
		},
 | 
			
		||||
		// 一键复制配置
 | 
			
		||||
		onCopyConfigClick() {
 | 
			
		||||
			this.$store.state.themeConfig.themeConfig.isDrawer = false;
 | 
			
		||||
			let clipboardJS = new ClipboardJS('.copy-config-btn', {
 | 
			
		||||
				text: () => JSON.stringify(this.$store.state.themeConfig.themeConfig),
 | 
			
		||||
			});
 | 
			
		||||
			clipboardJS.on('success', () => {
 | 
			
		||||
				this.$message.success('配置复制成功');
 | 
			
		||||
				this.isDrawer = false;
 | 
			
		||||
				clipboardJS.destroy();
 | 
			
		||||
			});
 | 
			
		||||
			clipboardJS.on('error', () => {
 | 
			
		||||
				this.$message.error('配置复制失败');
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		// 一键恢复默认
 | 
			
		||||
		onResetConfigClick() {
 | 
			
		||||
			Local.clear();
 | 
			
		||||
			window.location.reload();
 | 
			
		||||
			Local.set('version', config.version);
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.layout-breadcrumb-seting-bar {
 | 
			
		||||
	height: calc(100vh - 50px);
 | 
			
		||||
	padding: 0 15px;
 | 
			
		||||
	::v-deep .el-scrollbar__view {
 | 
			
		||||
		overflow-x: hidden !important;
 | 
			
		||||
	}
 | 
			
		||||
	.layout-breadcrumb-seting-bar-flex {
 | 
			
		||||
		display: flex;
 | 
			
		||||
		align-items: center;
 | 
			
		||||
		&-label {
 | 
			
		||||
			flex: 1;
 | 
			
		||||
			color: var(--prev-color-text-primary);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	.layout-drawer-content-flex {
 | 
			
		||||
		overflow: hidden;
 | 
			
		||||
		display: flex;
 | 
			
		||||
		flex-wrap: wrap;
 | 
			
		||||
		align-content: flex-start;
 | 
			
		||||
		margin: 0 -5px;
 | 
			
		||||
		.layout-drawer-content-item {
 | 
			
		||||
			width: 50%;
 | 
			
		||||
			height: 70px;
 | 
			
		||||
			cursor: pointer;
 | 
			
		||||
			border: 1px solid transparent;
 | 
			
		||||
			position: relative;
 | 
			
		||||
			padding: 5px;
 | 
			
		||||
			.el-container {
 | 
			
		||||
				height: 100%;
 | 
			
		||||
				.el-aside-dark {
 | 
			
		||||
					background-color: var(--prev-color-seting-header);
 | 
			
		||||
				}
 | 
			
		||||
				.el-aside {
 | 
			
		||||
					background-color: var(--prev-color-seting-aside);
 | 
			
		||||
				}
 | 
			
		||||
				.el-header {
 | 
			
		||||
					background-color: var(--prev-color-seting-header);
 | 
			
		||||
				}
 | 
			
		||||
				.el-main {
 | 
			
		||||
					background-color: var(--prev-color-seting-main);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			.el-circular {
 | 
			
		||||
				border-radius: 2px;
 | 
			
		||||
				overflow: hidden;
 | 
			
		||||
				border: 1px solid transparent;
 | 
			
		||||
				transition: all 0.3s ease-in-out;
 | 
			
		||||
			}
 | 
			
		||||
			.drawer-layout-active {
 | 
			
		||||
				border: 1px solid;
 | 
			
		||||
				border-color: var(--prev-color-primary);
 | 
			
		||||
			}
 | 
			
		||||
			.layout-tips-warp,
 | 
			
		||||
			.layout-tips-warp-active {
 | 
			
		||||
				transition: all 0.3s ease-in-out;
 | 
			
		||||
				position: absolute;
 | 
			
		||||
				left: 50%;
 | 
			
		||||
				top: 50%;
 | 
			
		||||
				transform: translate(-50%, -50%);
 | 
			
		||||
				border: 1px solid;
 | 
			
		||||
				border-color: var(--prev-color-primary-light-5);
 | 
			
		||||
				border-radius: 100%;
 | 
			
		||||
				padding: 4px;
 | 
			
		||||
				.layout-tips-box {
 | 
			
		||||
					transition: inherit;
 | 
			
		||||
					width: 30px;
 | 
			
		||||
					height: 30px;
 | 
			
		||||
					z-index: 9;
 | 
			
		||||
					border: 1px solid;
 | 
			
		||||
					border-color: var(--prev-color-primary-light-5);
 | 
			
		||||
					border-radius: 100%;
 | 
			
		||||
					.layout-tips-txt {
 | 
			
		||||
						transition: inherit;
 | 
			
		||||
						position: relative;
 | 
			
		||||
						top: 5px;
 | 
			
		||||
						font-size: 12px;
 | 
			
		||||
						line-height: 1;
 | 
			
		||||
						letter-spacing: 2px;
 | 
			
		||||
						white-space: nowrap;
 | 
			
		||||
						color: var(--prev-color-primary-light-5);
 | 
			
		||||
						text-align: center;
 | 
			
		||||
						transform: rotate(30deg);
 | 
			
		||||
						left: -1px;
 | 
			
		||||
						background-color: var(--prev-color-seting-main);
 | 
			
		||||
						width: 32px;
 | 
			
		||||
						height: 17px;
 | 
			
		||||
						line-height: 17px;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			.layout-tips-warp-active {
 | 
			
		||||
				border: 1px solid;
 | 
			
		||||
				border-color: var(--prev-color-primary);
 | 
			
		||||
				.layout-tips-box {
 | 
			
		||||
					border: 1px solid;
 | 
			
		||||
					border-color: var(--prev-color-primary);
 | 
			
		||||
					.layout-tips-txt {
 | 
			
		||||
						color: var(--prev-color-primary) !important;
 | 
			
		||||
						background-color: var(--prev-color-seting-main) !important;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			&:hover {
 | 
			
		||||
				.el-circular {
 | 
			
		||||
					transition: all 0.3s ease-in-out;
 | 
			
		||||
					border: 1px solid;
 | 
			
		||||
					border-color: var(--prev-color-primary);
 | 
			
		||||
				}
 | 
			
		||||
				.layout-tips-warp {
 | 
			
		||||
					transition: all 0.3s ease-in-out;
 | 
			
		||||
					border-color: var(--prev-color-primary);
 | 
			
		||||
					.layout-tips-box {
 | 
			
		||||
						transition: inherit;
 | 
			
		||||
						border-color: var(--prev-color-primary);
 | 
			
		||||
						.layout-tips-txt {
 | 
			
		||||
							transition: inherit;
 | 
			
		||||
							color: var(--prev-color-primary) !important;
 | 
			
		||||
							background-color: var(--prev-color-seting-main) !important;
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	.copy-config {
 | 
			
		||||
		margin: 10px 0;
 | 
			
		||||
		.copy-config-btn {
 | 
			
		||||
			width: 100%;
 | 
			
		||||
			margin-top: 15px;
 | 
			
		||||
		}
 | 
			
		||||
		.copy-config-btn-reset {
 | 
			
		||||
			width: 100%;
 | 
			
		||||
			margin: 10px 0 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										265
									
								
								src/layout/navBars/breadcrumb/user.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										265
									
								
								src/layout/navBars/breadcrumb/user.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,265 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="layout-navbars-breadcrumb-user" :style="{ flex: layoutUserFlexNum }">
 | 
			
		||||
		<el-dropdown :show-timeout="70" :hide-timeout="50" trigger="click" @command="onComponentSizeChange">
 | 
			
		||||
			<div class="layout-navbars-breadcrumb-user-icon">
 | 
			
		||||
				<i class="iconfont icon-ziti" :title="$t('message.user.title0')"></i>
 | 
			
		||||
			</div>
 | 
			
		||||
			<template #dropdown>
 | 
			
		||||
				<el-dropdown-menu>
 | 
			
		||||
					<el-dropdown-item command="" :disabled="disabledSize === ''">{{ $t('message.user.dropdownDefault') }}</el-dropdown-item>
 | 
			
		||||
					<el-dropdown-item command="medium" :disabled="disabledSize === 'medium'">{{ $t('message.user.dropdownMedium') }}</el-dropdown-item>
 | 
			
		||||
					<el-dropdown-item command="small" :disabled="disabledSize === 'small'">{{ $t('message.user.dropdownSmall') }}</el-dropdown-item>
 | 
			
		||||
					<el-dropdown-item command="mini" :disabled="disabledSize === 'mini'">{{ $t('message.user.dropdownMini') }}</el-dropdown-item>
 | 
			
		||||
				</el-dropdown-menu>
 | 
			
		||||
			</template>
 | 
			
		||||
		</el-dropdown>
 | 
			
		||||
		<el-dropdown :show-timeout="70" :hide-timeout="50" trigger="click" @command="onLanguageChange">
 | 
			
		||||
			<div class="layout-navbars-breadcrumb-user-icon">
 | 
			
		||||
				<i class="iconfont" :class="disabledI18n === 'en' ? 'icon-fuhao-yingwen' : 'icon-fuhao-zhongwen'" :title="$t('message.user.title1')"></i>
 | 
			
		||||
			</div>
 | 
			
		||||
			<el-dropdown-menu slot="dropdown">
 | 
			
		||||
				<el-dropdown-item command="zh-cn" :disabled="disabledI18n === 'zh-cn'">简体中文</el-dropdown-item>
 | 
			
		||||
				<el-dropdown-item command="en" :disabled="disabledI18n === 'en'">English</el-dropdown-item>
 | 
			
		||||
				<el-dropdown-item command="zh-tw" :disabled="disabledI18n === 'zh-tw'">繁體中文</el-dropdown-item>
 | 
			
		||||
			</el-dropdown-menu>
 | 
			
		||||
		</el-dropdown>
 | 
			
		||||
		<div class="layout-navbars-breadcrumb-user-icon" @click="onSearchClick">
 | 
			
		||||
			<i class="el-icon-search" :title="$t('message.user.title2')"></i>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="layout-navbars-breadcrumb-user-icon" @click="onLayoutSetingClick">
 | 
			
		||||
			<i class="icon-skin iconfont" :title="$t('message.user.title3')"></i>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="layout-navbars-breadcrumb-user-icon">
 | 
			
		||||
			<el-popover placement="bottom" trigger="click" v-model="isShowUserNewsPopover" :width="300" popper-class="el-popover-pupop-user-news">
 | 
			
		||||
				<el-badge :is-dot="true" @click.stop="isShowUserNewsPopover = !isShowUserNewsPopover" slot="reference">
 | 
			
		||||
					<i class="el-icon-bell" :title="$t('message.user.title4')"></i>
 | 
			
		||||
				</el-badge>
 | 
			
		||||
				<transition name="el-zoom-in-top">
 | 
			
		||||
					<UserNews v-show="isShowUserNewsPopover" />
 | 
			
		||||
				</transition>
 | 
			
		||||
			</el-popover>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="layout-navbars-breadcrumb-user-icon mr10" @click="onScreenfullClick">
 | 
			
		||||
			<i
 | 
			
		||||
				class="iconfont"
 | 
			
		||||
				:title="isScreenfull ? $t('message.user.title6') : $t('message.user.title5')"
 | 
			
		||||
				:class="!isScreenfull ? 'icon-fullscreen' : 'icon-tuichuquanping'"
 | 
			
		||||
			></i>
 | 
			
		||||
		</div>
 | 
			
		||||
		<el-dropdown :show-timeout="70" :hide-timeout="50" @command="onDropdownCommand">
 | 
			
		||||
			<span class="layout-navbars-breadcrumb-user-link">
 | 
			
		||||
				<img :src="getUserInfos.photo" class="layout-navbars-breadcrumb-user-link-photo mr5" />
 | 
			
		||||
				{{ getUserInfos.userName === '' ? 'test' : getUserInfos.userName }}
 | 
			
		||||
				<i class="el-icon-arrow-down el-icon--right"></i>
 | 
			
		||||
			</span>
 | 
			
		||||
			<el-dropdown-menu slot="dropdown">
 | 
			
		||||
				<el-dropdown-item command="/home">{{ $t('message.user.dropdown1') }}</el-dropdown-item>
 | 
			
		||||
				<el-dropdown-item command="wareHouse">{{ $t('message.user.dropdown6') }}</el-dropdown-item>
 | 
			
		||||
				<el-dropdown-item command="/personal">{{ $t('message.user.dropdown2') }}</el-dropdown-item>
 | 
			
		||||
				<el-dropdown-item command="/404">{{ $t('message.user.dropdown3') }}</el-dropdown-item>
 | 
			
		||||
				<el-dropdown-item command="/401">{{ $t('message.user.dropdown4') }}</el-dropdown-item>
 | 
			
		||||
				<el-dropdown-item divided command="logOut">{{ $t('message.user.dropdown5') }}</el-dropdown-item>
 | 
			
		||||
			</el-dropdown-menu>
 | 
			
		||||
		</el-dropdown>
 | 
			
		||||
		<Search ref="searchRef" />
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import screenfull from 'screenfull';
 | 
			
		||||
import { Session, Local } from '@/utils/storage.js';
 | 
			
		||||
import UserNews from '@/layout/navBars/breadcrumb/userNews.vue';
 | 
			
		||||
import Search from '@/layout/navBars/breadcrumb/search.vue';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layoutBreadcrumbUser',
 | 
			
		||||
	components: { UserNews, Search },
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			isScreenfull: false,
 | 
			
		||||
			isShowUserNewsPopover: false,
 | 
			
		||||
			disabledI18n: 'zh-cn',
 | 
			
		||||
			disabledSize: '',
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		// 获取用户信息
 | 
			
		||||
		getUserInfos() {
 | 
			
		||||
			return this.$store.state.userInfos.userInfos;
 | 
			
		||||
		},
 | 
			
		||||
		// 设置弹性盒子布局 flex
 | 
			
		||||
		layoutUserFlexNum() {
 | 
			
		||||
			let { layout, isClassicSplitMenu } = this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
			let num = '';
 | 
			
		||||
			if (layout === 'defaults' || (layout === 'classic' && !isClassicSplitMenu) || layout === 'columns') num = 1;
 | 
			
		||||
			else num = null;
 | 
			
		||||
			return num;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		if (Local.get('themeConfigPrev')) {
 | 
			
		||||
			this.initI18n();
 | 
			
		||||
			this.initComponentSize();
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 搜索点击
 | 
			
		||||
		onSearchClick() {
 | 
			
		||||
			this.$refs.searchRef.openSearch();
 | 
			
		||||
		},
 | 
			
		||||
		// 布局配置点击
 | 
			
		||||
		onLayoutSetingClick() {
 | 
			
		||||
			this.bus.$emit('openSetingsDrawer');
 | 
			
		||||
		},
 | 
			
		||||
		// 全屏点击
 | 
			
		||||
		onScreenfullClick() {
 | 
			
		||||
			if (!screenfull.isEnabled) {
 | 
			
		||||
				this.$message.warning('暂不不支持全屏');
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			screenfull.toggle();
 | 
			
		||||
			screenfull.on('change', () => {
 | 
			
		||||
				if (screenfull.isFullscreen) this.isScreenfull = true;
 | 
			
		||||
				else this.isScreenfull = false;
 | 
			
		||||
			});
 | 
			
		||||
			// 监听菜单 horizontal.vue 滚动条高度更新
 | 
			
		||||
			this.bus.$emit('updateElScrollBar');
 | 
			
		||||
		},
 | 
			
		||||
		// 组件大小改变
 | 
			
		||||
		onComponentSizeChange(size) {
 | 
			
		||||
			Local.remove('themeConfigPrev');
 | 
			
		||||
			this.$store.state.themeConfig.themeConfig.globalComponentSize = size;
 | 
			
		||||
			Local.set('themeConfigPrev', this.$store.state.themeConfig.themeConfig);
 | 
			
		||||
			this.$ELEMENT.size = size;
 | 
			
		||||
			this.initComponentSize();
 | 
			
		||||
			window.location.reload();
 | 
			
		||||
		},
 | 
			
		||||
		// 语言切换
 | 
			
		||||
		onLanguageChange(lang) {
 | 
			
		||||
			Local.remove('themeConfigPrev');
 | 
			
		||||
			this.$store.state.themeConfig.themeConfig.globalI18n = lang;
 | 
			
		||||
			Local.set('themeConfigPrev', this.$store.state.themeConfig.themeConfig);
 | 
			
		||||
			this.$i18n.locale = lang;
 | 
			
		||||
			this.initI18n();
 | 
			
		||||
		},
 | 
			
		||||
		// 初始化言语国际化
 | 
			
		||||
		initI18n() {
 | 
			
		||||
			switch (Local.get('themeConfigPrev').globalI18n) {
 | 
			
		||||
				case 'zh-cn':
 | 
			
		||||
					this.disabledI18n = 'zh-cn';
 | 
			
		||||
					break;
 | 
			
		||||
				case 'en':
 | 
			
		||||
					this.disabledI18n = 'en';
 | 
			
		||||
					break;
 | 
			
		||||
				case 'zh-tw':
 | 
			
		||||
					this.disabledI18n = 'zh-tw';
 | 
			
		||||
					break;
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		// 初始化全局组件大小
 | 
			
		||||
		initComponentSize() {
 | 
			
		||||
			switch (Local.get('themeConfigPrev').globalComponentSize) {
 | 
			
		||||
				case '':
 | 
			
		||||
					this.disabledSize = '';
 | 
			
		||||
					break;
 | 
			
		||||
				case 'medium':
 | 
			
		||||
					this.disabledSize = 'medium';
 | 
			
		||||
					break;
 | 
			
		||||
				case 'small':
 | 
			
		||||
					this.disabledSize = 'small';
 | 
			
		||||
					break;
 | 
			
		||||
				case 'mini':
 | 
			
		||||
					this.disabledSize = 'mini';
 | 
			
		||||
					break;
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		// `dropdown 下拉菜单` 当前项点击
 | 
			
		||||
		onDropdownCommand(path) {
 | 
			
		||||
			if (path === 'logOut') {
 | 
			
		||||
				setTimeout(() => {
 | 
			
		||||
					this.$msgbox({
 | 
			
		||||
						closeOnClickModal: false,
 | 
			
		||||
						closeOnPressEscape: false,
 | 
			
		||||
						title: this.$t('message.user.logOutTitle'),
 | 
			
		||||
						message: this.$t('message.user.logOutMessage'),
 | 
			
		||||
						showCancelButton: true,
 | 
			
		||||
						confirmButtonText: this.$t('message.user.logOutConfirm'),
 | 
			
		||||
						cancelButtonText: this.$t('message.user.logOutCancel'),
 | 
			
		||||
						beforeClose: (action, instance, done) => {
 | 
			
		||||
							if (action === 'confirm') {
 | 
			
		||||
								instance.confirmButtonLoading = true;
 | 
			
		||||
								instance.confirmButtonText = this.$t('message.user.logOutExit');
 | 
			
		||||
								setTimeout(() => {
 | 
			
		||||
									done();
 | 
			
		||||
									setTimeout(() => {
 | 
			
		||||
										instance.confirmButtonLoading = false;
 | 
			
		||||
									}, 300);
 | 
			
		||||
								}, 700);
 | 
			
		||||
							} else {
 | 
			
		||||
								done();
 | 
			
		||||
							}
 | 
			
		||||
						},
 | 
			
		||||
					})
 | 
			
		||||
						.then(() => {
 | 
			
		||||
							// 清除缓存/token等
 | 
			
		||||
							Session.clear();
 | 
			
		||||
							// 使用 reload 时,不需要调用 resetRoute() 重置路由
 | 
			
		||||
							window.location.reload();
 | 
			
		||||
						})
 | 
			
		||||
						.catch(() => {});
 | 
			
		||||
				}, 150);
 | 
			
		||||
			} else if (path === 'wareHouse') {
 | 
			
		||||
				window.open('https://gitee.com/lyt-top/vue-next-admin');
 | 
			
		||||
			} else {
 | 
			
		||||
				this.$router.push(path);
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.layout-navbars-breadcrumb-user {
 | 
			
		||||
	display: flex;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	justify-content: flex-end;
 | 
			
		||||
	&-link {
 | 
			
		||||
		height: 100%;
 | 
			
		||||
		display: flex;
 | 
			
		||||
		align-items: center;
 | 
			
		||||
		white-space: nowrap;
 | 
			
		||||
		&-photo {
 | 
			
		||||
			width: 25px;
 | 
			
		||||
			height: 25px;
 | 
			
		||||
			border-radius: 100%;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	&-icon {
 | 
			
		||||
		padding: 0 10px;
 | 
			
		||||
		cursor: pointer;
 | 
			
		||||
		color: var(--prev-bg-topBarColor);
 | 
			
		||||
		height: 50px;
 | 
			
		||||
		line-height: 50px;
 | 
			
		||||
		display: flex;
 | 
			
		||||
		align-items: center;
 | 
			
		||||
		&:hover {
 | 
			
		||||
			background: var(--prev-color-hover);
 | 
			
		||||
			i {
 | 
			
		||||
				display: inline-block;
 | 
			
		||||
				animation: logoAnimation 0.3s ease-in-out;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	& ::v-deep .el-dropdown {
 | 
			
		||||
		color: var(--prev-bg-topBarColor);
 | 
			
		||||
	}
 | 
			
		||||
	& ::v-deep .el-badge {
 | 
			
		||||
		height: 40px;
 | 
			
		||||
		line-height: 40px;
 | 
			
		||||
		display: flex;
 | 
			
		||||
		align-items: center;
 | 
			
		||||
	}
 | 
			
		||||
	& ::v-deep .el-badge__content.is-fixed {
 | 
			
		||||
		top: 12px;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										126
									
								
								src/layout/navBars/breadcrumb/userNews.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								src/layout/navBars/breadcrumb/userNews.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,126 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="layout-navbars-breadcrumb-user-news">
 | 
			
		||||
		<div class="head-box">
 | 
			
		||||
			<div class="head-box-title">{{ $t('message.user.newTitle') }}</div>
 | 
			
		||||
			<div class="head-box-btn" v-if="newsList.length > 0" @click="onAllReadClick">{{ $t('message.user.newBtn') }}</div>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="content-box">
 | 
			
		||||
			<template v-if="newsList.length > 0">
 | 
			
		||||
				<div class="content-box-item" v-for="(v, k) in newsList" :key="k">
 | 
			
		||||
					<div>{{ v.label }}</div>
 | 
			
		||||
					<div class="content-box-msg">
 | 
			
		||||
						{{ v.value }}
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="content-box-time">{{ v.time }}</div>
 | 
			
		||||
				</div>
 | 
			
		||||
			</template>
 | 
			
		||||
			<div class="content-box-empty" v-else>
 | 
			
		||||
				<div class="content-box-empty-margin">
 | 
			
		||||
					<i class="el-icon-s-promotion"></i>
 | 
			
		||||
					<div class="mt15">{{ $t('message.user.newDesc') }}</div>
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="foot-box" @click="onGoToGiteeClick" v-if="newsList.length > 0">{{ $t('message.user.newGo') }}</div>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layoutBreadcrumbUserNews',
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			newsList: [
 | 
			
		||||
				{
 | 
			
		||||
					label: '关于版本发布的通知',
 | 
			
		||||
					value: '基于 vue2.x + element ui,正式发布时间:2020年11月15日!',
 | 
			
		||||
					time: '2020-11-15',
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					label: '关于学习交流的通知',
 | 
			
		||||
					value: 'QQ群号码 665452019,欢迎小伙伴入群学习交流探讨!',
 | 
			
		||||
					time: '2020-11-15',
 | 
			
		||||
				},
 | 
			
		||||
			],
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 全部已读点击
 | 
			
		||||
		onAllReadClick() {
 | 
			
		||||
			this.newsList = [];
 | 
			
		||||
		},
 | 
			
		||||
		// 前往通知中心点击
 | 
			
		||||
		onGoToGiteeClick() {
 | 
			
		||||
			window.open('https://gitee.com/lyt-top/vue-next-admin');
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.layout-navbars-breadcrumb-user-news {
 | 
			
		||||
	.head-box {
 | 
			
		||||
		display: flex;
 | 
			
		||||
		border-bottom: 1px solid var(--prev-border-color-lighter);
 | 
			
		||||
		box-sizing: border-box;
 | 
			
		||||
		color: var(--prev-color-text-primary);
 | 
			
		||||
		justify-content: space-between;
 | 
			
		||||
		height: 35px;
 | 
			
		||||
		align-items: center;
 | 
			
		||||
		.head-box-btn {
 | 
			
		||||
			color: var(--prev-color-primary);
 | 
			
		||||
			font-size: 13px;
 | 
			
		||||
			cursor: pointer;
 | 
			
		||||
			opacity: 0.8;
 | 
			
		||||
			&:hover {
 | 
			
		||||
				opacity: 1;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	.content-box {
 | 
			
		||||
		font-size: 13px;
 | 
			
		||||
		.content-box-item {
 | 
			
		||||
			padding-top: 12px;
 | 
			
		||||
			&:last-of-type {
 | 
			
		||||
				padding-bottom: 12px;
 | 
			
		||||
			}
 | 
			
		||||
			.content-box-msg {
 | 
			
		||||
				color: var(--prev-color-text-secondary);
 | 
			
		||||
				margin-top: 5px;
 | 
			
		||||
				margin-bottom: 5px;
 | 
			
		||||
			}
 | 
			
		||||
			.content-box-time {
 | 
			
		||||
				color: var(--prev-color-text-secondary);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		.content-box-empty {
 | 
			
		||||
			height: 260px;
 | 
			
		||||
			display: flex;
 | 
			
		||||
			.content-box-empty-margin {
 | 
			
		||||
				margin: auto;
 | 
			
		||||
				text-align: center;
 | 
			
		||||
				i {
 | 
			
		||||
					font-size: 60px;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	.foot-box {
 | 
			
		||||
		height: 35px;
 | 
			
		||||
		color: var(--prev-color-primary);
 | 
			
		||||
		font-size: 13px;
 | 
			
		||||
		cursor: pointer;
 | 
			
		||||
		opacity: 0.8;
 | 
			
		||||
		display: flex;
 | 
			
		||||
		align-items: center;
 | 
			
		||||
		justify-content: center;
 | 
			
		||||
		border-top: 1px solid var(--prev-border-color-lighter);
 | 
			
		||||
		&:hover {
 | 
			
		||||
			opacity: 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	::v-deep(.el-empty__description p) {
 | 
			
		||||
		font-size: 13px;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										34
									
								
								src/layout/navBars/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/layout/navBars/index.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="layout-navbars-container">
 | 
			
		||||
		<BreadcrumbIndex />
 | 
			
		||||
		<TagsView v-if="setShowTagsView" />
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import BreadcrumbIndex from '@/layout/navBars/breadcrumb/index.vue';
 | 
			
		||||
import TagsView from '@/layout/navBars/tagsView/tagsView.vue';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layoutNavBars',
 | 
			
		||||
	components: { BreadcrumbIndex, TagsView },
 | 
			
		||||
	data() {
 | 
			
		||||
		return {};
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		// 设置是否显示 tagsView
 | 
			
		||||
		setShowTagsView() {
 | 
			
		||||
			let { layout, isTagsview } = this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
			return layout !== 'classic' && isTagsview;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.layout-navbars-container {
 | 
			
		||||
	display: flex;
 | 
			
		||||
	flex-direction: column;
 | 
			
		||||
	width: 100%;
 | 
			
		||||
	height: 100%;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										110
									
								
								src/layout/navBars/tagsView/contextmenu.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								src/layout/navBars/tagsView/contextmenu.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div>
 | 
			
		||||
		<transition name="el-zoom-in-center">
 | 
			
		||||
			<ul
 | 
			
		||||
				class="el-dropdown-menu el-popper el-dropdown-menu--medium custom-contextmenu"
 | 
			
		||||
				:style="`top: ${dropdowns.y}px;left: ${dropdowns.x}px;`"
 | 
			
		||||
				x-placement="bottom-end"
 | 
			
		||||
				id="contextmenu"
 | 
			
		||||
				v-show="isShow"
 | 
			
		||||
			>
 | 
			
		||||
				<li class="el-dropdown-menu__item" v-for="(v, k) in dropdownList" :key="k" @click="onCurrentContextmenuClick(v.id)">
 | 
			
		||||
					<template v-if="!v.affix">
 | 
			
		||||
						<i :class="v.icon"></i>
 | 
			
		||||
						<span>{{ $t(v.txt) }}</span>
 | 
			
		||||
					</template>
 | 
			
		||||
				</li>
 | 
			
		||||
				<div x-arrow class="popper__arrow" :style="{ left: `${arrowLeft}px` }"></div>
 | 
			
		||||
			</ul>
 | 
			
		||||
		</transition>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layoutTagsViewContextmenu',
 | 
			
		||||
	props: {
 | 
			
		||||
		dropdown: {
 | 
			
		||||
			type: Object,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			isShow: false,
 | 
			
		||||
			dropdownList: [
 | 
			
		||||
				{ id: 0, txt: 'message.tagsView.refresh', affix: false, icon: 'el-icon-refresh-right' },
 | 
			
		||||
				{ id: 1, txt: 'message.tagsView.close', affix: false, icon: 'el-icon-close' },
 | 
			
		||||
				{ id: 2, txt: 'message.tagsView.closeOther', affix: false, icon: 'el-icon-circle-close' },
 | 
			
		||||
				{ id: 3, txt: 'message.tagsView.closeAll', affix: false, icon: 'el-icon-folder-delete' },
 | 
			
		||||
			],
 | 
			
		||||
			path: {},
 | 
			
		||||
			arrowLeft: 5,
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		dropdowns() {
 | 
			
		||||
			// 99 为 `Dropdown 下拉菜单` 的宽度
 | 
			
		||||
			if (this.dropdown.x + 99 > document.documentElement.clientWidth) {
 | 
			
		||||
				return {
 | 
			
		||||
					x: document.documentElement.clientWidth - 99 - 5,
 | 
			
		||||
					y: this.dropdown.y,
 | 
			
		||||
				};
 | 
			
		||||
			} else {
 | 
			
		||||
				return this.dropdown;
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		// 监听页面监听进行右键菜单的关闭
 | 
			
		||||
		document.body.addEventListener('click', this.closeContextmenu);
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 当前项菜单点击
 | 
			
		||||
		onCurrentContextmenuClick(id) {
 | 
			
		||||
			this.$emit('currentContextmenuClick', { id, path: this.path });
 | 
			
		||||
		},
 | 
			
		||||
		// 打开右键菜单:判断是否固定,固定则不显示关闭按钮
 | 
			
		||||
		openContextmenu(item) {
 | 
			
		||||
			this.path = item.path;
 | 
			
		||||
			item.meta.isAffix ? (this.dropdownList[1].affix = true) : (this.dropdownList[1].affix = false);
 | 
			
		||||
			this.closeContextmenu();
 | 
			
		||||
			setTimeout(() => {
 | 
			
		||||
				this.isShow = true;
 | 
			
		||||
			}, 80);
 | 
			
		||||
		},
 | 
			
		||||
		// 关闭右键菜单
 | 
			
		||||
		closeContextmenu() {
 | 
			
		||||
			this.isShow = false;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	destroyed() {
 | 
			
		||||
		// 页面卸载时,移除右键菜单监听事件
 | 
			
		||||
		document.body.removeEventListener('click', this.closeContextmenu);
 | 
			
		||||
	},
 | 
			
		||||
	// 监听下拉菜单位置
 | 
			
		||||
	watch: {
 | 
			
		||||
		dropdown: {
 | 
			
		||||
			handler({ x }) {
 | 
			
		||||
				if (x + 99 > document.documentElement.clientWidth) this.arrowLeft = 99 - (document.documentElement.clientWidth - x);
 | 
			
		||||
				else this.arrowLeft = 10;
 | 
			
		||||
			},
 | 
			
		||||
			deep: true,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.custom-contextmenu {
 | 
			
		||||
	transform-origin: center top;
 | 
			
		||||
	z-index: 2190;
 | 
			
		||||
	position: fixed;
 | 
			
		||||
	.el-dropdown-menu__item {
 | 
			
		||||
		font-size: 12px !important;
 | 
			
		||||
		white-space: nowrap;
 | 
			
		||||
		i {
 | 
			
		||||
			font-size: 12px !important;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										404
									
								
								src/layout/navBars/tagsView/tagsView.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										404
									
								
								src/layout/navBars/tagsView/tagsView.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,404 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="layout-navbars-tagsview">
 | 
			
		||||
		<el-scrollbar ref="scrollbarRef" @wheel.native.prevent="onHandleScroll">
 | 
			
		||||
			<ul class="layout-navbars-tagsview-ul" :class="setTagsStyle" ref="tagsUlRef">
 | 
			
		||||
				<li
 | 
			
		||||
					v-for="(v, k) in tagsViewList"
 | 
			
		||||
					:key="k"
 | 
			
		||||
					class="layout-navbars-tagsview-ul-li"
 | 
			
		||||
					:data-name="v.name"
 | 
			
		||||
					:class="{ 'is-active': v.path === tagsRoutePath }"
 | 
			
		||||
					@contextmenu.prevent="onContextmenu(v, $event)"
 | 
			
		||||
					@click="onTagsClick(v, k)"
 | 
			
		||||
					ref="tagsRefs"
 | 
			
		||||
				>
 | 
			
		||||
					<i class="iconfont icon-webicon318 layout-navbars-tagsview-ul-li-iconfont font14" v-if="v.path === tagsRoutePath"></i>
 | 
			
		||||
					<i
 | 
			
		||||
						class="layout-navbars-tagsview-ul-li-iconfont font14 is-tagsview-icon"
 | 
			
		||||
						:class="v.meta.icon"
 | 
			
		||||
						v-if="v.path !== tagsRoutePath && getThemeConfig.isTagsviewIcon"
 | 
			
		||||
					></i>
 | 
			
		||||
					<span>{{ $t(v.meta.title) }}</span>
 | 
			
		||||
					<i
 | 
			
		||||
						class="el-icon-refresh-right layout-navbars-tagsview-ul-li-icon ml5"
 | 
			
		||||
						v-if="v.path === tagsRoutePath"
 | 
			
		||||
						@click.stop="refreshCurrentTagsView(v.path)"
 | 
			
		||||
					></i>
 | 
			
		||||
					<i class="el-icon-close layout-navbars-tagsview-ul-li-icon ml5" v-if="!v.meta.isAffix" @click.stop="closeCurrentTagsView(v.path)"></i>
 | 
			
		||||
				</li>
 | 
			
		||||
			</ul>
 | 
			
		||||
		</el-scrollbar>
 | 
			
		||||
		<Contextmenu :dropdown="tagsDropdown" ref="tagsContextmenu" @currentContextmenuClick="onCurrentContextmenuClick" />
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import Contextmenu from '@/layout/navBars/tagsView/contextmenu';
 | 
			
		||||
import { Session } from '@/utils/storage.js';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'tagsView',
 | 
			
		||||
	components: { Contextmenu },
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			userInfo: {},
 | 
			
		||||
			tagsViewList: [],
 | 
			
		||||
			tagsDropdown: {
 | 
			
		||||
				x: '',
 | 
			
		||||
				y: '',
 | 
			
		||||
			},
 | 
			
		||||
			tagsRefsIndex: 0,
 | 
			
		||||
			tagsRoutePath: this.$route.path,
 | 
			
		||||
			tagsViewRoutesList: [],
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		// 获取布局配置信息
 | 
			
		||||
		getThemeConfig() {
 | 
			
		||||
			return this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
		},
 | 
			
		||||
		// 动态设置 tagsView 风格样式
 | 
			
		||||
		setTagsStyle() {
 | 
			
		||||
			return this.$store.state.themeConfig.themeConfig.tagsStyle;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	created() {
 | 
			
		||||
		// 监听非本页面调用 0 刷新当前,1 关闭当前,2 关闭其它,3 关闭全部
 | 
			
		||||
		this.bus.$on('onCurrentContextmenuClick', (data) => {
 | 
			
		||||
			this.onCurrentContextmenuClick(data);
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.getTagsViewRoutes();
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 获取路由信息
 | 
			
		||||
		getRoutesList() {
 | 
			
		||||
			return this.$store.state.routesList.routesList;
 | 
			
		||||
		},
 | 
			
		||||
		// 当前的 tagsView 项点击时
 | 
			
		||||
		onTagsClick(v, k) {
 | 
			
		||||
			this.tagsRoutePath = v.path;
 | 
			
		||||
			this.tagsRefsIndex = k;
 | 
			
		||||
			this.$router.push(v);
 | 
			
		||||
		},
 | 
			
		||||
		// 获取 tagsView 的下标:用于处理 tagsView 点击时的横向滚动
 | 
			
		||||
		getTagsRefsIndex(path) {
 | 
			
		||||
			if (this.tagsViewList.length > 0) {
 | 
			
		||||
				this.tagsRefsIndex = this.tagsViewList.findIndex((item) => item.path === path);
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		// 鼠标滚轮滚动
 | 
			
		||||
		onHandleScroll(e) {
 | 
			
		||||
			this.$refs.scrollbarRef.$refs.wrap.scrollLeft += e.wheelDelta / 4;
 | 
			
		||||
		},
 | 
			
		||||
		// tagsView 横向滚动
 | 
			
		||||
		tagsViewmoveToCurrentTag() {
 | 
			
		||||
			this.$nextTick(() => {
 | 
			
		||||
				const tagsRefs = this.$refs.tagsRefs;
 | 
			
		||||
				if (tagsRefs.length <= 0) return false;
 | 
			
		||||
				// 当前 li 元素
 | 
			
		||||
				let liDom = tagsRefs[this.tagsRefsIndex];
 | 
			
		||||
				// 当前 li 元素下标
 | 
			
		||||
				let liIndex = this.tagsRefsIndex;
 | 
			
		||||
				// 当前 ul 下 li 元素总长度
 | 
			
		||||
				let liLength = tagsRefs.length;
 | 
			
		||||
				// 最前 li
 | 
			
		||||
				let liFirst = tagsRefs[0];
 | 
			
		||||
				// 最后 li
 | 
			
		||||
				let liLast = tagsRefs[tagsRefs.length - 1];
 | 
			
		||||
				// 当前滚动条的值
 | 
			
		||||
				let scrollRefs = this.$refs.scrollbarRef.$refs.wrap;
 | 
			
		||||
				// 当前滚动条滚动宽度
 | 
			
		||||
				let scrollS = scrollRefs.scrollWidth;
 | 
			
		||||
				// 当前滚动条偏移宽度
 | 
			
		||||
				let offsetW = scrollRefs.offsetWidth;
 | 
			
		||||
				// 当前滚动条偏移距离
 | 
			
		||||
				let scrollL = scrollRefs.scrollLeft;
 | 
			
		||||
				// 上一个 tags li dom
 | 
			
		||||
				let liPrevTag = tagsRefs[this.tagsRefsIndex - 1];
 | 
			
		||||
				// 下一个 tags li dom
 | 
			
		||||
				let liNextTag = tagsRefs[this.tagsRefsIndex + 1];
 | 
			
		||||
				// 上一个 tags li dom 的偏移距离
 | 
			
		||||
				let beforePrevL = '';
 | 
			
		||||
				// 下一个 tags li dom 的偏移距离
 | 
			
		||||
				let afterNextL = '';
 | 
			
		||||
				if (liDom === liFirst) {
 | 
			
		||||
					// 头部
 | 
			
		||||
					scrollRefs.scrollLeft = 0;
 | 
			
		||||
				} else if (liDom === liLast) {
 | 
			
		||||
					// 尾部
 | 
			
		||||
					scrollRefs.scrollLeft = scrollS - offsetW;
 | 
			
		||||
				} else {
 | 
			
		||||
					// 非头/尾部
 | 
			
		||||
					if (liIndex === 0) beforePrevL = liFirst?.offsetLeft - 5;
 | 
			
		||||
					else beforePrevL = liPrevTag?.offsetLeft - 5;
 | 
			
		||||
					if (liIndex === liLength) afterNextL = liLast?.offsetLeft + liLast.offsetWidth + 5;
 | 
			
		||||
					else afterNextL = liNextTag?.offsetLeft + liNextTag.offsetWidth + 5;
 | 
			
		||||
					if (afterNextL > scrollL + offsetW) {
 | 
			
		||||
						scrollRefs.scrollLeft = afterNextL - offsetW;
 | 
			
		||||
					} else if (beforePrevL < scrollL) {
 | 
			
		||||
						scrollRefs.scrollLeft = beforePrevL;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				// 更新滚动条,防止不出现
 | 
			
		||||
				this.updateScrollbar();
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		// 更新滚动条显示
 | 
			
		||||
		updateScrollbar() {
 | 
			
		||||
			this.$refs.scrollbarRef.update();
 | 
			
		||||
		},
 | 
			
		||||
		// 递归查找当前路径下的组件信息
 | 
			
		||||
		filterCurrentMenu(arr, currentPath, callback) {
 | 
			
		||||
			arr.map((item) => {
 | 
			
		||||
				if (item.path === currentPath) {
 | 
			
		||||
					callback(item);
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				item = Object.assign({}, item);
 | 
			
		||||
				if (item.children) {
 | 
			
		||||
					item.children = this.filterCurrentMenu(item.children, currentPath, callback);
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		// 数组对象去重
 | 
			
		||||
		duplicate(arr) {
 | 
			
		||||
			let newobj = {};
 | 
			
		||||
			arr = arr.reduce((preVal, curVal) => {
 | 
			
		||||
				newobj[curVal.path] ? '' : (newobj[curVal.path] = preVal.push(curVal));
 | 
			
		||||
				return preVal;
 | 
			
		||||
			}, []);
 | 
			
		||||
			return arr;
 | 
			
		||||
		},
 | 
			
		||||
		// 获取 vuex 中的 tagsViewRoutes 列表
 | 
			
		||||
		getTagsViewRoutes() {
 | 
			
		||||
			this.tagsRoutePath = this.$route.path;
 | 
			
		||||
			this.tagsViewList = [];
 | 
			
		||||
			if (!this.$store.state.themeConfig.themeConfig.isCacheTagsView) Session.remove('tagsViewList');
 | 
			
		||||
			this.tagsViewRoutesList = this.$store.state.tagsViewRoutes.tagsViewRoutes;
 | 
			
		||||
			this.initTagsViewList();
 | 
			
		||||
		},
 | 
			
		||||
		// 存储 tagsViewList 到浏览器临时缓存中,页面刷新时,保留记录
 | 
			
		||||
		addBrowserSetSession(tagsViewList) {
 | 
			
		||||
			Session.set('tagsViewList', tagsViewList);
 | 
			
		||||
		},
 | 
			
		||||
		// 初始化设置了 tagsView 数据
 | 
			
		||||
		initTagsViewList() {
 | 
			
		||||
			if (Session.get('tagsViewList') && this.$store.state.themeConfig.themeConfig.isCacheTagsView) {
 | 
			
		||||
				this.tagsViewList = Session.get('tagsViewList');
 | 
			
		||||
			} else {
 | 
			
		||||
				this.tagsViewRoutesList.map((v) => {
 | 
			
		||||
					if (v.meta.isAffix && !v.meta.isHide) this.tagsViewList.push({ ...v });
 | 
			
		||||
				});
 | 
			
		||||
				this.addTagsView(this.$route.path);
 | 
			
		||||
			}
 | 
			
		||||
			// 初始化当前元素(li)的下标
 | 
			
		||||
			this.getTagsRefsIndex(this.$route.path);
 | 
			
		||||
			// 添加初始化横向滚动条移动到对应位置
 | 
			
		||||
			this.tagsViewmoveToCurrentTag();
 | 
			
		||||
		},
 | 
			
		||||
		// 添加 tagsView:未设置隐藏(isHide)也添加到在 tagsView 中
 | 
			
		||||
		addTagsView(path, to) {
 | 
			
		||||
			if (this.tagsViewList.some((v) => v.path === path)) return false;
 | 
			
		||||
			const item = this.tagsViewRoutesList.find((v) => v.path === path);
 | 
			
		||||
			if (item.meta.isLink && !item.meta.isIframe) return false;
 | 
			
		||||
			item.query = to?.query ? to?.query : this.$route.query;
 | 
			
		||||
			this.tagsViewList.push({ ...item });
 | 
			
		||||
			this.addBrowserSetSession(this.tagsViewList);
 | 
			
		||||
		},
 | 
			
		||||
		// 右键菜单点击时显示菜单列表
 | 
			
		||||
		onContextmenu(v, e) {
 | 
			
		||||
			let { clientX, clientY } = e;
 | 
			
		||||
			this.tagsDropdown.x = clientX;
 | 
			
		||||
			this.tagsDropdown.y = clientY;
 | 
			
		||||
			this.$refs.tagsContextmenu.openContextmenu(v);
 | 
			
		||||
		},
 | 
			
		||||
		// 当前项右键菜单点击
 | 
			
		||||
		onCurrentContextmenuClick(data) {
 | 
			
		||||
			let { id, path } = data;
 | 
			
		||||
			let currentTag = this.tagsViewList.find((v) => v.path === path);
 | 
			
		||||
			switch (id) {
 | 
			
		||||
				case 0:
 | 
			
		||||
					this.refreshCurrentTagsView(path);
 | 
			
		||||
					this.$router.push({ path, query: currentTag.query });
 | 
			
		||||
					break;
 | 
			
		||||
				case 1:
 | 
			
		||||
					this.closeCurrentTagsView(path);
 | 
			
		||||
					break;
 | 
			
		||||
				case 2:
 | 
			
		||||
					this.$router.push({ path, query: currentTag.query });
 | 
			
		||||
					this.closeOtherTagsView(path);
 | 
			
		||||
					break;
 | 
			
		||||
				case 3:
 | 
			
		||||
					this.closeAllTagsView(path);
 | 
			
		||||
					break;
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		// 1、刷新当前 tagsView:
 | 
			
		||||
		refreshCurrentTagsView(path) {
 | 
			
		||||
			this.bus.$emit('onTagsViewRefreshRouterView', path);
 | 
			
		||||
		},
 | 
			
		||||
		// 2、关闭当前 tagsView:当前项 `tags-view` icon 关闭时点击,如果是设置了固定的(isAffix),不可以关闭
 | 
			
		||||
		closeCurrentTagsView(path) {
 | 
			
		||||
			this.tagsViewList.map((v, k, arr) => {
 | 
			
		||||
				if (!v.meta.isAffix) {
 | 
			
		||||
					if (v.path === path) {
 | 
			
		||||
						this.tagsViewList.splice(k, 1);
 | 
			
		||||
						setTimeout(() => {
 | 
			
		||||
							// 最后一个
 | 
			
		||||
							if (this.tagsViewList.length === k) this.$router.push({ path: arr[arr.length - 1].path, query: arr[arr.length - 1].query });
 | 
			
		||||
							// 否则,跳转到下一个
 | 
			
		||||
							else this.$router.push({ path: arr[k].path, query: arr[k].query });
 | 
			
		||||
						}, 0);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
			this.addBrowserSetSession(this.tagsViewList);
 | 
			
		||||
		},
 | 
			
		||||
		// 3、关闭其它 tagsView:如果是设置了固定的(isAffix),不进行关闭
 | 
			
		||||
		closeOtherTagsView(path) {
 | 
			
		||||
			this.tagsViewList = [];
 | 
			
		||||
			this.tagsViewRoutesList.map((v) => {
 | 
			
		||||
				if (v.meta.isAffix && !v.meta.isHide) this.tagsViewList.push({ ...v });
 | 
			
		||||
			});
 | 
			
		||||
			this.addTagsView(path);
 | 
			
		||||
		},
 | 
			
		||||
		// 4、关闭全部 tagsView:如果是设置了固定的(isAffix),不进行关闭
 | 
			
		||||
		closeAllTagsView(path) {
 | 
			
		||||
			this.tagsViewList = [];
 | 
			
		||||
			this.tagsViewRoutesList.map((v) => {
 | 
			
		||||
				if (v.meta.isAffix && !v.meta.isHide) {
 | 
			
		||||
					this.tagsViewList.push({ ...v });
 | 
			
		||||
					if (this.tagsViewList.some((v) => v.path === path)) this.$router.push({ path, query: this.$route.query });
 | 
			
		||||
					else this.$router.push({ path: v.path, query: this.$route.query });
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
			this.addBrowserSetSession(this.tagsViewList);
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	watch: {
 | 
			
		||||
		// 监听路由变化
 | 
			
		||||
		$route: {
 | 
			
		||||
			handler(to) {
 | 
			
		||||
				this.tagsRoutePath = to.path;
 | 
			
		||||
				this.addTagsView(to.path, to);
 | 
			
		||||
				this.getTagsRefsIndex(to.path);
 | 
			
		||||
				this.tagsViewmoveToCurrentTag();
 | 
			
		||||
			},
 | 
			
		||||
			deep: true,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	destroyed() {
 | 
			
		||||
		// 取消非本页面调用监听(fun/tagsView)
 | 
			
		||||
		this.bus.$off('onCurrentContextmenuClick');
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.layout-navbars-tagsview {
 | 
			
		||||
	flex: 1;
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	border-bottom: 1px solid var(--prev-border-color-lighter);
 | 
			
		||||
	& ::v-deep .is-vertical {
 | 
			
		||||
		display: none !important;
 | 
			
		||||
	}
 | 
			
		||||
	&-ul {
 | 
			
		||||
		list-style: none;
 | 
			
		||||
		margin: 0;
 | 
			
		||||
		padding: 0;
 | 
			
		||||
		width: 100%;
 | 
			
		||||
		height: 34px;
 | 
			
		||||
		display: flex;
 | 
			
		||||
		align-items: center;
 | 
			
		||||
		white-space: nowrap;
 | 
			
		||||
		color: var(--prev-color-text-regular);
 | 
			
		||||
		font-size: 12px;
 | 
			
		||||
		padding: 0 15px;
 | 
			
		||||
		&-li {
 | 
			
		||||
			height: 26px;
 | 
			
		||||
			line-height: 26px;
 | 
			
		||||
			display: flex;
 | 
			
		||||
			align-items: center;
 | 
			
		||||
			border: 1px solid var(--prev-border-color-lighter);
 | 
			
		||||
			padding: 0 12px 0 15px;
 | 
			
		||||
			margin-right: 5px;
 | 
			
		||||
			border-radius: 2px;
 | 
			
		||||
			position: relative;
 | 
			
		||||
			z-index: 0;
 | 
			
		||||
			cursor: pointer;
 | 
			
		||||
			justify-content: space-between;
 | 
			
		||||
			transition: all 0.3s cubic-bezier(0.2, 1, 0.3, 1);
 | 
			
		||||
			&::before {
 | 
			
		||||
				content: '';
 | 
			
		||||
				position: absolute;
 | 
			
		||||
				top: 0;
 | 
			
		||||
				right: 0;
 | 
			
		||||
				bottom: 0;
 | 
			
		||||
				left: 0;
 | 
			
		||||
				background: var(--prev-color-primary);
 | 
			
		||||
				z-index: -1;
 | 
			
		||||
				opacity: 0;
 | 
			
		||||
				transform: scale3d(0.7, 1, 1);
 | 
			
		||||
				transition: transform 0.3s, opacity 0.3s;
 | 
			
		||||
				transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
 | 
			
		||||
			}
 | 
			
		||||
			&:hover {
 | 
			
		||||
				color: var(--prev-color-text-white);
 | 
			
		||||
				transition: all 0.3s cubic-bezier(0.2, 1, 0.3, 1);
 | 
			
		||||
				border-color: transparent;
 | 
			
		||||
				&::before {
 | 
			
		||||
					opacity: 1;
 | 
			
		||||
					transform: translate3d(0, 0, 0);
 | 
			
		||||
					border-radius: 2px;
 | 
			
		||||
				}
 | 
			
		||||
				.is-tagsview-icon {
 | 
			
		||||
					color: var(--prev-color-text-white);
 | 
			
		||||
					transition: all 0.3s cubic-bezier(0.2, 1, 0.3, 1);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			&-iconfont {
 | 
			
		||||
				position: relative;
 | 
			
		||||
				left: -5px;
 | 
			
		||||
				top: 1px;
 | 
			
		||||
				color: var(--prev-color-text-white);
 | 
			
		||||
			}
 | 
			
		||||
			&-icon {
 | 
			
		||||
				border-radius: 100%;
 | 
			
		||||
				position: relative;
 | 
			
		||||
				height: 14px;
 | 
			
		||||
				width: 14px;
 | 
			
		||||
				text-align: center;
 | 
			
		||||
				line-height: 14px;
 | 
			
		||||
				top: 1px;
 | 
			
		||||
			}
 | 
			
		||||
			.is-tagsview-icon {
 | 
			
		||||
				color: var(--prev-color-text-regular);
 | 
			
		||||
				transition: all 0.3s cubic-bezier(0.2, 1, 0.3, 1);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		.is-active {
 | 
			
		||||
			color: var(--prev-color-text-white);
 | 
			
		||||
			transition: all 0.3s cubic-bezier(0.2, 1, 0.3, 1);
 | 
			
		||||
			border-color: transparent;
 | 
			
		||||
			&::before {
 | 
			
		||||
				opacity: 1;
 | 
			
		||||
				transform: translate3d(0, 0, 0);
 | 
			
		||||
				border-radius: 2px;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	& ::-webkit-scrollbar {
 | 
			
		||||
		display: none !important;
 | 
			
		||||
	}
 | 
			
		||||
	// // 风格2
 | 
			
		||||
	// .tags-style-two {
 | 
			
		||||
	// }
 | 
			
		||||
	// // 风格3
 | 
			
		||||
	// .tags-style-three {
 | 
			
		||||
	// }
 | 
			
		||||
	// // 风格4
 | 
			
		||||
	// .tags-style-four {
 | 
			
		||||
	// }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										138
									
								
								src/layout/navMenu/horizontal.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								src/layout/navMenu/horizontal.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,138 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="el-menu-horizontal-warp">
 | 
			
		||||
		<el-scrollbar @wheel.native.prevent="onElMenuHorizontalScroll" ref="elMenuHorizontalScrollRef">
 | 
			
		||||
			<el-menu router :default-active="defaultActive" background-color="transparent" mode="horizontal" @select="onHorizontalSelect">
 | 
			
		||||
				<template v-for="val in menuList">
 | 
			
		||||
					<el-submenu :index="val.path" v-if="val.children && val.children.length > 0" :key="val.path">
 | 
			
		||||
						<template slot="title">
 | 
			
		||||
							<i :class="val.meta.icon ? val.meta.icon : ''"></i>
 | 
			
		||||
							<span>{{ $t(val.meta.title) }}</span>
 | 
			
		||||
						</template>
 | 
			
		||||
						<SubItem :chil="val.children" />
 | 
			
		||||
					</el-submenu>
 | 
			
		||||
					<template v-else>
 | 
			
		||||
						<el-menu-item :index="val.path" :key="val.path">
 | 
			
		||||
							<template slot="title" v-if="!val.meta.isLink || (val.meta.isLink && val.meta.isIframe)">
 | 
			
		||||
								<i :class="val.meta.icon ? val.meta.icon : ''"></i>
 | 
			
		||||
								{{ $t(val.meta.title) }}
 | 
			
		||||
							</template>
 | 
			
		||||
							<template slot="title" v-else>
 | 
			
		||||
								<a :href="val.meta.isLink" target="_blank">
 | 
			
		||||
									<i :class="val.meta.icon ? val.meta.icon : ''"></i>
 | 
			
		||||
									{{ $t(val.meta.title) }}
 | 
			
		||||
								</a>
 | 
			
		||||
							</template>
 | 
			
		||||
						</el-menu-item>
 | 
			
		||||
					</template>
 | 
			
		||||
				</template>
 | 
			
		||||
			</el-menu>
 | 
			
		||||
		</el-scrollbar>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import SubItem from '@/layout/navMenu/subItem.vue';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'navMenuHorizontal',
 | 
			
		||||
	components: { SubItem },
 | 
			
		||||
	props: {
 | 
			
		||||
		menuList: {
 | 
			
		||||
			type: Array,
 | 
			
		||||
			default: () => [],
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			defaultActive: null,
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.initElMenuOffsetLeft();
 | 
			
		||||
		this.setCurrentRouterHighlight(this.$route.path);
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 设置横向滚动条可以鼠标滚轮滚动
 | 
			
		||||
		onElMenuHorizontalScroll(e) {
 | 
			
		||||
			const eventDelta = e.wheelDelta || -e.deltaY * 40;
 | 
			
		||||
			this.$refs.elMenuHorizontalScrollRef.$refs.wrap.scrollLeft = this.$refs.elMenuHorizontalScrollRef.$refs.wrap.scrollLeft + eventDelta / 4;
 | 
			
		||||
		},
 | 
			
		||||
		// 初始化数据,页面刷新时,滚动条滚动到对应位置
 | 
			
		||||
		initElMenuOffsetLeft() {
 | 
			
		||||
			this.$nextTick(() => {
 | 
			
		||||
				let els = document.querySelector('.el-menu.el-menu--horizontal li.is-active');
 | 
			
		||||
				if (!els) return false;
 | 
			
		||||
				this.$refs.elMenuHorizontalScrollRef.$refs.wrap.scrollLeft = els.offsetLeft;
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		// 路由过滤递归函数
 | 
			
		||||
		filterRoutesFun(arr) {
 | 
			
		||||
			return arr
 | 
			
		||||
				.filter((item) => !item.meta.isHide)
 | 
			
		||||
				.map((item) => {
 | 
			
		||||
					item = Object.assign({}, item);
 | 
			
		||||
					if (item.children) item.children = this.filterRoutesFun(item.children);
 | 
			
		||||
					return item;
 | 
			
		||||
				});
 | 
			
		||||
		},
 | 
			
		||||
		// 传送当前子级数据到菜单中
 | 
			
		||||
		setSendClassicChildren(path) {
 | 
			
		||||
			const currentPathSplit = path.split('/');
 | 
			
		||||
			let currentData = {};
 | 
			
		||||
			this.filterRoutesFun(this.$store.state.routesList.routesList).map((v, k) => {
 | 
			
		||||
				if (v.path === `/${currentPathSplit[1]}`) {
 | 
			
		||||
					v['k'] = k;
 | 
			
		||||
					currentData['item'] = [{ ...v }];
 | 
			
		||||
					currentData['children'] = [{ ...v }];
 | 
			
		||||
					if (v.children) currentData['children'] = v.children;
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
			return currentData;
 | 
			
		||||
		},
 | 
			
		||||
		// 菜单激活回调
 | 
			
		||||
		onHorizontalSelect(path) {
 | 
			
		||||
			this.bus.$emit('setSendClassicChildren', this.setSendClassicChildren(path));
 | 
			
		||||
		},
 | 
			
		||||
		// 设置页面当前路由高亮
 | 
			
		||||
		setCurrentRouterHighlight(path) {
 | 
			
		||||
			const currentPathSplit = path.split('/');
 | 
			
		||||
			if (this.$store.state.themeConfig.themeConfig.layout === 'classic') {
 | 
			
		||||
				this.defaultActive = `/${currentPathSplit[1]}`;
 | 
			
		||||
			} else {
 | 
			
		||||
				this.defaultActive = path;
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	watch: {
 | 
			
		||||
		// 监听路由的变化
 | 
			
		||||
		$route: {
 | 
			
		||||
			handler(to) {
 | 
			
		||||
				this.setCurrentRouterHighlight(to.path);
 | 
			
		||||
			},
 | 
			
		||||
			deep: true,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.el-menu-horizontal-warp {
 | 
			
		||||
	flex: 1;
 | 
			
		||||
	overflow: hidden;
 | 
			
		||||
	margin-right: 30px;
 | 
			
		||||
	::v-deep .el-scrollbar__bar.is-vertical {
 | 
			
		||||
		display: none;
 | 
			
		||||
	}
 | 
			
		||||
	::v-deep .el-scrollbar__wrap {
 | 
			
		||||
		overflow-y: hidden !important;
 | 
			
		||||
	}
 | 
			
		||||
	::v-deep a {
 | 
			
		||||
		width: 100%;
 | 
			
		||||
	}
 | 
			
		||||
	.el-menu.el-menu--horizontal {
 | 
			
		||||
		display: flex;
 | 
			
		||||
		height: 100%;
 | 
			
		||||
		width: 100%;
 | 
			
		||||
		box-sizing: border-box;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										41
									
								
								src/layout/navMenu/subItem.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/layout/navMenu/subItem.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div>
 | 
			
		||||
		<template v-for="val in chil">
 | 
			
		||||
			<el-submenu :index="val.path" :key="val.path" v-if="val.children && val.children.length > 0">
 | 
			
		||||
				<template slot="title">
 | 
			
		||||
					<i :class="val.meta.icon"></i>
 | 
			
		||||
					<span>{{ $t(val.meta.title) }}</span>
 | 
			
		||||
				</template>
 | 
			
		||||
				<sub-item :chil="val.children" />
 | 
			
		||||
			</el-submenu>
 | 
			
		||||
			<template v-else>
 | 
			
		||||
				<el-menu-item :index="val.path" :key="val.path">
 | 
			
		||||
					<template v-if="!val.meta.isLink || (val.meta.isLink && val.meta.isIframe)">
 | 
			
		||||
						<i :class="val.meta.icon ? val.meta.icon : ''"></i>
 | 
			
		||||
						<span>{{ $t(val.meta.title) }}</span>
 | 
			
		||||
					</template>
 | 
			
		||||
					<template v-else>
 | 
			
		||||
						<a :href="val.meta.isLink" target="_blank">
 | 
			
		||||
							<i :class="val.meta.icon ? val.meta.icon : ''"></i>
 | 
			
		||||
							{{ $t(val.meta.title) }}
 | 
			
		||||
						</a>
 | 
			
		||||
					</template>
 | 
			
		||||
				</el-menu-item>
 | 
			
		||||
			</template>
 | 
			
		||||
		</template>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'subItem',
 | 
			
		||||
	props: {
 | 
			
		||||
		chil: {
 | 
			
		||||
			type: Array,
 | 
			
		||||
			default() {
 | 
			
		||||
				return [];
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										73
									
								
								src/layout/navMenu/vertical.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								src/layout/navMenu/vertical.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<el-menu
 | 
			
		||||
		router
 | 
			
		||||
		background-color="transparent"
 | 
			
		||||
		:default-active="defaultActive"
 | 
			
		||||
		:collapse="setIsCollapse"
 | 
			
		||||
		:unique-opened="getThemeConfig.isUniqueOpened"
 | 
			
		||||
		:collapse-transition="false"
 | 
			
		||||
	>
 | 
			
		||||
		<template v-for="val in menuList">
 | 
			
		||||
			<el-submenu :index="val.path" v-if="val.children && val.children.length > 0" :key="val.path">
 | 
			
		||||
				<template slot="title">
 | 
			
		||||
					<i :class="val.meta.icon ? val.meta.icon : ''"></i>
 | 
			
		||||
					<span>{{ $t(val.meta.title) }}</span>
 | 
			
		||||
				</template>
 | 
			
		||||
				<SubItem :chil="val.children" />
 | 
			
		||||
			</el-submenu>
 | 
			
		||||
			<template v-else>
 | 
			
		||||
				<el-menu-item :index="val.path" :key="val.path">
 | 
			
		||||
					<i :class="val.meta.icon ? val.meta.icon : ''"></i>
 | 
			
		||||
					<template slot="title" v-if="!val.meta.isLink || (val.meta.isLink && val.meta.isIframe)">
 | 
			
		||||
						<span>{{ $t(val.meta.title) }}</span>
 | 
			
		||||
					</template>
 | 
			
		||||
					<template slot="title" v-else>
 | 
			
		||||
						<a :href="val.meta.isLink" target="_blank">{{ $t(val.meta.title) }}</a>
 | 
			
		||||
					</template>
 | 
			
		||||
				</el-menu-item>
 | 
			
		||||
			</template>
 | 
			
		||||
		</template>
 | 
			
		||||
	</el-menu>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import SubItem from '@/layout/navMenu/subItem.vue';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'navMenuVertical',
 | 
			
		||||
	components: { SubItem },
 | 
			
		||||
	props: {
 | 
			
		||||
		menuList: {
 | 
			
		||||
			type: Array,
 | 
			
		||||
			default() {
 | 
			
		||||
				return [];
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			defaultActive: this.$route.path,
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		// 获取布局配置信息
 | 
			
		||||
		getThemeConfig() {
 | 
			
		||||
			return this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
		},
 | 
			
		||||
		// 设置左侧菜单是否展开/收起
 | 
			
		||||
		setIsCollapse() {
 | 
			
		||||
			return document.body.clientWidth < 1000 ? false : this.$store.state.themeConfig.themeConfig.isCollapse;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	watch: {
 | 
			
		||||
		// 监听路由的变化
 | 
			
		||||
		$route: {
 | 
			
		||||
			handler(to) {
 | 
			
		||||
				this.defaultActive = to.path;
 | 
			
		||||
				const clientWidth = document.body.clientWidth;
 | 
			
		||||
				if (clientWidth < 1000) this.$store.state.themeConfig.themeConfig.isCollapse = false;
 | 
			
		||||
			},
 | 
			
		||||
			deep: true,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										46
									
								
								src/layout/routerView/iframes.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/layout/routerView/iframes.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div>
 | 
			
		||||
		<div class="layout-view-bg-white flex h100" v-loading="iframeLoading">
 | 
			
		||||
			<iframe :src="meta.isLink" frameborder="0" height="100%" width="100%" id="iframe"></iframe>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layoutIfameView',
 | 
			
		||||
	props: {
 | 
			
		||||
		meta: {
 | 
			
		||||
			type: Object,
 | 
			
		||||
			default: () => {},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			iframeLoading: true,
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	created() {
 | 
			
		||||
		this.bus.$on('onTagsViewRefreshRouterView', (path) => {
 | 
			
		||||
			if (this.$route.path !== path) return false;
 | 
			
		||||
			this.$emit('getCurrentRouteMeta');
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.initIframeLoad();
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 初始化页面加载 loading
 | 
			
		||||
		initIframeLoad() {
 | 
			
		||||
			this.$nextTick(() => {
 | 
			
		||||
				this.iframeLoading = true;
 | 
			
		||||
				const iframe = document.getElementById('iframe');
 | 
			
		||||
				if (!iframe) return false;
 | 
			
		||||
				iframe.onload = () => {
 | 
			
		||||
					this.iframeLoading = false;
 | 
			
		||||
				};
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										83
									
								
								src/layout/routerView/link.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/layout/routerView/link.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="layout-scrollbar layout-link-container">
 | 
			
		||||
		<div class="layout-view-bg-white flex layout-view-link">
 | 
			
		||||
			<div class="layout-link-warp">
 | 
			
		||||
				<i class="layout-link-icon iconfont icon-xingqiu"></i>
 | 
			
		||||
				<div class="layout-link-msg">页面 "{{ $t(meta.title) }}" 已在新窗口中打开</div>
 | 
			
		||||
				<el-button class="mt30" round size="small" @click="onGotoFullPage">
 | 
			
		||||
					<i class="iconfont icon-lianjie"></i>
 | 
			
		||||
					<span>立即前往体验</span>
 | 
			
		||||
				</el-button>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { verifyUrl } from '@/utils/toolsValidate';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'layoutLinkView',
 | 
			
		||||
	props: {
 | 
			
		||||
		meta: {
 | 
			
		||||
			type: Object,
 | 
			
		||||
			default: () => {},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 立即前往
 | 
			
		||||
		onGotoFullPage() {
 | 
			
		||||
			const { origin, pathname } = window.location;
 | 
			
		||||
			if (verifyUrl(this.meta.isLink)) window.open(this.meta.isLink);
 | 
			
		||||
			else window.open(`${origin}${pathname}#${this.meta.isLink}`);
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.layout-link-container {
 | 
			
		||||
	.layout-link-warp {
 | 
			
		||||
		margin: auto;
 | 
			
		||||
		display: flex;
 | 
			
		||||
		flex-direction: column;
 | 
			
		||||
		align-items: center;
 | 
			
		||||
		justify-content: center;
 | 
			
		||||
		i.layout-link-icon {
 | 
			
		||||
			position: relative;
 | 
			
		||||
			font-size: 100px;
 | 
			
		||||
			color: var(--prev-color-primary);
 | 
			
		||||
			&::after {
 | 
			
		||||
				content: '';
 | 
			
		||||
				position: absolute;
 | 
			
		||||
				left: 50px;
 | 
			
		||||
				top: 0;
 | 
			
		||||
				width: 15px;
 | 
			
		||||
				height: 100px;
 | 
			
		||||
				background: linear-gradient(
 | 
			
		||||
					rgba(255, 255, 255, 0.01),
 | 
			
		||||
					rgba(255, 255, 255, 0.01),
 | 
			
		||||
					rgba(255, 255, 255, 0.01),
 | 
			
		||||
					rgba(255, 255, 255, 0.05),
 | 
			
		||||
					rgba(255, 255, 255, 0.05),
 | 
			
		||||
					rgba(255, 255, 255, 0.05),
 | 
			
		||||
					rgba(235, 255, 255, 0.5),
 | 
			
		||||
					rgba(255, 255, 255, 0.05),
 | 
			
		||||
					rgba(255, 255, 255, 0.05),
 | 
			
		||||
					rgba(255, 255, 255, 0.05),
 | 
			
		||||
					rgba(255, 255, 255, 0.01),
 | 
			
		||||
					rgba(255, 255, 255, 0.01),
 | 
			
		||||
					rgba(255, 255, 255, 0.01)
 | 
			
		||||
				);
 | 
			
		||||
				transform: rotate(-15deg);
 | 
			
		||||
				animation: toRight 5s linear infinite;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		.layout-link-msg {
 | 
			
		||||
			font-size: 12px;
 | 
			
		||||
			color: var(--prev-bg-topBarColor);
 | 
			
		||||
			opacity: 0.7;
 | 
			
		||||
			margin-top: 15px;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										47
									
								
								src/layout/routerView/parent.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/layout/routerView/parent.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="h100">
 | 
			
		||||
		<transition :name="setTransitionName" mode="out-in">
 | 
			
		||||
			<keep-alive :include="keepAliveNameList">
 | 
			
		||||
				<router-view :key="refreshRouterViewKey" />
 | 
			
		||||
			</keep-alive>
 | 
			
		||||
		</transition>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'parent',
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			refreshRouterViewKey: null,
 | 
			
		||||
			keepAliveNameList: [],
 | 
			
		||||
			keepAliveNameNewList: [],
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	created() {
 | 
			
		||||
		// 页面加载前,处理缓存,页面刷新时路由缓存处理
 | 
			
		||||
		this.keepAliveNameList = this.getKeepAliveNames();
 | 
			
		||||
		this.bus.$on('onTagsViewRefreshRouterView', (path) => {
 | 
			
		||||
			if (this.$route.path !== path) return false;
 | 
			
		||||
			this.keepAliveNameList = this.getKeepAliveNames().filter((name) => this.$route.name !== name);
 | 
			
		||||
			this.refreshRouterViewKey = this.$route.path;
 | 
			
		||||
			this.$nextTick(() => {
 | 
			
		||||
				this.refreshRouterViewKey = null;
 | 
			
		||||
				this.keepAliveNameList = this.getKeepAliveNames();
 | 
			
		||||
			});
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		// 设置主界面切换动画
 | 
			
		||||
		setTransitionName() {
 | 
			
		||||
			return this.$store.state.themeConfig.themeConfig.animation;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 获取路由缓存列表(name),默认路由全部缓存
 | 
			
		||||
		getKeepAliveNames() {
 | 
			
		||||
			return this.$store.state.keepAliveNames.keepAliveNames;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										149
									
								
								src/layout/upgrade/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								src/layout/upgrade/index.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,149 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="upgrade-dialog">
 | 
			
		||||
		<el-dialog
 | 
			
		||||
			:visible.sync="isUpgrade"
 | 
			
		||||
			width="300px"
 | 
			
		||||
			destroy-on-close
 | 
			
		||||
			:show-close="false"
 | 
			
		||||
			:close-on-click-modal="false"
 | 
			
		||||
			:close-on-press-escape="false"
 | 
			
		||||
		>
 | 
			
		||||
			<div class="upgrade-title">
 | 
			
		||||
				<div class="upgrade-title-warp">
 | 
			
		||||
					<span class="upgrade-title-warp-txt">{{ $t('message.upgrade.title') }}</span>
 | 
			
		||||
					<span class="upgrade-title-warp-version">v{{ version }}</span>
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="upgrade-content">
 | 
			
		||||
				{{ getThemeConfig.globalTitle }} {{ $t('message.upgrade.msg') }}
 | 
			
		||||
				<div class="mt5">
 | 
			
		||||
					<el-link type="primary" class="font12" href="https://gitee.com/lyt-top/vue-next-admin/blob/vue-prev-admin/CHANGELOG.md" target="_black">
 | 
			
		||||
						CHANGELOG.md
 | 
			
		||||
					</el-link>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="upgrade-content-desc mt5">{{ $t('message.upgrade.desc') }}</div>
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="upgrade-btn">
 | 
			
		||||
				<el-button round size="small" @click="onCancel">{{ $t('message.upgrade.btnOne') }}</el-button>
 | 
			
		||||
				<el-button type="primary" round size="small" @click="onUpgrade" :loading="isLoading">{{ btnTxt }}</el-button>
 | 
			
		||||
			</div>
 | 
			
		||||
		</el-dialog>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { Local } from '@/utils/storage';
 | 
			
		||||
import config from '/package.json';
 | 
			
		||||
export default {
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			isUpgrade: false,
 | 
			
		||||
			version: config.version,
 | 
			
		||||
			isLoading: false,
 | 
			
		||||
			btnTxt: '',
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		// 获取布局配置信息
 | 
			
		||||
		getThemeConfig() {
 | 
			
		||||
			return this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 残忍拒绝
 | 
			
		||||
		onCancel() {
 | 
			
		||||
			this.isUpgrade = false;
 | 
			
		||||
		},
 | 
			
		||||
		// 马上更新
 | 
			
		||||
		onUpgrade() {
 | 
			
		||||
			this.isLoading = true;
 | 
			
		||||
			this.btnTxt = this.$t('message.upgrade.btnTwoLoading');
 | 
			
		||||
			setTimeout(() => {
 | 
			
		||||
				Local.clear();
 | 
			
		||||
				window.location.reload();
 | 
			
		||||
				Local.set('version', this.version);
 | 
			
		||||
			}, 2000);
 | 
			
		||||
		},
 | 
			
		||||
		// 延迟显示,防止刷新时界面显示太快
 | 
			
		||||
		delayShow() {
 | 
			
		||||
			setTimeout(() => {
 | 
			
		||||
				this.isUpgrade = true;
 | 
			
		||||
			}, 2000);
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.delayShow();
 | 
			
		||||
		setTimeout(() => {
 | 
			
		||||
			this.btnTxt = this.$t('message.upgrade.btnTwo');
 | 
			
		||||
		}, 200);
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.upgrade-dialog {
 | 
			
		||||
	& ::v-deep .el-dialog {
 | 
			
		||||
		.el-dialog__body {
 | 
			
		||||
			padding: 0 !important;
 | 
			
		||||
		}
 | 
			
		||||
		.el-dialog__header {
 | 
			
		||||
			display: none !important;
 | 
			
		||||
		}
 | 
			
		||||
		.upgrade-title {
 | 
			
		||||
			text-align: center;
 | 
			
		||||
			height: 130px;
 | 
			
		||||
			display: flex;
 | 
			
		||||
			align-items: center;
 | 
			
		||||
			justify-content: center;
 | 
			
		||||
			position: relative;
 | 
			
		||||
			&::after {
 | 
			
		||||
				content: '';
 | 
			
		||||
				position: absolute;
 | 
			
		||||
				background-color: var(--prev-color-primary-light-1);
 | 
			
		||||
				width: 130%;
 | 
			
		||||
				height: 130px;
 | 
			
		||||
				border-bottom-left-radius: 100%;
 | 
			
		||||
				border-bottom-right-radius: 100%;
 | 
			
		||||
			}
 | 
			
		||||
			.upgrade-title-warp {
 | 
			
		||||
				z-index: 1;
 | 
			
		||||
				position: relative;
 | 
			
		||||
				.upgrade-title-warp-txt {
 | 
			
		||||
					color: var(--prev-color-text-white);
 | 
			
		||||
					font-size: 22px;
 | 
			
		||||
					letter-spacing: 3px;
 | 
			
		||||
				}
 | 
			
		||||
				.upgrade-title-warp-version {
 | 
			
		||||
					background-color: var(--prev-color-primary-light-4);
 | 
			
		||||
					color: var(--prev-color-text-white);
 | 
			
		||||
					font-size: 12px;
 | 
			
		||||
					position: absolute;
 | 
			
		||||
					display: flex;
 | 
			
		||||
					top: -2px;
 | 
			
		||||
					right: -50px;
 | 
			
		||||
					padding: 2px 4px;
 | 
			
		||||
					border-radius: 2px;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		.upgrade-content {
 | 
			
		||||
			padding: 20px;
 | 
			
		||||
			line-height: 22px;
 | 
			
		||||
			color: var(--prev-color-text-regular);
 | 
			
		||||
			.upgrade-content-desc {
 | 
			
		||||
				color: var(--prev-color-text-placeholder);
 | 
			
		||||
				font-size: 12px;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		.upgrade-btn {
 | 
			
		||||
			border-top: 1px solid var(--prev-border-color-lighter);
 | 
			
		||||
			display: flex;
 | 
			
		||||
			justify-content: space-around;
 | 
			
		||||
			padding: 15px 20px;
 | 
			
		||||
			.el-button {
 | 
			
		||||
				width: 100%;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										24
									
								
								src/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/main.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import App from './App.vue';
 | 
			
		||||
import router from './router';
 | 
			
		||||
import store from './store';
 | 
			
		||||
 | 
			
		||||
import Particles from 'vue-particles';
 | 
			
		||||
import Element from 'element-ui';
 | 
			
		||||
import 'element-ui/lib/theme-chalk/index.css';
 | 
			
		||||
import '@/theme/index.scss';
 | 
			
		||||
import { i18n } from '@/i18n/index.js';
 | 
			
		||||
import { globalComponentSize } from '@/utils/componentSize.js';
 | 
			
		||||
 | 
			
		||||
Vue.use(Particles);
 | 
			
		||||
Vue.use(Element, { i18n: (key, value) => i18n.t(key, value), size: globalComponentSize });
 | 
			
		||||
 | 
			
		||||
Vue.config.productionTip = false;
 | 
			
		||||
Vue.prototype.bus = new Vue();
 | 
			
		||||
 | 
			
		||||
new Vue({
 | 
			
		||||
	router,
 | 
			
		||||
	store,
 | 
			
		||||
	i18n,
 | 
			
		||||
	render: (h) => h(App),
 | 
			
		||||
}).$mount('#app');
 | 
			
		||||
							
								
								
									
										275
									
								
								src/router/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										275
									
								
								src/router/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,275 @@
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import store from '../store';
 | 
			
		||||
import VueRouter from 'vue-router';
 | 
			
		||||
import NProgress from 'nprogress';
 | 
			
		||||
import 'nprogress/nprogress.css';
 | 
			
		||||
import { Session } from '@/utils/storage';
 | 
			
		||||
import { PrevLoading } from '@/utils/loading.js';
 | 
			
		||||
import { useMenuApi } from '@/api/menu';
 | 
			
		||||
 | 
			
		||||
const menuApi = useMenuApi();
 | 
			
		||||
 | 
			
		||||
// 解决 `element ui` 导航栏重复点菜单报错问题
 | 
			
		||||
const originalPush = VueRouter.prototype.push;
 | 
			
		||||
VueRouter.prototype.push = function push(location) {
 | 
			
		||||
	return originalPush.call(this, location).catch((err) => err);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 安装 VueRouter 插件
 | 
			
		||||
Vue.use(VueRouter);
 | 
			
		||||
 | 
			
		||||
// 定义动态路由
 | 
			
		||||
const dynamicRoutes = [
 | 
			
		||||
	{
 | 
			
		||||
		path: '/',
 | 
			
		||||
		name: '/',
 | 
			
		||||
		component: 'layout/index',
 | 
			
		||||
		redirect: '/home',
 | 
			
		||||
		meta: {
 | 
			
		||||
			isKeepAlive: true,
 | 
			
		||||
		},
 | 
			
		||||
		children: [],
 | 
			
		||||
	},
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
// 定义静态路由
 | 
			
		||||
const staticRoutes = [
 | 
			
		||||
	{
 | 
			
		||||
		path: '/login',
 | 
			
		||||
		name: 'login',
 | 
			
		||||
		component: () => import('@/views/login'),
 | 
			
		||||
		meta: {
 | 
			
		||||
			title: '登录',
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		path: '/404',
 | 
			
		||||
		name: 'notFound',
 | 
			
		||||
		component: () => import('@/views/error/404.vue'),
 | 
			
		||||
		meta: {
 | 
			
		||||
			title: 'message.staticRoutes.notFound',
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		path: '/401',
 | 
			
		||||
		name: 'noPower',
 | 
			
		||||
		component: () => import('@/views/error/401.vue'),
 | 
			
		||||
		meta: {
 | 
			
		||||
			title: 'message.staticRoutes.noPower',
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
// 加载静态路由
 | 
			
		||||
const createRouter = () =>
 | 
			
		||||
	new VueRouter({
 | 
			
		||||
		routes: staticRoutes,
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
// 创建路由
 | 
			
		||||
const router = createRouter();
 | 
			
		||||
 | 
			
		||||
// 加载 loading
 | 
			
		||||
PrevLoading.start();
 | 
			
		||||
 | 
			
		||||
// 多级嵌套数组处理成一维数组
 | 
			
		||||
export function formatFlatteningRoutes(arr) {
 | 
			
		||||
	if (arr.length <= 0) return false;
 | 
			
		||||
	for (let i = 0; i < arr.length; i++) {
 | 
			
		||||
		if (arr[i].children) {
 | 
			
		||||
			arr = arr.slice(0, i + 1).concat(arr[i].children, arr.slice(i + 1));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return arr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 处理 tagsViewList 数据,默认路由全部缓存
 | 
			
		||||
// isKeepAlive 处理 `name` 值,进行路由缓存
 | 
			
		||||
export function formatTwoStageRoutes(arr) {
 | 
			
		||||
	if (arr.length <= 0) return false;
 | 
			
		||||
	const newArr = [];
 | 
			
		||||
	const cacheList = [];
 | 
			
		||||
	arr.forEach((v) => {
 | 
			
		||||
		newArr.push({ ...v });
 | 
			
		||||
		cacheList.push(v.name);
 | 
			
		||||
		store.dispatch('keepAliveNames/setCacheKeepAlive', cacheList);
 | 
			
		||||
	});
 | 
			
		||||
	return newArr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 判断路由 meta.roles 中是否包含当前登录用户权限字段
 | 
			
		||||
export function hasAuth(roles, route) {
 | 
			
		||||
	if (route.meta && route.meta.roles) return roles.some((role) => route.meta.roles.includes(role));
 | 
			
		||||
	else return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 递归过滤有权限的路由
 | 
			
		||||
export function setFilterMenuFun(routes, role) {
 | 
			
		||||
	const menu = [];
 | 
			
		||||
	routes.forEach((route) => {
 | 
			
		||||
		const item = { ...route };
 | 
			
		||||
		if (hasAuth(role, item)) {
 | 
			
		||||
			if (item.children) item.children = setFilterMenuFun(item.children, role);
 | 
			
		||||
			menu.push(item);
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
	return menu;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 缓存多级嵌套数组处理后的一维数组(tagsView、菜单搜索中使用:未过滤隐藏的(isHide))
 | 
			
		||||
export function setCacheTagsViewRoutes(arr) {
 | 
			
		||||
	// 先处理有权限的路由,否则 tagsView、菜单搜索中无权限的路由也将显示
 | 
			
		||||
	let rolesRoutes = setFilterMenuFun(arr, store.state.userInfos.userInfos.roles);
 | 
			
		||||
	// 添加到 vuex setTagsViewRoutes 中
 | 
			
		||||
	store.dispatch('tagsViewRoutes/setTagsViewRoutes', formatTwoStageRoutes(formatFlatteningRoutes(rolesRoutes)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 递归处理多余的 layout : <router-view>,让需要访问的组件保持在第一层 layout 层。
 | 
			
		||||
// 因为 `keep-alive` 只能缓存二级路由
 | 
			
		||||
// 默认初始化时就执行
 | 
			
		||||
export function keepAliveSplice(to) {
 | 
			
		||||
	if (to.matched && to.matched.length > 2) {
 | 
			
		||||
		to.matched.map((v, k) => {
 | 
			
		||||
			if (v.components.default instanceof Function) {
 | 
			
		||||
				v.components.default().then((components) => {
 | 
			
		||||
					if (components.default.name === 'parent') {
 | 
			
		||||
						to.matched.splice(k, 1);
 | 
			
		||||
						router.push({ path: to.path, query: to.query });
 | 
			
		||||
						keepAliveSplice(to);
 | 
			
		||||
					}
 | 
			
		||||
				});
 | 
			
		||||
			} else {
 | 
			
		||||
				if (v.components.default.name === 'parent') {
 | 
			
		||||
					to.matched.splice(k, 1);
 | 
			
		||||
					keepAliveSplice(to);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 处理后端返回的 `component` 路径,拼装实现懒加载
 | 
			
		||||
export function loadView(path) {
 | 
			
		||||
	/**
 | 
			
		||||
	 * 打包成一个 js、一个 css
 | 
			
		||||
	 */
 | 
			
		||||
	// if (path.indexOf('layout') > -1) return () => Promise.resolve(require(`@/${path}`));
 | 
			
		||||
	// else return () => Promise.resolve(require(`@/views/${path}`));
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * 打包成多个 js、多个 css
 | 
			
		||||
	 */
 | 
			
		||||
	if (path.indexOf('layout') > -1) return () => import(`@/${path}`);
 | 
			
		||||
	else return () => import(`@/views/${path}`);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 递归处理每一项 `component` 中的路径
 | 
			
		||||
export function dynamicRouter(routes) {
 | 
			
		||||
	return routes.map((view) => {
 | 
			
		||||
		if (view.component) view.component = loadView(view.component);
 | 
			
		||||
		if (view.children) dynamicRouter(view.children);
 | 
			
		||||
		return view;
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 添加路由,模拟数据与方法,可自行进行修改 admin
 | 
			
		||||
// 添加动态路由,`{ path: '*', redirect: '/404' }` 防止页面刷新,静态路由丢失问题
 | 
			
		||||
// next({ ...to, replace: true }) 动态路由 addRoute 完毕后才放行,防止刷新时 NProgress 进度条加载2次
 | 
			
		||||
// 文档地址:https://router.vuejs.org/zh/api/#router-addroutes
 | 
			
		||||
export function adminUser(router, to, next) {
 | 
			
		||||
	resetRouter();
 | 
			
		||||
	menuApi
 | 
			
		||||
		.getMenuAdmin()
 | 
			
		||||
		.then(async (res) => {
 | 
			
		||||
			// 读取用户信息,获取对应权限进行判断
 | 
			
		||||
			store.dispatch('userInfos/setUserInfos');
 | 
			
		||||
			store.dispatch('routesList/setRoutesList', setFilterMenuFun(res.data, store.state.userInfos.userInfos.roles));
 | 
			
		||||
			dynamicRoutes[0].children = res.data;
 | 
			
		||||
			const awaitRoute = await dynamicRouter(dynamicRoutes);
 | 
			
		||||
			[...awaitRoute, { path: '*', redirect: '/404' }].forEach((route) => {
 | 
			
		||||
				router.addRoute({ ...route });
 | 
			
		||||
			});
 | 
			
		||||
			setCacheTagsViewRoutes(JSON.parse(JSON.stringify(res.data)));
 | 
			
		||||
			next({ ...to, replace: true });
 | 
			
		||||
		})
 | 
			
		||||
		.catch(() => {});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 添加路由,模拟数据与方法,可自行进行修改 test
 | 
			
		||||
// 添加动态路由,`{ path: '*', redirect: '/404' }` 防止页面刷新,静态路由丢失问题
 | 
			
		||||
export function testUser(router, to, next) {
 | 
			
		||||
	resetRouter();
 | 
			
		||||
	menuApi
 | 
			
		||||
		.getMenuTest()
 | 
			
		||||
		.then(async (res) => {
 | 
			
		||||
			// 读取用户信息,获取对应权限进行判断
 | 
			
		||||
			store.dispatch('userInfos/setUserInfos');
 | 
			
		||||
			store.dispatch('routesList/setRoutesList', setFilterMenuFun(res.data, store.state.userInfos.userInfos.roles));
 | 
			
		||||
			dynamicRoutes[0].children = res.data;
 | 
			
		||||
			const awaitRoute = await dynamicRouter(dynamicRoutes);
 | 
			
		||||
			[...awaitRoute, { path: '*', redirect: '/404' }].forEach((route) => {
 | 
			
		||||
				router.addRoute({ ...route });
 | 
			
		||||
			});
 | 
			
		||||
			setCacheTagsViewRoutes(JSON.parse(JSON.stringify(res.data)));
 | 
			
		||||
			next({ ...to, replace: true });
 | 
			
		||||
		})
 | 
			
		||||
		.catch(() => {});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 重置路由
 | 
			
		||||
export function resetRouter() {
 | 
			
		||||
	router.matcher = createRouter().matcher;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 延迟关闭进度条
 | 
			
		||||
export function delayNProgressDone(time = 300) {
 | 
			
		||||
	setTimeout(() => {
 | 
			
		||||
		NProgress.done();
 | 
			
		||||
	}, time);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 动态加载后端返回路由路由(模拟数据)
 | 
			
		||||
export function getRouterList(router, to, next) {
 | 
			
		||||
	if (!Session.get('userInfo')) return false;
 | 
			
		||||
	if (Session.get('userInfo').userName === 'admin') adminUser(router, to, next);
 | 
			
		||||
	else if (Session.get('userInfo').userName === 'test') testUser(router, to, next);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 路由加载前
 | 
			
		||||
router.beforeEach((to, from, next) => {
 | 
			
		||||
	keepAliveSplice(to);
 | 
			
		||||
	NProgress.configure({ showSpinner: false });
 | 
			
		||||
	if (to.meta.title && to.path !== '/login') NProgress.start();
 | 
			
		||||
	let token = Session.get('token');
 | 
			
		||||
	if (to.path === '/login' && !token) {
 | 
			
		||||
		NProgress.start();
 | 
			
		||||
		next();
 | 
			
		||||
		delayNProgressDone();
 | 
			
		||||
	} else {
 | 
			
		||||
		if (!token) {
 | 
			
		||||
			NProgress.start();
 | 
			
		||||
			next('/login');
 | 
			
		||||
			Session.clear();
 | 
			
		||||
			delayNProgressDone();
 | 
			
		||||
		} else if (token && to.path === '/login') {
 | 
			
		||||
			next('/home');
 | 
			
		||||
			delayNProgressDone();
 | 
			
		||||
		} else {
 | 
			
		||||
			if (Object.keys(store.state.routesList.routesList).length <= 0) {
 | 
			
		||||
				getRouterList(router, to, next);
 | 
			
		||||
			} else {
 | 
			
		||||
				next();
 | 
			
		||||
				delayNProgressDone(0);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// 路由加载后
 | 
			
		||||
router.afterEach(() => {
 | 
			
		||||
	PrevLoading.done();
 | 
			
		||||
	delayNProgressDone();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// 导出路由
 | 
			
		||||
export default router;
 | 
			
		||||
							
								
								
									
										15
									
								
								src/store/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/store/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import Vuex from 'vuex';
 | 
			
		||||
 | 
			
		||||
Vue.use(Vuex);
 | 
			
		||||
 | 
			
		||||
let moduleFn = require.context('./modules', false, /\.js$/);
 | 
			
		||||
let modules = moduleFn.keys().reduce((p, c) => {
 | 
			
		||||
	let mod = moduleFn(c).default;
 | 
			
		||||
	mod = { ...mod, namespaced: true };
 | 
			
		||||
	let modName = c.match(/\.\/(\w+)\.js$/)[1];
 | 
			
		||||
	p[modName] = mod;
 | 
			
		||||
	return p;
 | 
			
		||||
}, {});
 | 
			
		||||
 | 
			
		||||
export default new Vuex.Store({ modules });
 | 
			
		||||
							
								
								
									
										20
									
								
								src/store/modules/keepAliveNames.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/store/modules/keepAliveNames.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
const keepAliveNamesModule = {
 | 
			
		||||
	namespaced: true,
 | 
			
		||||
	state: {
 | 
			
		||||
		keepAliveNames: [],
 | 
			
		||||
	},
 | 
			
		||||
	mutations: {
 | 
			
		||||
		// 设置路由缓存(name字段)
 | 
			
		||||
		getCacheKeepAlive(state, data) {
 | 
			
		||||
			state.keepAliveNames = data;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	actions: {
 | 
			
		||||
		// 设置路由缓存(name字段)
 | 
			
		||||
		async setCacheKeepAlive({ commit }, data) {
 | 
			
		||||
			commit('getCacheKeepAlive', data);
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default keepAliveNamesModule;
 | 
			
		||||
							
								
								
									
										20
									
								
								src/store/modules/routesList.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/store/modules/routesList.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
const routesListModule = {
 | 
			
		||||
	namespaced: true,
 | 
			
		||||
	state: {
 | 
			
		||||
		routesList: [],
 | 
			
		||||
	},
 | 
			
		||||
	mutations: {
 | 
			
		||||
		// 设置路由,菜单中使用到
 | 
			
		||||
		getRoutesList(state, data) {
 | 
			
		||||
			state.routesList = data;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	actions: {
 | 
			
		||||
		// 设置路由,菜单中使用到
 | 
			
		||||
		async setRoutesList({ commit }, data) {
 | 
			
		||||
			commit('getRoutesList', data);
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default routesListModule;
 | 
			
		||||
							
								
								
									
										20
									
								
								src/store/modules/tagsViewRoutes.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/store/modules/tagsViewRoutes.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
const tagsViewRoutesModule = {
 | 
			
		||||
	namespaced: true,
 | 
			
		||||
	state: {
 | 
			
		||||
		tagsViewRoutes: [],
 | 
			
		||||
	},
 | 
			
		||||
	mutations: {
 | 
			
		||||
		// 设置 TagsView 路由
 | 
			
		||||
		getTagsViewRoutes(state, data) {
 | 
			
		||||
			state.tagsViewRoutes = data;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	actions: {
 | 
			
		||||
		// 设置 TagsView 路由
 | 
			
		||||
		async setTagsViewRoutes({ commit }, data) {
 | 
			
		||||
			commit('getTagsViewRoutes', data);
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default tagsViewRoutesModule;
 | 
			
		||||
							
								
								
									
										122
									
								
								src/store/modules/themeConfig.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								src/store/modules/themeConfig.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,122 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 2020.05.28 by lyt 优化
 | 
			
		||||
 * 修改一下配置时,需要每次都清理 `window.localStorage` 浏览器永久缓存,配置才会生效
 | 
			
		||||
 */
 | 
			
		||||
const themeConfigModule = {
 | 
			
		||||
	namespaced: true,
 | 
			
		||||
	state: {
 | 
			
		||||
		themeConfig: {
 | 
			
		||||
			// 是否开启布局配置抽屉
 | 
			
		||||
			isDrawer: false,
 | 
			
		||||
 | 
			
		||||
			/**
 | 
			
		||||
			 * 全局主题
 | 
			
		||||
			 */
 | 
			
		||||
			// 默认 primary 主题颜色
 | 
			
		||||
			primary: '#409eff',
 | 
			
		||||
			// 是否开启深色模式
 | 
			
		||||
			isIsDark: false,
 | 
			
		||||
 | 
			
		||||
			/**
 | 
			
		||||
			 * 菜单 / 顶栏
 | 
			
		||||
			 * 请注意:
 | 
			
		||||
			 * 需要同时修改 `/@/theme/common/var.scss` 对应的值,
 | 
			
		||||
			 * 不提供像 vue-next-admin 一样的实现
 | 
			
		||||
			 */
 | 
			
		||||
			// 默认顶栏导航背景颜色
 | 
			
		||||
			topBar: '#ffffff',
 | 
			
		||||
			// 默认顶栏导航字体颜色
 | 
			
		||||
			topBarColor: '#606266',
 | 
			
		||||
			// 默认菜单导航背景颜色
 | 
			
		||||
			menuBar: '#545c64',
 | 
			
		||||
			// 默认菜单导航字体颜色
 | 
			
		||||
			menuBarColor: '#eaeaea',
 | 
			
		||||
			// 默认分栏菜单背景颜色
 | 
			
		||||
			columnsMenuBar: '#545c64',
 | 
			
		||||
			// 默认分栏菜单字体颜色
 | 
			
		||||
			columnsMenuBarColor: '#e6e6e6',
 | 
			
		||||
 | 
			
		||||
			/**
 | 
			
		||||
			 * 界面设置
 | 
			
		||||
			 */
 | 
			
		||||
			// 是否开启菜单水平折叠效果
 | 
			
		||||
			isCollapse: false,
 | 
			
		||||
			// 是否开启菜单手风琴效果
 | 
			
		||||
			isUniqueOpened: false,
 | 
			
		||||
			// 是否开启固定 Header
 | 
			
		||||
			isFixedHeader: false,
 | 
			
		||||
 | 
			
		||||
			/**
 | 
			
		||||
			 * 界面显示
 | 
			
		||||
			 */
 | 
			
		||||
			// 是否开启侧边栏 Logo
 | 
			
		||||
			isShowLogo: false,
 | 
			
		||||
			// 是否开启 Breadcrumb
 | 
			
		||||
			isBreadcrumb: true,
 | 
			
		||||
			// 是否开启 Breadcrumb 图标
 | 
			
		||||
			isBreadcrumbIcon: false,
 | 
			
		||||
			// 是否开启 Tagsview
 | 
			
		||||
			isTagsview: true,
 | 
			
		||||
			// 是否开启 Tagsview 图标
 | 
			
		||||
			isTagsviewIcon: false,
 | 
			
		||||
			// 是否开启 TagsView 缓存
 | 
			
		||||
			isCacheTagsView: false,
 | 
			
		||||
			// 是否开启 Footer 底部版权信息
 | 
			
		||||
			isFooter: false,
 | 
			
		||||
			// 是否开启灰色模式
 | 
			
		||||
			isGrayscale: false,
 | 
			
		||||
			// 是否开启色弱模式
 | 
			
		||||
			isInvert: false,
 | 
			
		||||
 | 
			
		||||
			/**
 | 
			
		||||
			 * 其它设置
 | 
			
		||||
			 */
 | 
			
		||||
			// 默认 Tagsview 风格,可选 1、 tags-style-one,自行扩展:
 | 
			
		||||
			// 1、需修改 @/layout/navBars/breadcrumb/setings.vue `getThemeConfig.tagsStyle` el-option
 | 
			
		||||
			// 2、需修改 @/layout/navBars/tagsView/tagsView.vue 代码最底部注释部分 css 样式
 | 
			
		||||
			tagsStyle: 'tags-style-one',
 | 
			
		||||
			// 主页面切换动画:可选值"<slide-right|slide-left|opacitys>",默认 slide-right
 | 
			
		||||
			animation: 'slide-right',
 | 
			
		||||
			// 分栏高亮风格:可选值"<columns-round|columns-card>",默认 columns-round
 | 
			
		||||
			columnsAsideStyle: 'columns-round',
 | 
			
		||||
			// 分栏布局风格:可选值"<columns-horizontal|columns-vertical>",默认 columns-horizontal
 | 
			
		||||
			columnsAsideLayout: 'columns-vertical',
 | 
			
		||||
 | 
			
		||||
			/**
 | 
			
		||||
			 * 布局切换
 | 
			
		||||
			 * 注意:为了演示,切换布局时,颜色会被还原成默认,代码位置:/@/layout/navBars/breadcrumb/setings.vue
 | 
			
		||||
			 * 中的 `initSetLayoutChange(设置布局切换,重置主题样式)` 方法
 | 
			
		||||
			 */
 | 
			
		||||
			// 布局切换:可选值"<defaults|classic|transverse|columns>",默认 defaults
 | 
			
		||||
			layout: 'defaults',
 | 
			
		||||
 | 
			
		||||
			/**
 | 
			
		||||
			 * 全局网站标题 / 副标题
 | 
			
		||||
			 */
 | 
			
		||||
			// 网站主标题(菜单导航、浏览器当前网页标题)
 | 
			
		||||
			globalTitle: 'vue-prev-admin',
 | 
			
		||||
			// 网站副标题(登录页顶部文字)
 | 
			
		||||
			globalViceTitle: 'SMALL@小柒',
 | 
			
		||||
			// 网站描述(登录页顶部文字)
 | 
			
		||||
			globalViceDes: 'vue2.x后台管理系统免费开源模板',
 | 
			
		||||
			// 默认初始语言,可选值"<zh-cn|en|zh-tw>",默认 zh-cn
 | 
			
		||||
			globalI18n: 'zh-cn',
 | 
			
		||||
			// 默认全局组件大小,可选值"<|medium|small|mini>",默认 ''
 | 
			
		||||
			globalComponentSize: '',
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	mutations: {
 | 
			
		||||
		// 设置布局配置
 | 
			
		||||
		getThemeConfig(state, data) {
 | 
			
		||||
			state.themeConfig = data;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	actions: {
 | 
			
		||||
		// 设置布局配置
 | 
			
		||||
		setThemeConfig({ commit }, data) {
 | 
			
		||||
			commit('getThemeConfig', data);
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default themeConfigModule;
 | 
			
		||||
							
								
								
									
										26
									
								
								src/store/modules/userInfos.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/store/modules/userInfos.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
import { Session } from '@/utils/storage.js';
 | 
			
		||||
 | 
			
		||||
const userInfosModule = {
 | 
			
		||||
	namespaced: true,
 | 
			
		||||
	state: {
 | 
			
		||||
		userInfos: {},
 | 
			
		||||
	},
 | 
			
		||||
	mutations: {
 | 
			
		||||
		// 设置用户信息
 | 
			
		||||
		getUserInfos(state, data) {
 | 
			
		||||
			state.userInfos = data;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	actions: {
 | 
			
		||||
		// 设置用户信息
 | 
			
		||||
		async setUserInfos({ commit }, data) {
 | 
			
		||||
			if (data) {
 | 
			
		||||
				commit('getUserInfos', data);
 | 
			
		||||
			} else {
 | 
			
		||||
				if (Session.get('userInfo')) commit('getUserInfos', Session.get('userInfo'));
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default userInfosModule;
 | 
			
		||||
							
								
								
									
										240
									
								
								src/theme/app.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										240
									
								
								src/theme/app.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,240 @@
 | 
			
		||||
/* 初始化样式
 | 
			
		||||
------------------------------- */
 | 
			
		||||
* {
 | 
			
		||||
	margin: 0;
 | 
			
		||||
	padding: 0;
 | 
			
		||||
	box-sizing: border-box;
 | 
			
		||||
	outline: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
:root {
 | 
			
		||||
	--prev-bg-menuBar: #545c64;
 | 
			
		||||
	--prev-bg-menuBarColor: #eaeaea;
 | 
			
		||||
	--prev-bg-topBar: #ffffff;
 | 
			
		||||
	--prev-bg-topBarColor: #606266;
 | 
			
		||||
	--prev-bg-columnsMenuBar: #545c64;
 | 
			
		||||
	--prev-bg-columnsMenuBarColor: #e6e6e6;
 | 
			
		||||
	--prev-bg-main-color: #f8f8f8;
 | 
			
		||||
	--prev-bg-color: #f5f7fa;
 | 
			
		||||
	--prev-bg-white: #ffffff;
 | 
			
		||||
	--prev-color-primary: #409eff;
 | 
			
		||||
	--prev-color-text-white: #ffffff;
 | 
			
		||||
	--prev-color-text-black: #000000;
 | 
			
		||||
	--prev-color-text-primary: #303133;
 | 
			
		||||
	--prev-color-text-regular: #606266;
 | 
			
		||||
	--prev-color-text-secondary: #909399;
 | 
			
		||||
	--prev-color-text-placeholder: #c0c4cc;
 | 
			
		||||
	--prev-color-hover: rgba(0, 0, 0, 0.04);
 | 
			
		||||
	--prev-color-seting-main: #e9eef3;
 | 
			
		||||
	--prev-color-seting-aside: #d3dce6;
 | 
			
		||||
	--prev-color-seting-header: #b3c0d1;
 | 
			
		||||
	--prev-border-color-hover: #c0c4cc;
 | 
			
		||||
	--prev-border-color-base: #dcdfe6;
 | 
			
		||||
	--prev-border-color-light: #e4e7ed;
 | 
			
		||||
	--prev-border-color-lighter: #ebeef5;
 | 
			
		||||
	--prev-border-color-extra-light: #f2f6fc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
html,
 | 
			
		||||
body,
 | 
			
		||||
#app {
 | 
			
		||||
	width: 100%;
 | 
			
		||||
	height: 100%;
 | 
			
		||||
	background-color: var(--prev-bg-main-color);
 | 
			
		||||
	font-size: 14px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 主布局样式
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.layout-container {
 | 
			
		||||
	width: 100%;
 | 
			
		||||
	height: 100%;
 | 
			
		||||
	.layout-aside {
 | 
			
		||||
		background: var(--prev-bg-menuBar);
 | 
			
		||||
		box-shadow: 2px 0 6px rgb(0 21 41 / 1%);
 | 
			
		||||
		height: inherit;
 | 
			
		||||
		position: relative;
 | 
			
		||||
		z-index: 1;
 | 
			
		||||
		display: flex;
 | 
			
		||||
		flex-direction: column;
 | 
			
		||||
		overflow-x: hidden !important;
 | 
			
		||||
		.el-scrollbar__view {
 | 
			
		||||
			overflow: hidden;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	.layout-header {
 | 
			
		||||
		padding: 0 !important;
 | 
			
		||||
	}
 | 
			
		||||
	.layout-main {
 | 
			
		||||
		padding: 0 !important;
 | 
			
		||||
		overflow: hidden;
 | 
			
		||||
		width: 100%;
 | 
			
		||||
		background-color: var(--prev-bg-main-color);
 | 
			
		||||
	}
 | 
			
		||||
	.el-scrollbar {
 | 
			
		||||
		width: 100%;
 | 
			
		||||
	}
 | 
			
		||||
	.layout-view-bg-white {
 | 
			
		||||
		background: var(--prev-bg-white);
 | 
			
		||||
		width: 100%;
 | 
			
		||||
		height: 100%;
 | 
			
		||||
		border-radius: 4px;
 | 
			
		||||
		border: 1px solid var(--prev-border-color-lighter);
 | 
			
		||||
	}
 | 
			
		||||
	.layout-el-aside-br-color {
 | 
			
		||||
		border-right: 1px solid rgb(238, 238, 238);
 | 
			
		||||
	}
 | 
			
		||||
	.layout-aside-width-default {
 | 
			
		||||
		width: 220px !important;
 | 
			
		||||
		transition: width 0.3s ease;
 | 
			
		||||
	}
 | 
			
		||||
	.layout-aside-width64 {
 | 
			
		||||
		width: 64px !important;
 | 
			
		||||
		transition: width 0.3s ease;
 | 
			
		||||
	}
 | 
			
		||||
	.layout-aside-width1 {
 | 
			
		||||
		width: 1px !important;
 | 
			
		||||
		transition: width 0.3s ease;
 | 
			
		||||
	}
 | 
			
		||||
	.layout-scrollbar {
 | 
			
		||||
		@extend .el-scrollbar;
 | 
			
		||||
		padding: 15px;
 | 
			
		||||
	}
 | 
			
		||||
	.layout-mian-height-50 {
 | 
			
		||||
		height: calc(100vh - 50px);
 | 
			
		||||
	}
 | 
			
		||||
	.layout-columns-warp {
 | 
			
		||||
		flex: 1;
 | 
			
		||||
		display: flex;
 | 
			
		||||
		overflow: hidden;
 | 
			
		||||
	}
 | 
			
		||||
	.layout-hide {
 | 
			
		||||
		display: none;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 进度条颜色
 | 
			
		||||
------------------------------- */
 | 
			
		||||
#nprogress .bar {
 | 
			
		||||
	background: var(--prev-color-primary) !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* flex 弹性布局
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.flex {
 | 
			
		||||
	display: flex;
 | 
			
		||||
}
 | 
			
		||||
.flex-auto {
 | 
			
		||||
	flex: 1;
 | 
			
		||||
}
 | 
			
		||||
.flex-center {
 | 
			
		||||
	@extend .flex;
 | 
			
		||||
	flex-direction: column;
 | 
			
		||||
	width: 100%;
 | 
			
		||||
	overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
.flex-margin {
 | 
			
		||||
	margin: auto;
 | 
			
		||||
}
 | 
			
		||||
.flex-warp {
 | 
			
		||||
	display: flex;
 | 
			
		||||
	flex-wrap: wrap;
 | 
			
		||||
	align-content: flex-start;
 | 
			
		||||
	margin: 0 -5px;
 | 
			
		||||
	.flex-warp-item {
 | 
			
		||||
		padding: 5px;
 | 
			
		||||
		.flex-warp-item-box {
 | 
			
		||||
			width: 100%;
 | 
			
		||||
			height: 100%;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
/* 宽高 100%
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.w100 {
 | 
			
		||||
	width: 100% !important;
 | 
			
		||||
}
 | 
			
		||||
.h100 {
 | 
			
		||||
	height: 100% !important;
 | 
			
		||||
}
 | 
			
		||||
.vh100 {
 | 
			
		||||
	height: 100vh !important;
 | 
			
		||||
}
 | 
			
		||||
.max100vh {
 | 
			
		||||
	max-height: 100vh !important;
 | 
			
		||||
}
 | 
			
		||||
.min100vh {
 | 
			
		||||
	min-height: 100vh !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 颜色值
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.color-primary {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.color-success {
 | 
			
		||||
	color: var(--prev-color-success);
 | 
			
		||||
}
 | 
			
		||||
.color-warning {
 | 
			
		||||
	color: var(--prev-color-warning);
 | 
			
		||||
}
 | 
			
		||||
.color-danger {
 | 
			
		||||
	color: var(--prev-color-danger);
 | 
			
		||||
}
 | 
			
		||||
.color-info {
 | 
			
		||||
	color: var(--prev-color-info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 溢出省略号
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.one-text-overflow {
 | 
			
		||||
	overflow: hidden;
 | 
			
		||||
	text-overflow: ellipsis;
 | 
			
		||||
	white-space: nowrap;
 | 
			
		||||
}
 | 
			
		||||
.two-text-overflow {
 | 
			
		||||
	display: -webkit-box;
 | 
			
		||||
	-webkit-box-orient: vertical;
 | 
			
		||||
	-webkit-line-clamp: 2;
 | 
			
		||||
	overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
.overflow {
 | 
			
		||||
	overflow: hidden !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 字体大小全局样式
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@for $i from 10 through 32 {
 | 
			
		||||
	.font#{$i} {
 | 
			
		||||
		font-size: #{$i}px !important;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 外边距、内边距全局样式
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@for $i from 5 through 35 {
 | 
			
		||||
	.mt#{$i} {
 | 
			
		||||
		margin-top: #{$i}px !important;
 | 
			
		||||
	}
 | 
			
		||||
	.mr#{$i} {
 | 
			
		||||
		margin-right: #{$i}px !important;
 | 
			
		||||
	}
 | 
			
		||||
	.mb#{$i} {
 | 
			
		||||
		margin-bottom: #{$i}px !important;
 | 
			
		||||
	}
 | 
			
		||||
	.ml#{$i} {
 | 
			
		||||
		margin-left: #{$i}px !important;
 | 
			
		||||
	}
 | 
			
		||||
	.pt#{$i} {
 | 
			
		||||
		padding-top: #{$i}px !important;
 | 
			
		||||
	}
 | 
			
		||||
	.pr#{$i} {
 | 
			
		||||
		padding-right: #{$i}px !important;
 | 
			
		||||
	}
 | 
			
		||||
	.pb#{$i} {
 | 
			
		||||
		padding-bottom: #{$i}px !important;
 | 
			
		||||
	}
 | 
			
		||||
	.pl#{$i} {
 | 
			
		||||
		padding-left: #{$i}px !important;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/theme/base.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/theme/base.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
@import 'common/transition.scss';
 | 
			
		||||
							
								
								
									
										102
									
								
								src/theme/common/transition.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								src/theme/common/transition.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
			
		||||
/* 页面切换动画
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.slide-right-enter-active,
 | 
			
		||||
.slide-right-leave-active,
 | 
			
		||||
.slide-left-enter-active,
 | 
			
		||||
.slide-left-leave-active {
 | 
			
		||||
	will-change: transform;
 | 
			
		||||
	transition: all 0.3s ease;
 | 
			
		||||
}
 | 
			
		||||
// slide-right
 | 
			
		||||
.slide-right-enter {
 | 
			
		||||
	opacity: 0;
 | 
			
		||||
	transform: translateX(-20px);
 | 
			
		||||
}
 | 
			
		||||
.slide-right-leave-active {
 | 
			
		||||
	opacity: 0;
 | 
			
		||||
	transform: translateX(20px);
 | 
			
		||||
}
 | 
			
		||||
// slide-left
 | 
			
		||||
.slide-left-enter-from {
 | 
			
		||||
	@extend .slide-right-leave-active;
 | 
			
		||||
}
 | 
			
		||||
.slide-left-leave-to {
 | 
			
		||||
	@extend .slide-right-enter;
 | 
			
		||||
}
 | 
			
		||||
// opacitys
 | 
			
		||||
.opacitys-enter-active,
 | 
			
		||||
.opacitys-leave-active {
 | 
			
		||||
	will-change: transform;
 | 
			
		||||
	transition: all 0.3s ease;
 | 
			
		||||
}
 | 
			
		||||
.opacitys-enter,
 | 
			
		||||
.opacitys-leave-active {
 | 
			
		||||
	opacity: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Breadcrumb 面包屑过渡动画
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.breadcrumb-enter-active,
 | 
			
		||||
.breadcrumb-leave-active {
 | 
			
		||||
	transition: all 0.3s;
 | 
			
		||||
}
 | 
			
		||||
.breadcrumb-enter,
 | 
			
		||||
.breadcrumb-leave-active {
 | 
			
		||||
	opacity: 0;
 | 
			
		||||
	transform: translateX(20px);
 | 
			
		||||
}
 | 
			
		||||
.breadcrumb-move {
 | 
			
		||||
	transition: all 0.3s;
 | 
			
		||||
}
 | 
			
		||||
.breadcrumb-leave-active {
 | 
			
		||||
	position: absolute;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* logo 过渡动画
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@keyframes logoAnimation {
 | 
			
		||||
	0% {
 | 
			
		||||
		transform: scale(0);
 | 
			
		||||
	}
 | 
			
		||||
	80% {
 | 
			
		||||
		transform: scale(1.2);
 | 
			
		||||
	}
 | 
			
		||||
	100% {
 | 
			
		||||
		transform: scale(1);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 404、401 过渡动画
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@keyframes error-num {
 | 
			
		||||
	0% {
 | 
			
		||||
		transform: translateY(60px);
 | 
			
		||||
		opacity: 0;
 | 
			
		||||
	}
 | 
			
		||||
	100% {
 | 
			
		||||
		transform: translateY(0);
 | 
			
		||||
		opacity: 1;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@keyframes error-img {
 | 
			
		||||
	0% {
 | 
			
		||||
		opacity: 0;
 | 
			
		||||
	}
 | 
			
		||||
	100% {
 | 
			
		||||
		opacity: 1;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 左右左 link.vue
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@keyframes toRight {
 | 
			
		||||
	0% {
 | 
			
		||||
		left: -5px;
 | 
			
		||||
	}
 | 
			
		||||
	50% {
 | 
			
		||||
		left: 100%;
 | 
			
		||||
	}
 | 
			
		||||
	100% {
 | 
			
		||||
		left: -5px;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										109
									
								
								src/theme/dark.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								src/theme/dark.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
			
		||||
/* 深色模式样式
 | 
			
		||||
------------------------------- */
 | 
			
		||||
[data-theme='dark'] {
 | 
			
		||||
	--prev-bg-menuBar: #191919 !important;
 | 
			
		||||
	--prev-bg-menuBarColor: #dadada !important;
 | 
			
		||||
	--prev-bg-topBar: #191919 !important;
 | 
			
		||||
	--prev-bg-topBarColor: #dadada !important;
 | 
			
		||||
	--prev-bg-columnsMenuBar: #191919 !important;
 | 
			
		||||
	--prev-bg-columnsMenuBarColor: #dadada !important;
 | 
			
		||||
	--prev-bg-main-color: #1f1f1f !important;
 | 
			
		||||
	--prev-bg-color: rgba(0, 0, 0, 0.3) !important;
 | 
			
		||||
	--prev-bg-white: #191919 !important;
 | 
			
		||||
	--prev-color-text-black: #ffffff !important;
 | 
			
		||||
	--prev-color-text-primary: #dadada !important;
 | 
			
		||||
	--prev-color-text-regular: #dadada !important;
 | 
			
		||||
	--prev-color-text-secondary: #a3a3a3 !important;
 | 
			
		||||
	--prev-color-hover: rgba(0, 0, 0, 0.3) !important;
 | 
			
		||||
	--prev-color-seting-main: #505050 !important;
 | 
			
		||||
	--prev-color-seting-aside: #3c3c3c !important;
 | 
			
		||||
	--prev-color-seting-header: #303030 !important;
 | 
			
		||||
	--prev-border-color-hover: #616161 !important;
 | 
			
		||||
	--prev-border-color-base: #333333 !important;
 | 
			
		||||
	--prev-border-color-light: #333333 !important;
 | 
			
		||||
	--prev-border-color-lighter: #333333 !important;
 | 
			
		||||
	--prev-border-color-extra-light: #333333 !important;
 | 
			
		||||
 | 
			
		||||
	// menu
 | 
			
		||||
	.layout-aside {
 | 
			
		||||
		border-right: 1px solid var(--prev-border-color-lighter) !important;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// drawer
 | 
			
		||||
	.el-drawer {
 | 
			
		||||
		border-left: 1px solid var(--prev-border-color-lighter) !important;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// button
 | 
			
		||||
	.el-button--default {
 | 
			
		||||
		background: var(--prev-bg-white);
 | 
			
		||||
		color: var(--prev-color-text-primary);
 | 
			
		||||
		border-color: var(--prev-border-color-lighter);
 | 
			
		||||
		&:hover,
 | 
			
		||||
		&:focus {
 | 
			
		||||
			color: var(--prev-color-primary) !important;
 | 
			
		||||
			background: var(--prev-color-primary-light-8) !important;
 | 
			
		||||
			border-color: var(--prev-color-primary-light-6) !important;
 | 
			
		||||
		}
 | 
			
		||||
		&:focus {
 | 
			
		||||
			border-color: var(--prev-color-primary-light-1) !important;
 | 
			
		||||
		}
 | 
			
		||||
		&:active {
 | 
			
		||||
			border-color: var(--prev-color-primary-light-6) !important;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// tag
 | 
			
		||||
	.el-tag.el-tag--info {
 | 
			
		||||
		background-color: var(--prev-bg-white) !important;
 | 
			
		||||
		border-color: var(--prev-border-color-light) !important;
 | 
			
		||||
		color: var(--prev-color-text-regular) !important;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// switch
 | 
			
		||||
	.el-switch:not(.is-checked) {
 | 
			
		||||
		.el-switch__core {
 | 
			
		||||
			border-color: var(--prev-border-color-base) !important;
 | 
			
		||||
			background-color: var(--prev-border-color-base) !important;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TimePicker
 | 
			
		||||
	.el-time-spinner__item.active:not(.disabled) {
 | 
			
		||||
		color: var(--prev-color-primary) !important;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// date
 | 
			
		||||
	.el-date-table td.in-range div,
 | 
			
		||||
	.el-date-table td.in-range div:hover,
 | 
			
		||||
	.el-date-table.is-week-mode .el-date-table__row.current div,
 | 
			
		||||
	.el-date-table.is-week-mode .el-date-table__row:hover div,
 | 
			
		||||
	.el-date-table td.selected div,
 | 
			
		||||
	.el-month-table td.in-range div,
 | 
			
		||||
	.el-month-table td.in-range div:hover {
 | 
			
		||||
		background-color: var(--prev-bg-color) !important;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// transfer
 | 
			
		||||
	.el-transfer-panel,
 | 
			
		||||
	.el-transfer-panel .el-transfer-panel__header {
 | 
			
		||||
		background-color: var(--prev-bg-color) !important;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// loading
 | 
			
		||||
	.el-loading-mask {
 | 
			
		||||
		background-color: var(--prev-bg-color) !important;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// dropdown
 | 
			
		||||
	.el-dropdown-menu__item:focus,
 | 
			
		||||
	.el-dropdown-menu__item:not(.is-disabled):hover {
 | 
			
		||||
		background-color: var(--prev-color-hover) !important;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// dialog
 | 
			
		||||
	.el-dialog,
 | 
			
		||||
	.el-calendar {
 | 
			
		||||
		border: 1px solid var(--prev-border-color-lighter);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										219
									
								
								src/theme/element.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										219
									
								
								src/theme/element.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,219 @@
 | 
			
		||||
/* 防止页面切换时,滚动条高度不变的问题(滚动条高度非滚动条滚动高度)
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-scrollbar {
 | 
			
		||||
	overflow: hidden;
 | 
			
		||||
	position: relative;
 | 
			
		||||
	height: 100%;
 | 
			
		||||
}
 | 
			
		||||
.el-scrollbar__wrap {
 | 
			
		||||
	overflow: auto !important;
 | 
			
		||||
	overflow-x: hidden !important;
 | 
			
		||||
	max-height: 100%; /*防止页面切换时,滚动条高度不变的问题(滚动条高度非滚动条滚动高度)*/
 | 
			
		||||
}
 | 
			
		||||
.el-select-dropdown .el-scrollbar__wrap {
 | 
			
		||||
	overflow-x: scroll !important;
 | 
			
		||||
}
 | 
			
		||||
.el-select-dropdown__wrap {
 | 
			
		||||
	max-height: 274px !important; /*修复Select 选择器高度问题*/
 | 
			
		||||
}
 | 
			
		||||
.el-autocomplete-suggestion__wrap {
 | 
			
		||||
	max-height: 280px !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Button 按钮
 | 
			
		||||
------------------------------- */
 | 
			
		||||
// 第三方字体图标大小
 | 
			
		||||
.el-button i.iconfont,
 | 
			
		||||
.el-button i.fa {
 | 
			
		||||
	font-size: 14px !important;
 | 
			
		||||
	margin-right: 5px;
 | 
			
		||||
}
 | 
			
		||||
.el-button--medium i.iconfont,
 | 
			
		||||
.el-button--medium i.fa {
 | 
			
		||||
	font-size: 14px !important;
 | 
			
		||||
	margin-right: 5px;
 | 
			
		||||
}
 | 
			
		||||
.el-button--small i.iconfont,
 | 
			
		||||
.el-button--small i.fa {
 | 
			
		||||
	font-size: 12px !important;
 | 
			
		||||
	margin-right: 5px;
 | 
			
		||||
}
 | 
			
		||||
.el-button--mini i.iconfont,
 | 
			
		||||
.el-button--mini i.fa {
 | 
			
		||||
	font-size: 12px !important;
 | 
			
		||||
	margin-right: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Dialog 对话框
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-overlay,
 | 
			
		||||
.el-dialog__wrapper {
 | 
			
		||||
	display: flex;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	justify-content: center;
 | 
			
		||||
	.el-dialog {
 | 
			
		||||
		margin: 0 auto !important;
 | 
			
		||||
		.el-dialog__body {
 | 
			
		||||
			padding: 20px !important;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
.el-dialog__body {
 | 
			
		||||
	max-height: calc(90vh - 111px) !important;
 | 
			
		||||
	overflow-y: auto;
 | 
			
		||||
	overflow-x: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Alert 警告
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-alert--warning.is-light {
 | 
			
		||||
	border: 1px solid rgba(230, 162, 60, 0.3) !important;
 | 
			
		||||
}
 | 
			
		||||
.el-alert--success.is-light {
 | 
			
		||||
	border: 1px solid rgba(103, 194, 58, 0.3) !important;
 | 
			
		||||
}
 | 
			
		||||
.el-alert--info.is-light {
 | 
			
		||||
	border: 1px solid rgba(144, 147, 153, 0.3) !important;
 | 
			
		||||
}
 | 
			
		||||
.el-alert--error.is-light {
 | 
			
		||||
	border: 1px solid rgba(245, 108, 108, 0.3) !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Table 表格
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-table-column--selection {
 | 
			
		||||
	.el-checkbox {
 | 
			
		||||
		margin-right: unset !important;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
.el-table::before,
 | 
			
		||||
.el-table--group::after,
 | 
			
		||||
.el-table--border::after {
 | 
			
		||||
	z-index: 99 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 下拉选择器/时间选择器滚动条
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-select-dropdown .el-scrollbar__wrap,
 | 
			
		||||
.el-picker-panel .el-scrollbar__wrap {
 | 
			
		||||
	overflow-x: scroll !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* NavMenu 导航菜单
 | 
			
		||||
------------------------------- */
 | 
			
		||||
// 默认样式修改
 | 
			
		||||
.el-menu {
 | 
			
		||||
	border-right: none !important;
 | 
			
		||||
}
 | 
			
		||||
.el-menu-item,
 | 
			
		||||
.el-submenu__title {
 | 
			
		||||
	height: 50px !important;
 | 
			
		||||
	line-height: 50px !important;
 | 
			
		||||
	color: var(--prev-bg-menuBarColor) !important;
 | 
			
		||||
	transition: none !important;
 | 
			
		||||
}
 | 
			
		||||
// horizontal 水平方向时
 | 
			
		||||
.el-menu--horizontal > .el-menu-item.is-active,
 | 
			
		||||
.el-menu--horizontal > .el-submenu.is-active .el-submenu__title {
 | 
			
		||||
	border-bottom: 3px solid !important;
 | 
			
		||||
	border-bottom-color: var(--prev-color-primary) !important;
 | 
			
		||||
	color: var(--prev-color-primary) !important;
 | 
			
		||||
}
 | 
			
		||||
.el-menu--horizontal .el-menu-item:not(.is-disabled):focus,
 | 
			
		||||
.el-menu--horizontal .el-menu-item:not(.is-disabled):hover,
 | 
			
		||||
.el-menu--horizontal > .el-submenu:focus .el-submenu__title,
 | 
			
		||||
.el-menu--horizontal > .el-submenu:hover .el-submenu__title,
 | 
			
		||||
.el-menu--horizontal .el-menu .el-menu-item.is-active,
 | 
			
		||||
.el-menu--horizontal .el-menu .el-submenu.is-active > .el-submenu__title {
 | 
			
		||||
	color: var(--prev-color-primary) !important;
 | 
			
		||||
}
 | 
			
		||||
.el-menu.el-menu--horizontal {
 | 
			
		||||
	border-bottom: none !important;
 | 
			
		||||
}
 | 
			
		||||
.el-menu--horizontal > .el-menu-item,
 | 
			
		||||
.el-menu--horizontal > .el-submenu .el-submenu__title {
 | 
			
		||||
	color: var(--bg-topBarColor) !important;
 | 
			
		||||
}
 | 
			
		||||
// 外部链接时
 | 
			
		||||
.el-menu-item a,
 | 
			
		||||
.el-menu-item a:hover,
 | 
			
		||||
.el-menu-item i,
 | 
			
		||||
.el-submenu__title i {
 | 
			
		||||
	color: inherit;
 | 
			
		||||
	text-decoration: none;
 | 
			
		||||
}
 | 
			
		||||
.el-menu-item a {
 | 
			
		||||
	width: 86%;
 | 
			
		||||
	display: inline-block;
 | 
			
		||||
}
 | 
			
		||||
// 默认 hover 时
 | 
			
		||||
.el-menu-item:hover,
 | 
			
		||||
.el-submenu__title:hover {
 | 
			
		||||
	color: var(--prev-color-primary) !important;
 | 
			
		||||
	background-color: transparent !important;
 | 
			
		||||
	i {
 | 
			
		||||
		color: var(--prev-color-primary) !important;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
// 高亮时
 | 
			
		||||
.el-menu-item.is-active {
 | 
			
		||||
	color: var(--prev-color-primary) !important;
 | 
			
		||||
}
 | 
			
		||||
.el-active-extend {
 | 
			
		||||
	color: #ffffff !important;
 | 
			
		||||
	background-color: var(--prev-color-primary) !important;
 | 
			
		||||
	i {
 | 
			
		||||
		color: #ffffff !important;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
#add-is-active {
 | 
			
		||||
	@extend .el-active-extend;
 | 
			
		||||
	&:hover {
 | 
			
		||||
		@extend .el-active-extend;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
// 菜单收起时且是a链接
 | 
			
		||||
.is-dark a {
 | 
			
		||||
	color: #ffffff !important;
 | 
			
		||||
	text-decoration: none;
 | 
			
		||||
}
 | 
			
		||||
// 菜单收起时鼠标经过背景颜色/字体颜色
 | 
			
		||||
.el-menu--vertical {
 | 
			
		||||
	background: var(--prev-bg-menuBar) !important;
 | 
			
		||||
}
 | 
			
		||||
.el-menu--horizontal {
 | 
			
		||||
	.el-menu {
 | 
			
		||||
		background: var(--bg-topBar) !important;
 | 
			
		||||
	}
 | 
			
		||||
	.el-menu-item,
 | 
			
		||||
	.el-submenu__title {
 | 
			
		||||
		color: var(--bg-topBarColor);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
// 第三方图标字体间距/大小设置
 | 
			
		||||
.el-menu-item .iconfont,
 | 
			
		||||
.el-submenu .iconfont,
 | 
			
		||||
.el-menu-item .fa,
 | 
			
		||||
.el-submenu__title .fa {
 | 
			
		||||
	font-size: 14px !important;
 | 
			
		||||
	display: inline-block;
 | 
			
		||||
	vertical-align: middle;
 | 
			
		||||
	margin-right: 5px;
 | 
			
		||||
	width: 24px;
 | 
			
		||||
	text-align: center;
 | 
			
		||||
}
 | 
			
		||||
// element plus 本身字体图标
 | 
			
		||||
.el-submenu [class^='el-icon-'],
 | 
			
		||||
.el-menu-item [class^='el-icon-'] {
 | 
			
		||||
	font-size: 14px !important;
 | 
			
		||||
}
 | 
			
		||||
// 去掉离开浏览器时,菜单的默认高亮
 | 
			
		||||
.el-menu-item:focus {
 | 
			
		||||
	background-color: transparent !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Alert 警告
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-alert__title {
 | 
			
		||||
	word-break: break-all;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								src/theme/index.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/theme/index.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
@import './base.scss';
 | 
			
		||||
@import './app.scss';
 | 
			
		||||
@import './other.scss';
 | 
			
		||||
@import './element.scss';
 | 
			
		||||
@import './media/media.scss';
 | 
			
		||||
@import './variables.scss';
 | 
			
		||||
@import './dark.scss';
 | 
			
		||||
							
								
								
									
										56
									
								
								src/theme/loading.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/theme/loading.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
.loading-prev {
 | 
			
		||||
	width: 100%;
 | 
			
		||||
	height: 100%;
 | 
			
		||||
	position: fixed;
 | 
			
		||||
	top: 0;
 | 
			
		||||
	left: 0;
 | 
			
		||||
	z-index: 2;
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
}
 | 
			
		||||
.loading-prev .loading-prev-box {
 | 
			
		||||
	position: absolute;
 | 
			
		||||
	top: 50%;
 | 
			
		||||
	left: 50%;
 | 
			
		||||
	transform: translate(-50%, -50%);
 | 
			
		||||
}
 | 
			
		||||
.loading-prev .loading-prev-box-warp {
 | 
			
		||||
	width: 80px;
 | 
			
		||||
	height: 80px;
 | 
			
		||||
}
 | 
			
		||||
.loading-prev .loading-prev-box-warp .loading-prev-box-item {
 | 
			
		||||
	width: 33.333333%;
 | 
			
		||||
	height: 33.333333%;
 | 
			
		||||
	background: var(--prev-color-primary);
 | 
			
		||||
	float: left;
 | 
			
		||||
	animation: loading-prev-animation 1.2s infinite ease;
 | 
			
		||||
	border-radius: 1px;
 | 
			
		||||
}
 | 
			
		||||
.loading-prev .loading-prev-box-warp .loading-prev-box-item:nth-child(7) {
 | 
			
		||||
	animation-delay: 0s;
 | 
			
		||||
}
 | 
			
		||||
.loading-prev .loading-prev-box-warp .loading-prev-box-item:nth-child(4),
 | 
			
		||||
.loading-prev .loading-prev-box-warp .loading-prev-box-item:nth-child(8) {
 | 
			
		||||
	animation-delay: 0.1s;
 | 
			
		||||
}
 | 
			
		||||
.loading-prev .loading-prev-box-warp .loading-prev-box-item:nth-child(1),
 | 
			
		||||
.loading-prev .loading-prev-box-warp .loading-prev-box-item:nth-child(5),
 | 
			
		||||
.loading-prev .loading-prev-box-warp .loading-prev-box-item:nth-child(9) {
 | 
			
		||||
	animation-delay: 0.2s;
 | 
			
		||||
}
 | 
			
		||||
.loading-prev .loading-prev-box-warp .loading-prev-box-item:nth-child(2),
 | 
			
		||||
.loading-prev .loading-prev-box-warp .loading-prev-box-item:nth-child(6) {
 | 
			
		||||
	animation-delay: 0.3s;
 | 
			
		||||
}
 | 
			
		||||
.loading-prev .loading-prev-box-warp .loading-prev-box-item:nth-child(3) {
 | 
			
		||||
	animation-delay: 0.4s;
 | 
			
		||||
}
 | 
			
		||||
@keyframes loading-prev-animation {
 | 
			
		||||
	0%,
 | 
			
		||||
	70%,
 | 
			
		||||
	100% {
 | 
			
		||||
		transform: scale3D(1, 1, 1);
 | 
			
		||||
	}
 | 
			
		||||
	35% {
 | 
			
		||||
		transform: scale3D(0, 0, 1);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								src/theme/media/dialog.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/theme/media/dialog.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
@import './index.scss';
 | 
			
		||||
 | 
			
		||||
/* 页面宽度小于800px
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@media screen and (max-width: 800px) {
 | 
			
		||||
	.el-dialog {
 | 
			
		||||
		width: 90%;
 | 
			
		||||
	}
 | 
			
		||||
	.el-dialog.is-fullscreen {
 | 
			
		||||
		width: 100% !important;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								src/theme/media/error.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/theme/media/error.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
@import './index.scss';
 | 
			
		||||
 | 
			
		||||
/* 页面宽度小于768px
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@media screen and (max-width: $sm) {
 | 
			
		||||
	.error {
 | 
			
		||||
		.error-flex {
 | 
			
		||||
			flex-direction: column-reverse !important;
 | 
			
		||||
			height: auto !important;
 | 
			
		||||
			width: 100% !important;
 | 
			
		||||
		}
 | 
			
		||||
		.right,
 | 
			
		||||
		.left {
 | 
			
		||||
			flex: unset !important;
 | 
			
		||||
			display: flex !important;
 | 
			
		||||
		}
 | 
			
		||||
		.left-item {
 | 
			
		||||
			margin: auto !important;
 | 
			
		||||
		}
 | 
			
		||||
		.right img {
 | 
			
		||||
			max-width: 450px !important;
 | 
			
		||||
			@extend .left-item;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 页面宽度大于768px小于992px
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@media screen and (min-width: $sm) and (max-width: $md) {
 | 
			
		||||
	.error {
 | 
			
		||||
		.error-flex {
 | 
			
		||||
			padding-left: 30px !important;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								src/theme/media/form.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/theme/media/form.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
@import './index.scss';
 | 
			
		||||
 | 
			
		||||
/* 页面宽度小于576px
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@media screen and (max-width: $xs) {
 | 
			
		||||
	.el-form-item__label {
 | 
			
		||||
		width: 100% !important;
 | 
			
		||||
		text-align: left !important;
 | 
			
		||||
	}
 | 
			
		||||
	.el-form-item__content {
 | 
			
		||||
		margin-left: 0 !important;
 | 
			
		||||
	}
 | 
			
		||||
	.el-form-item {
 | 
			
		||||
		display: unset !important;
 | 
			
		||||
	}
 | 
			
		||||
	.login-form .el-form-item {
 | 
			
		||||
		display: block !important;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								src/theme/media/home.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/theme/media/home.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
@import './index.scss';
 | 
			
		||||
 | 
			
		||||
/* 页面宽度小于1200px
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@media screen and (max-width: $lg) {
 | 
			
		||||
	.home-recommend-row {
 | 
			
		||||
		.home-recommend {
 | 
			
		||||
			margin-bottom: 15px;
 | 
			
		||||
		}
 | 
			
		||||
		& .el-col:last-of-type,
 | 
			
		||||
		& .el-col:nth-last-child(2) {
 | 
			
		||||
			.home-recommend {
 | 
			
		||||
				margin-bottom: 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	.home-lg {
 | 
			
		||||
		margin-bottom: 15px;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 页面宽度小于992px
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@media screen and (max-width: $md) {
 | 
			
		||||
	.home-recommend-row {
 | 
			
		||||
		& .el-col:nth-last-child(2) {
 | 
			
		||||
			margin-bottom: 15px;
 | 
			
		||||
		}
 | 
			
		||||
		& .el-col:last-of-type {
 | 
			
		||||
			.home-recommend {
 | 
			
		||||
				margin-bottom: 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								src/theme/media/index.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/theme/media/index.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
/* 栅格布局(媒体查询变量)
 | 
			
		||||
* $xs <768px  响应式栅格
 | 
			
		||||
* $sm ≥768px  响应式栅格
 | 
			
		||||
* $md ≥992px  响应式栅格
 | 
			
		||||
* $lg ≥1200px 响应式栅格
 | 
			
		||||
* $xl ≥1920px 响应式栅格
 | 
			
		||||
------------------------------- */
 | 
			
		||||
$xs: 576px;
 | 
			
		||||
$sm: 768px;
 | 
			
		||||
$md: 992px;
 | 
			
		||||
$lg: 1200px;
 | 
			
		||||
$xl: 1920px;
 | 
			
		||||
 | 
			
		||||
/* 页面宽度小于576px
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@media screen and (max-width: $xs) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 页面宽度小于768px
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@media screen and (max-width: $sm) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 页面宽度大于768px小于992px
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@media screen and (min-width: $sm) and (max-width: $md) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 页面宽度大于992px小于1200px
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@media screen and (min-width: $md) and (max-width: $lg) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 页面宽度大于1920px
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@media screen and (min-width: $xl) {
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										55
									
								
								src/theme/media/layout.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/theme/media/layout.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
@import './index.scss';
 | 
			
		||||
 | 
			
		||||
/* 页面宽度小于576px
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@media screen and (max-width: $xs) {
 | 
			
		||||
	// MessageBox 弹框
 | 
			
		||||
	.el-message-box {
 | 
			
		||||
		width: 80% !important;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 页面宽度小于768px
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@media screen and (max-width: $sm) {
 | 
			
		||||
	// Breadcrumb 面包屑
 | 
			
		||||
	.layout-navbars-breadcrumb-hide {
 | 
			
		||||
		display: none;
 | 
			
		||||
	}
 | 
			
		||||
	// 外链视图
 | 
			
		||||
	.layout-view-link {
 | 
			
		||||
		a {
 | 
			
		||||
			max-width: 80%;
 | 
			
		||||
			text-align: center;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// 菜单搜索
 | 
			
		||||
	.layout-search-dialog {
 | 
			
		||||
		.el-autocomplete {
 | 
			
		||||
			width: 80% !important;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 页面宽度小于1000px
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@media screen and (max-width: 1000px) {
 | 
			
		||||
	// 布局配置
 | 
			
		||||
	.layout-drawer-content-flex {
 | 
			
		||||
		position: relative;
 | 
			
		||||
		&::after {
 | 
			
		||||
			content: '手机版不支持切换布局';
 | 
			
		||||
			position: absolute;
 | 
			
		||||
			top: 0;
 | 
			
		||||
			right: 0;
 | 
			
		||||
			bottom: 0;
 | 
			
		||||
			left: 0;
 | 
			
		||||
			z-index: 1;
 | 
			
		||||
			text-align: center;
 | 
			
		||||
			height: 140px;
 | 
			
		||||
			line-height: 140px;
 | 
			
		||||
			background: rgba(255, 255, 255, 0.9);
 | 
			
		||||
			color: #666666;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								src/theme/media/login.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/theme/media/login.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
@import './index.scss';
 | 
			
		||||
 | 
			
		||||
/* 页面宽度小于576px
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@media screen and (max-width: $xs) {
 | 
			
		||||
	.login-weaper {
 | 
			
		||||
		height: 420px !important;
 | 
			
		||||
		.login-left {
 | 
			
		||||
			display: none !important;
 | 
			
		||||
		}
 | 
			
		||||
		.login-right {
 | 
			
		||||
			width: 100% !important;
 | 
			
		||||
			border-top-left-radius: 4px;
 | 
			
		||||
			border-bottom-left-radius: 4px;
 | 
			
		||||
			.login-main {
 | 
			
		||||
				width: 94% !important;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 页面宽度大于576px小于992px
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@media screen and (min-width: $xs) and (max-width: $md) {
 | 
			
		||||
	.login-left {
 | 
			
		||||
		display: none !important;
 | 
			
		||||
	}
 | 
			
		||||
	.login-right {
 | 
			
		||||
		border-top-left-radius: 4px;
 | 
			
		||||
		border-bottom-left-radius: 4px;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								src/theme/media/media.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/theme/media/media.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
@import './login.scss';
 | 
			
		||||
@import './error.scss';
 | 
			
		||||
@import './home.scss';
 | 
			
		||||
@import './layout.scss';
 | 
			
		||||
@import './scrollbar.scss';
 | 
			
		||||
@import './dialog.scss';
 | 
			
		||||
@import './form.scss';
 | 
			
		||||
							
								
								
									
										13
									
								
								src/theme/media/scrollbar.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/theme/media/scrollbar.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
@import './index.scss';
 | 
			
		||||
 | 
			
		||||
/* 页面宽度小于768px
 | 
			
		||||
------------------------------- */
 | 
			
		||||
@media screen and (max-width: $sm) {
 | 
			
		||||
	// element plus scrollbar
 | 
			
		||||
	.el-scrollbar__bar.is-vertical {
 | 
			
		||||
		width: 2px !important;
 | 
			
		||||
	}
 | 
			
		||||
	.el-scrollbar__bar.is-horizontal {
 | 
			
		||||
		height: 2px !important;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										0
									
								
								src/theme/other.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/theme/other.scss
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										952
									
								
								src/theme/variables.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										952
									
								
								src/theme/variables.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,952 @@
 | 
			
		||||
/* Button 按钮
 | 
			
		||||
------------------------------- */
 | 
			
		||||
// text
 | 
			
		||||
.el-button--text {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
	&:focus,
 | 
			
		||||
	&:hover {
 | 
			
		||||
		color: var(--prev-color-primary-light-3);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
.el-button--text:active {
 | 
			
		||||
	color: var(--prev-color-primary-light-3);
 | 
			
		||||
}
 | 
			
		||||
// default
 | 
			
		||||
.el-button--default:hover,
 | 
			
		||||
.el-button--default:focus {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
	background: var(--prev-color-primary-light-8);
 | 
			
		||||
	border-color: var(--prev-color-primary-light-6);
 | 
			
		||||
}
 | 
			
		||||
.el-button--default.is-plain:hover,
 | 
			
		||||
.el-button--default.is-plain:focus {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
	background: var(--prev-bg-white);
 | 
			
		||||
	border-color: var(--prev-color-primary-light-1);
 | 
			
		||||
}
 | 
			
		||||
.el-button--default:active {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
	background: var(--prev-bg-white);
 | 
			
		||||
	border-color: var(--prev-color-primary-light-1);
 | 
			
		||||
}
 | 
			
		||||
// primary
 | 
			
		||||
.el-button--primary {
 | 
			
		||||
	color: var(--prev-color-text-white) !important;
 | 
			
		||||
	background: var(--prev-color-primary) !important;
 | 
			
		||||
	border-color: var(--prev-color-primary) !important;
 | 
			
		||||
	&:hover,
 | 
			
		||||
	&:focus {
 | 
			
		||||
		color: var(--prev-color-text-white) !important;
 | 
			
		||||
		background: var(--prev-color-primary-light-3) !important;
 | 
			
		||||
		border-color: var(--prev-color-primary-light-3) !important;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
.el-button--primary.is-plain {
 | 
			
		||||
	color: var(--prev-color-primary) !important;
 | 
			
		||||
	background: var(--prev-color-primary-light-8) !important;
 | 
			
		||||
	border-color: var(--prev-color-primary-light-6) !important;
 | 
			
		||||
	&:hover,
 | 
			
		||||
	&:focus {
 | 
			
		||||
		color: var(--prev-color-text-white) !important;
 | 
			
		||||
		background: var(--prev-color-primary) !important;
 | 
			
		||||
		border-color: var(--prev-color-primary) !important;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
.el-button--primary.is-disabled,
 | 
			
		||||
.el-button--primary.is-disabled:active,
 | 
			
		||||
.el-button--primary.is-disabled:focus,
 | 
			
		||||
.el-button--primary.is-disabled:hover {
 | 
			
		||||
	color: var(--prev-color-primary) !important;
 | 
			
		||||
	background: var(--prev-color-primary-light-7) !important;
 | 
			
		||||
	border-color: var(--prev-color-primary-light-7) !important;
 | 
			
		||||
}
 | 
			
		||||
.el-button--primary.is-active,
 | 
			
		||||
.el-button--primary:active {
 | 
			
		||||
	color: var(--prev-color-text-white) !important;
 | 
			
		||||
	background: var(--prev-color-primary) !important;
 | 
			
		||||
	border-color: var(--prev-color-primary) !important;
 | 
			
		||||
}
 | 
			
		||||
.el-button.is-disabled.is-plain,
 | 
			
		||||
.el-button.is-disabled.is-plain:focus,
 | 
			
		||||
.el-button.is-disabled.is-plain:hover {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	border-color: var(--prev-border-color-lighter);
 | 
			
		||||
	color: var(--prev-color-text-placeholder);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Link 文字链接
 | 
			
		||||
------------------------------- */
 | 
			
		||||
// default
 | 
			
		||||
.el-link.el-link--default:hover {
 | 
			
		||||
	color: var(--prev-color-primary-light-3);
 | 
			
		||||
}
 | 
			
		||||
// primary
 | 
			
		||||
.el-link.el-link--primary {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
	&:hover {
 | 
			
		||||
		color: var(--prev-color-primary-light-3);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
.el-link.el-link--default::after,
 | 
			
		||||
.el-link.is-underline:hover::after,
 | 
			
		||||
.el-link.el-link--primary.is-underline:hover::after,
 | 
			
		||||
.el-link.el-link--primary::after {
 | 
			
		||||
	border-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Radio 单选框
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-radio,
 | 
			
		||||
.el-checkbox {
 | 
			
		||||
	color: var(--prev-color-text-regular);
 | 
			
		||||
}
 | 
			
		||||
.el-radio__input.is-checked + .el-radio__label,
 | 
			
		||||
.el-radio-button__inner:hover {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-radio__input.is-checked .el-radio__inner {
 | 
			
		||||
	background-color: var(--prev-color-primary);
 | 
			
		||||
	border-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-radio-button__orig-radio:checked + .el-radio-button__inner {
 | 
			
		||||
	color: var(--prev-color-text-white);
 | 
			
		||||
	background-color: var(--prev-color-primary);
 | 
			
		||||
	border-color: var(--prev-color-primary);
 | 
			
		||||
	box-shadow: -1px 0 0 0 var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-radio.is-bordered.is-checked,
 | 
			
		||||
.el-radio__inner:hover {
 | 
			
		||||
	border-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-radio-button__inner,
 | 
			
		||||
.el-checkbox-button__inner {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	color: var(--prev-color-text-regular);
 | 
			
		||||
	border-color: var(--prev-border-color-base);
 | 
			
		||||
}
 | 
			
		||||
.el-radio-button:first-child .el-radio-button__inner,
 | 
			
		||||
.el-checkbox-button:first-child .el-checkbox-button__inner {
 | 
			
		||||
	border-left-color: var(--prev-border-color-base);
 | 
			
		||||
}
 | 
			
		||||
.el-radio.is-bordered,
 | 
			
		||||
.el-checkbox.is-bordered {
 | 
			
		||||
	border-color: var(--prev-border-color-base);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Checkbox 多选框
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-checkbox__input.is-checked + .el-checkbox__label,
 | 
			
		||||
.el-checkbox-button__inner:hover {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-checkbox__input.is-checked .el-checkbox__inner {
 | 
			
		||||
	background-color: var(--prev-color-primary);
 | 
			
		||||
	border-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-checkbox__input.is-focus .el-checkbox__inner,
 | 
			
		||||
.el-checkbox__inner:hover,
 | 
			
		||||
.el-checkbox.is-bordered.is-checked,
 | 
			
		||||
.el-checkbox-button.is-focus .el-checkbox-button__inner {
 | 
			
		||||
	border-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-checkbox-button.is-checked .el-checkbox-button__inner {
 | 
			
		||||
	color: var(--prev-color-text-white);
 | 
			
		||||
	background-color: var(--prev-color-primary);
 | 
			
		||||
	border-color: var(--prev-color-primary);
 | 
			
		||||
	box-shadow: -1px 0 0 0 var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-checkbox-button.is-checked:first-child .el-checkbox-button__inner {
 | 
			
		||||
	border-left-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-checkbox__input.is-checked .el-checkbox__inner,
 | 
			
		||||
.el-checkbox__input.is-indeterminate .el-checkbox__inner {
 | 
			
		||||
	background-color: var(--prev-color-primary);
 | 
			
		||||
	border-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-checkbox-button.is-disabled .el-checkbox-button__inner {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	border-color: var(--prev-border-color-base);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Input 输入框、InputNumber 计数器
 | 
			
		||||
------------------------------- */
 | 
			
		||||
// input-number
 | 
			
		||||
.el-input__inner:focus,
 | 
			
		||||
.el-input-number__decrease:hover:not(.is-disabled) ~ .el-input .el-input__inner:not(.is-disabled),
 | 
			
		||||
.el-input-number__increase:hover:not(.is-disabled) ~ .el-input .el-input__inner:not(.is-disabled),
 | 
			
		||||
.el-textarea__inner:focus {
 | 
			
		||||
	border-color: var(--prev-color-primary) !important;
 | 
			
		||||
}
 | 
			
		||||
.el-input-number__increase:hover,
 | 
			
		||||
.el-input-number__decrease:hover {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-input-number__decrease,
 | 
			
		||||
.el-input-number__increase {
 | 
			
		||||
	background-color: var(--prev-bg-color);
 | 
			
		||||
	border-color: var(--prev-border-color-base) !important;
 | 
			
		||||
}
 | 
			
		||||
// input
 | 
			
		||||
.el-input__inner,
 | 
			
		||||
.el-textarea__inner {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	border-color: var(--prev-border-color-base);
 | 
			
		||||
	color: var(--prev-color-text-regular);
 | 
			
		||||
	&:hover {
 | 
			
		||||
		border-color: var(--prev-border-color-hover);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
.el-input.is-disabled .el-input__inner,
 | 
			
		||||
.el-textarea.is-disabled .el-textarea__inner {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	border-color: var(--prev-border-color-base);
 | 
			
		||||
}
 | 
			
		||||
.el-input-group__append,
 | 
			
		||||
.el-input-group__prepend {
 | 
			
		||||
	background-color: var(--prev-bg-color);
 | 
			
		||||
	color: var(--prev-color-text-regular);
 | 
			
		||||
	border-color: var(--prev-border-color-base);
 | 
			
		||||
}
 | 
			
		||||
.el-input .el-input__count .el-input__count-inner {
 | 
			
		||||
	background-color: var(--prev-bg-color);
 | 
			
		||||
}
 | 
			
		||||
// autocomplete
 | 
			
		||||
.el-autocomplete-suggestion {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	border-color: var(--prev-border-color-base);
 | 
			
		||||
}
 | 
			
		||||
.el-autocomplete-suggestion__wrap {
 | 
			
		||||
	max-height: 280px !important;
 | 
			
		||||
}
 | 
			
		||||
// scss 循环
 | 
			
		||||
$positions: 'top', 'right', 'bottom', 'left';
 | 
			
		||||
@each $i in $positions {
 | 
			
		||||
	.el-popper[x-placement^='#{$i}'] .popper__arrow {
 | 
			
		||||
		border-#{$i}-color: var(--prev-border-color-base);
 | 
			
		||||
		&::after {
 | 
			
		||||
			border-#{$i}-color: var(--prev-bg-white);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
.el-autocomplete-suggestion li {
 | 
			
		||||
	color: var(--prev-color-text-regular);
 | 
			
		||||
}
 | 
			
		||||
.el-autocomplete-suggestion li.highlighted,
 | 
			
		||||
.el-autocomplete-suggestion li:hover {
 | 
			
		||||
	background-color: var(--prev-color-hover);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Select 选择器
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-range-editor.is-active,
 | 
			
		||||
.el-range-editor.is-active:hover,
 | 
			
		||||
.el-select .el-input.is-focus .el-input__inner,
 | 
			
		||||
.el-select .el-input__inner:focus {
 | 
			
		||||
	border-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-select-dropdown__item.selected {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-select-dropdown {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	border-color: var(--prev-border-color-light);
 | 
			
		||||
}
 | 
			
		||||
.el-select-dropdown__item {
 | 
			
		||||
	color: var(--prev-color-text-regular);
 | 
			
		||||
}
 | 
			
		||||
.el-select-dropdown__item.hover,
 | 
			
		||||
.el-select-dropdown__item:hover {
 | 
			
		||||
	background-color: var(--prev-color-hover);
 | 
			
		||||
}
 | 
			
		||||
.el-select-dropdown__item.is-disabled:hover {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
}
 | 
			
		||||
.el-select .el-input.is-disabled .el-input__inner:hover {
 | 
			
		||||
	border-color: var(--prev-border-color-light);
 | 
			
		||||
}
 | 
			
		||||
.el-select:hover .el-input__inner {
 | 
			
		||||
	border-color: var(--prev-border-color-hover);
 | 
			
		||||
}
 | 
			
		||||
.el-select-dropdown.is-multiple .el-select-dropdown__item.selected {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
}
 | 
			
		||||
.el-select-dropdown.is-multiple .el-select-dropdown__item.selected.hover {
 | 
			
		||||
	background-color: var(--prev-color-hover);
 | 
			
		||||
}
 | 
			
		||||
.el-select-group__wrap:not(:last-of-type)::after {
 | 
			
		||||
	background: var(--prev-border-color-light);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Cascader 级联选择器
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-cascader .el-input .el-input__inner:focus,
 | 
			
		||||
.el-cascader .el-input.is-focus .el-input__inner {
 | 
			
		||||
	border-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-cascader-node.in-active-path,
 | 
			
		||||
.el-cascader-node.is-active,
 | 
			
		||||
.el-cascader-node.is-selectable.in-checked-path {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-cascader__dropdown {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	border-color: var(--prev-border-color-light);
 | 
			
		||||
}
 | 
			
		||||
.el-cascader-menu {
 | 
			
		||||
	border-color: var(--prev-border-color-light);
 | 
			
		||||
	color: var(--prev-color-text-regular);
 | 
			
		||||
}
 | 
			
		||||
.el-cascader-node:not(.is-disabled):focus,
 | 
			
		||||
.el-cascader-node:not(.is-disabled):hover {
 | 
			
		||||
	background-color: var(--prev-color-hover);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Switch 开关
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-switch.is-checked .el-switch__core {
 | 
			
		||||
	border-color: var(--prev-color-primary);
 | 
			
		||||
	background-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-switch__label.is-active {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Slider 滑块
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-slider__bar {
 | 
			
		||||
	background-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-slider__button {
 | 
			
		||||
	border-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-slider__runway {
 | 
			
		||||
	background-color: var(--prev-border-color-light);
 | 
			
		||||
}
 | 
			
		||||
.el-slider__marks-text {
 | 
			
		||||
	color: var(--prev-color-text-secondary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* TimePicker 时间选择器
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-time-panel__btn.confirm,
 | 
			
		||||
.el-time-spinner__arrow:hover,
 | 
			
		||||
.time-select-item.selected:not(.disabled) {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-picker-panel {
 | 
			
		||||
	border-color: var(--prev-border-color-light);
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	color: var(--prev-color-text-regular);
 | 
			
		||||
}
 | 
			
		||||
.time-select-item:hover,
 | 
			
		||||
.el-time-spinner__item:hover:not(.disabled):not(.active),
 | 
			
		||||
.el-time-spinner__wrapper.is-arrow .el-time-spinner__item:hover:not(.disabled):not(.active) {
 | 
			
		||||
	background-color: var(--prev-color-hover);
 | 
			
		||||
}
 | 
			
		||||
.el-time-panel {
 | 
			
		||||
	border-color: var(--prev-border-color-light);
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
}
 | 
			
		||||
.el-time-panel__footer,
 | 
			
		||||
.el-time-panel__content::after,
 | 
			
		||||
.el-time-panel__content::before,
 | 
			
		||||
.el-time-range-picker__body {
 | 
			
		||||
	border-color: var(--prev-border-color-light);
 | 
			
		||||
}
 | 
			
		||||
.el-time-panel__btn,
 | 
			
		||||
.el-date-editor .el-range-separator {
 | 
			
		||||
	color: var(--prev-color-text-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-date-editor .el-range-input {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	color: var(--prev-color-text-primary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* DatePicker 日期选择器
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-date-table td.today span,
 | 
			
		||||
.el-date-table td.available:hover,
 | 
			
		||||
.el-date-picker__header-label.active,
 | 
			
		||||
.el-date-picker__header-label:hover,
 | 
			
		||||
.el-picker-panel__icon-btn:hover,
 | 
			
		||||
.el-year-table td.today .cell,
 | 
			
		||||
.el-year-table td .cell:hover,
 | 
			
		||||
.el-year-table td.current:not(.disabled) .cell,
 | 
			
		||||
.el-month-table td .cell:hover,
 | 
			
		||||
.el-month-table td.today .cell,
 | 
			
		||||
.el-month-table td.current:not(.disabled) .cell,
 | 
			
		||||
.el-picker-panel__shortcut:hover {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-date-table td.current:not(.disabled) span,
 | 
			
		||||
.el-date-table td.selected span {
 | 
			
		||||
	color: var(--prev-color-text-white);
 | 
			
		||||
	background-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-date-table td.end-date span,
 | 
			
		||||
.el-date-table td.start-date span,
 | 
			
		||||
.el-month-table td.end-date .cell,
 | 
			
		||||
.el-month-table td.start-date .cell {
 | 
			
		||||
	background-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-date-table td.in-range div,
 | 
			
		||||
.el-date-table td.in-range div:hover,
 | 
			
		||||
.el-date-table.is-week-mode .el-date-table__row.current div,
 | 
			
		||||
.el-date-table.is-week-mode .el-date-table__row:hover div,
 | 
			
		||||
.el-date-table td.selected div {
 | 
			
		||||
	background-color: var(--prev-color-primary-light-9);
 | 
			
		||||
}
 | 
			
		||||
.el-date-table th,
 | 
			
		||||
.el-date-picker__header--bordered,
 | 
			
		||||
.el-date-range-picker__content.is-left,
 | 
			
		||||
.el-date-picker__time-header,
 | 
			
		||||
.el-date-range-picker__time-header {
 | 
			
		||||
	border-color: var(--prev-border-color-lighter);
 | 
			
		||||
}
 | 
			
		||||
.el-date-table th,
 | 
			
		||||
.el-date-picker__header-label,
 | 
			
		||||
.el-picker-panel__shortcut,
 | 
			
		||||
.el-month-table td .cell,
 | 
			
		||||
.el-year-table td .cell {
 | 
			
		||||
	color: var(--prev-color-text-regular);
 | 
			
		||||
}
 | 
			
		||||
.el-date-table td.next-month,
 | 
			
		||||
.el-date-table td.prev-month {
 | 
			
		||||
	color: var(--prev-border-color-hover);
 | 
			
		||||
}
 | 
			
		||||
.el-picker-panel__icon-btn {
 | 
			
		||||
	color: var(--prev-color-text-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-date-table td.disabled div {
 | 
			
		||||
	background-color: var(--prev-bg-color);
 | 
			
		||||
}
 | 
			
		||||
.el-picker-panel [slot='sidebar'],
 | 
			
		||||
.el-picker-panel__sidebar,
 | 
			
		||||
.el-picker-panel__footer {
 | 
			
		||||
	border-color: var(--prev-border-color-light);
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
}
 | 
			
		||||
.el-month-table td.end-date .cell,
 | 
			
		||||
.el-month-table td.start-date .cell {
 | 
			
		||||
	color: var(--prev-color-text-white);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Upload 上传
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-upload-list__item.is-success .el-upload-list__item-name:focus,
 | 
			
		||||
.el-upload-list__item.is-success .el-upload-list__item-name:hover,
 | 
			
		||||
.el-upload-list__item .el-icon-close-tip,
 | 
			
		||||
.el-upload-dragger .el-upload__text em {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-upload--picture-card,
 | 
			
		||||
.el-upload-dragger {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	border-color: var(--prev-border-color-light);
 | 
			
		||||
	i {
 | 
			
		||||
		color: var(--prev-color-text-regular);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
.el-upload--picture-card:hover,
 | 
			
		||||
.el-upload:focus {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
	border-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-upload-dragger:hover,
 | 
			
		||||
.el-upload:focus .el-upload-dragger {
 | 
			
		||||
	border-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-upload__tip,
 | 
			
		||||
.el-upload-list__item,
 | 
			
		||||
.el-upload-dragger .el-upload__text,
 | 
			
		||||
.el-upload-list__item-name,
 | 
			
		||||
.el-upload-list__item .el-icon-close {
 | 
			
		||||
	color: var(--prev-color-text-regular);
 | 
			
		||||
}
 | 
			
		||||
.el-upload-list__item:hover {
 | 
			
		||||
	background-color: var(--prev-bg-color);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ColorPicker 颜色选择器
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-color-picker__trigger {
 | 
			
		||||
	border-color: var(--prev-border-color-light);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Transfer 穿梭框
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-transfer-panel__item:hover {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-transfer-panel,
 | 
			
		||||
.el-transfer-panel .el-transfer-panel__header {
 | 
			
		||||
	border-color: var(--prev-border-color-lighter);
 | 
			
		||||
}
 | 
			
		||||
.el-transfer-panel .el-transfer-panel__footer {
 | 
			
		||||
	border-color: var(--prev-border-color-lighter);
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
}
 | 
			
		||||
.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label {
 | 
			
		||||
	color: var(--prev-color-text-primary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Form 表单
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-form {
 | 
			
		||||
	.el-form-item:last-of-type {
 | 
			
		||||
		margin-bottom: 0 !important;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
.el-form-item__label {
 | 
			
		||||
	color: var(--prev-color-text-regular);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Table 表格
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-table {
 | 
			
		||||
	color: var(--prev-color-text-regular);
 | 
			
		||||
}
 | 
			
		||||
.el-table .descending .sort-caret.descending {
 | 
			
		||||
	border-top-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-table .ascending .sort-caret.ascending {
 | 
			
		||||
	border-bottom-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-table thead {
 | 
			
		||||
	color: var(--prev-color-text-secondary);
 | 
			
		||||
}
 | 
			
		||||
.el-table td.el-table__cell,
 | 
			
		||||
.el-table th.el-table__cell.is-leaf,
 | 
			
		||||
.el-table--border,
 | 
			
		||||
.el-table--group {
 | 
			
		||||
	border-color: var(--prev-border-color-lighter) !important;
 | 
			
		||||
}
 | 
			
		||||
.el-table th.el-table__cell,
 | 
			
		||||
.el-table tr {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
}
 | 
			
		||||
.el-table--striped .el-table__body tr.el-table__row--striped td.el-table__cell,
 | 
			
		||||
.el-table--enable-row-hover .el-table__body tr:hover > td.el-table__cell {
 | 
			
		||||
	background-color: var(--prev-bg-color);
 | 
			
		||||
}
 | 
			
		||||
.el-table--border::after,
 | 
			
		||||
.el-table--group::after,
 | 
			
		||||
.el-table::before {
 | 
			
		||||
	background-color: var(--prev-border-color-lighter);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Tag 标签
 | 
			
		||||
------------------------------- */
 | 
			
		||||
// primary
 | 
			
		||||
.el-tag {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
	background-color: var(--prev-color-primary-light-8);
 | 
			
		||||
	border-color: var(--prev-color-primary-light-6);
 | 
			
		||||
}
 | 
			
		||||
.el-tag .el-tag__close {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
	&:hover {
 | 
			
		||||
		color: var(--prev-color-text-white);
 | 
			
		||||
		background-color: var(--prev-color-primary);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
.el-tag--dark {
 | 
			
		||||
	color: var(--prev-color-text-white);
 | 
			
		||||
	background-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-tag--dark .el-tag__close {
 | 
			
		||||
	color: var(--prev-color-text-white);
 | 
			
		||||
	&:hover {
 | 
			
		||||
		background-color: var(--prev-color-primary-light-3);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
.el-tag--plain {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	border-color: var(--prev-color-primary-light-3);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Progress 进度条
 | 
			
		||||
------------------------------- */
 | 
			
		||||
// primary
 | 
			
		||||
.el-progress-bar__inner {
 | 
			
		||||
	background-color: var(--prev-color-primary) !important;
 | 
			
		||||
}
 | 
			
		||||
.el-progress-bar__outer {
 | 
			
		||||
	background-color: var(--prev-border-color-lighter);
 | 
			
		||||
}
 | 
			
		||||
.el-progress__text {
 | 
			
		||||
	color: var(--prev-color-text-regular);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Tree 树形控件
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-tree {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	color: var(--prev-color-text-regular);
 | 
			
		||||
}
 | 
			
		||||
.el-tree-node__content:hover,
 | 
			
		||||
.el-tree-node:focus > .el-tree-node__content {
 | 
			
		||||
	background-color: var(--prev-bg-color);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Pagination 分页
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-pager li.active,
 | 
			
		||||
.el-pager li:hover,
 | 
			
		||||
.el-pagination button:hover,
 | 
			
		||||
.el-pagination.is-background .el-pager li:not(.disabled):hover {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-pagination__sizes .el-input .el-input__inner:hover {
 | 
			
		||||
	border-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-pagination.is-background .el-pager li:not(.disabled).active {
 | 
			
		||||
	background-color: var(--prev-color-primary);
 | 
			
		||||
	color: var(--prev-color-text-white);
 | 
			
		||||
}
 | 
			
		||||
.el-pagination__total,
 | 
			
		||||
.el-pagination__jump {
 | 
			
		||||
	color: var(--prev-color-text-regular);
 | 
			
		||||
}
 | 
			
		||||
.el-pagination button:disabled,
 | 
			
		||||
.el-pagination .btn-next,
 | 
			
		||||
.el-pagination .btn-prev {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
}
 | 
			
		||||
.el-pagination .btn-next,
 | 
			
		||||
.el-pagination .btn-prev {
 | 
			
		||||
	color: var(--prev-color-text-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-pager li {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	color: var(--prev-color-text-primary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Badge 标记
 | 
			
		||||
------------------------------- */
 | 
			
		||||
// primary
 | 
			
		||||
.el-badge__content--primary {
 | 
			
		||||
	background-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Loading 加载
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-loading-spinner .path {
 | 
			
		||||
	stroke: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-loading-spinner .el-loading-text,
 | 
			
		||||
.el-loading-spinner i {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Message 消息提示
 | 
			
		||||
------------------------------- */
 | 
			
		||||
// default/info
 | 
			
		||||
.el-message {
 | 
			
		||||
	min-width: unset !important;
 | 
			
		||||
	padding: 15px !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* MessageBox 弹框
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-message-box__headerbtn:focus .el-message-box__close,
 | 
			
		||||
.el-message-box__headerbtn:hover .el-message-box__close {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-message-box {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	border-color: var(--prev-border-color-lighter);
 | 
			
		||||
}
 | 
			
		||||
.el-message-box__title {
 | 
			
		||||
	color: var(--prev-color-text-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-message-box__content {
 | 
			
		||||
	color: var(--prev-color-text-regular);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Notification 通知
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-notification {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	border-color: var(--prev-border-color-lighter);
 | 
			
		||||
	.el-notification__title {
 | 
			
		||||
		color: var(--prev-color-text-primary);
 | 
			
		||||
	}
 | 
			
		||||
	.el-notification__content {
 | 
			
		||||
		color: var(--prev-color-text-regular);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Tabs 标签页
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-tabs__item.is-active,
 | 
			
		||||
.el-tabs__item:hover,
 | 
			
		||||
.el-tabs--border-card > .el-tabs__header .el-tabs__item.is-active,
 | 
			
		||||
.el-tabs--border-card > .el-tabs__header .el-tabs__item:not(.is-disabled):hover {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-tabs__active-bar {
 | 
			
		||||
	background-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-tabs__nav-wrap::after {
 | 
			
		||||
	height: 1px !important;
 | 
			
		||||
}
 | 
			
		||||
.el-tabs__item {
 | 
			
		||||
	color: var(--prev-color-text-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-tabs__nav-wrap::after {
 | 
			
		||||
	background-color: var(--prev-border-color-light);
 | 
			
		||||
}
 | 
			
		||||
.el-tabs--card > .el-tabs__header .el-tabs__item.is-active,
 | 
			
		||||
.el-tabs--card > .el-tabs__header .el-tabs__item,
 | 
			
		||||
.el-tabs--card > .el-tabs__header,
 | 
			
		||||
.el-tabs--card > .el-tabs__header .el-tabs__nav {
 | 
			
		||||
	border-color: var(--prev-bg-color);
 | 
			
		||||
}
 | 
			
		||||
.el-tabs--border-card {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	border-color: var(--prev-border-color-base);
 | 
			
		||||
}
 | 
			
		||||
.el-tabs--border-card > .el-tabs__header {
 | 
			
		||||
	background-color: var(--prev-bg-color);
 | 
			
		||||
	border-color: var(--prev-border-color-light);
 | 
			
		||||
}
 | 
			
		||||
.el-tabs--border-card > .el-tabs__header .el-tabs__item.is-active {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	border-color: var(--prev-border-color-base);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Breadcrumb 面包屑
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-breadcrumb__inner a:hover,
 | 
			
		||||
.el-breadcrumb__inner.is-link:hover {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-breadcrumb__inner a,
 | 
			
		||||
.el-breadcrumb__inner.is-link {
 | 
			
		||||
	color: var(--bg-topBarColor);
 | 
			
		||||
	font-weight: normal;
 | 
			
		||||
}
 | 
			
		||||
.el-breadcrumb__inner a,
 | 
			
		||||
.el-breadcrumb__inner.is-link {
 | 
			
		||||
	color: var(--prev-color-text-black);
 | 
			
		||||
	opacity: 0.7;
 | 
			
		||||
}
 | 
			
		||||
.el-breadcrumb__separator {
 | 
			
		||||
	color: var(--prev-border-color-hover);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* PageHeader 页头
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-page-header__left {
 | 
			
		||||
	color: var(--prev-color-text-black);
 | 
			
		||||
	&::after {
 | 
			
		||||
		background-color: var(--prev-border-color-base);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
.el-page-header__content {
 | 
			
		||||
	color: var(--prev-color-text-primary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Dropdown 下拉菜单
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-dropdown-menu__item:focus,
 | 
			
		||||
.el-dropdown-menu__item:not(.is-disabled):hover {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
	background-color: var(--prev-color-primary-light-9);
 | 
			
		||||
}
 | 
			
		||||
.el-dropdown-menu {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	border-color: var(--prev-border-color-lighter);
 | 
			
		||||
}
 | 
			
		||||
.el-dropdown-menu__item {
 | 
			
		||||
	color: var(--prev-color-text-regular);
 | 
			
		||||
}
 | 
			
		||||
.el-dropdown-menu__item--divided {
 | 
			
		||||
	border-color: var(--prev-border-color-lighter);
 | 
			
		||||
}
 | 
			
		||||
.el-dropdown-menu__item--divided:before {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Steps 步骤条
 | 
			
		||||
------------------------------- */
 | 
			
		||||
// default
 | 
			
		||||
.el-step__title.is-finish,
 | 
			
		||||
.el-step__description.is-finish,
 | 
			
		||||
.el-step__head.is-finish {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-step__head.is-finish {
 | 
			
		||||
	border-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Dialog 对话框
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-dialog__headerbtn:focus .el-dialog__close,
 | 
			
		||||
.el-dialog__headerbtn:hover .el-dialog__close {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-dialog {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
}
 | 
			
		||||
.el-dialog__title {
 | 
			
		||||
	color: var(--prev-color-text-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-dialog__body {
 | 
			
		||||
	color: var(--prev-color-text-regular);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Popover 弹出框
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-popover {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	border-color: var(--prev-border-color-lighter);
 | 
			
		||||
	color: var(--prev-color-text-regular);
 | 
			
		||||
}
 | 
			
		||||
.el-popover__title {
 | 
			
		||||
	color: var(--prev-color-text-primary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Card 卡片
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-card {
 | 
			
		||||
	color: var(--prev-color-text-primary);
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	border-color: var(--prev-border-color-lighter);
 | 
			
		||||
}
 | 
			
		||||
.el-card__header {
 | 
			
		||||
	padding: 15px 20px;
 | 
			
		||||
	border-bottom-color: var(--prev-border-color-lighter);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Collapse 折叠面板
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-collapse {
 | 
			
		||||
	border-color: var(--prev-border-color-lighter);
 | 
			
		||||
}
 | 
			
		||||
.el-collapse-item__header {
 | 
			
		||||
	color: var(--prev-color-text-primary);
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	border-color: var(--prev-border-color-lighter);
 | 
			
		||||
}
 | 
			
		||||
.el-collapse-item__wrap {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
	border-color: var(--prev-border-color-lighter);
 | 
			
		||||
}
 | 
			
		||||
.el-collapse-item__content {
 | 
			
		||||
	color: var(--prev-color-text-primary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Timeline 时间线
 | 
			
		||||
------------------------------- */
 | 
			
		||||
// primary
 | 
			
		||||
.el-timeline-item__node--primary {
 | 
			
		||||
	background-color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-timeline-item__content {
 | 
			
		||||
	color: var(--prev-color-text-primary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Divider 分割线
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-divider {
 | 
			
		||||
	background-color: var(--prev-border-color-base);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Calendar 日历
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-calendar-table td {
 | 
			
		||||
	color: var(--prev-color-text-black);
 | 
			
		||||
}
 | 
			
		||||
.el-calendar-table td.is-today {
 | 
			
		||||
	color: var(--prev-color-primary) !important;
 | 
			
		||||
	background-color: var(--prev-color-primary-light-9);
 | 
			
		||||
}
 | 
			
		||||
.el-calendar-table .el-calendar-day:hover,
 | 
			
		||||
.el-calendar-table td.is-selected {
 | 
			
		||||
	background-color: var(--prev-color-primary-light-9);
 | 
			
		||||
	color: var(--prev-color-primary) !important;
 | 
			
		||||
}
 | 
			
		||||
.el-calendar {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
}
 | 
			
		||||
.el-calendar__title {
 | 
			
		||||
	color: var(--prev-color-text-black);
 | 
			
		||||
}
 | 
			
		||||
.el-calendar__header,
 | 
			
		||||
.el-calendar-table tr:first-child td,
 | 
			
		||||
.el-calendar-table td,
 | 
			
		||||
.el-calendar-table tr td:first-child {
 | 
			
		||||
	border-color: var(--prev-border-color-lighter);
 | 
			
		||||
}
 | 
			
		||||
.el-calendar-table thead th {
 | 
			
		||||
	color: var(--prev-color-text-regular);
 | 
			
		||||
}
 | 
			
		||||
.el-calendar-table:not(.is-range) td.next,
 | 
			
		||||
.el-calendar-table:not(.is-range) td.prev {
 | 
			
		||||
	color: var(--prev-color-text-placeholder);
 | 
			
		||||
}
 | 
			
		||||
.el-calendar__button-group {
 | 
			
		||||
	.el-button {
 | 
			
		||||
		color: var(--prev-color-text-regular);
 | 
			
		||||
		background-color: var(--prev-bg-white);
 | 
			
		||||
		border-color: var(--prev-border-color-base);
 | 
			
		||||
		&:focus,
 | 
			
		||||
		&:hover {
 | 
			
		||||
			color: var(--prev-color-primary) !important;
 | 
			
		||||
			background: var(--prev-color-primary-light-8) !important;
 | 
			
		||||
			border-color: var(--prev-color-primary-light-6) !important;
 | 
			
		||||
		}
 | 
			
		||||
		&:active {
 | 
			
		||||
			color: var(--prev-color-primary-light-3);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Backtop 回到顶部
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-backtop {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
	&:hover {
 | 
			
		||||
		background-color: var(--prev-color-primary-light-9);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* scrollbar
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-scrollbar__wrap {
 | 
			
		||||
	overflow-x: hidden !important;
 | 
			
		||||
	max-height: 100%; /*防止页面切换时,滚动条高度不变的问题(滚动条高度非滚动条滚动高度)*/
 | 
			
		||||
}
 | 
			
		||||
.el-select-dropdown .el-scrollbar__wrap {
 | 
			
		||||
	overflow-x: scroll !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Drawer 抽屉
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.el-drawer,
 | 
			
		||||
.el-divider__text {
 | 
			
		||||
	background-color: var(--prev-bg-white);
 | 
			
		||||
}
 | 
			
		||||
.el-divider__text {
 | 
			
		||||
	color: var(--prev-color-text-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-drawer__close-btn:hover {
 | 
			
		||||
	color: var(--prev-color-primary);
 | 
			
		||||
}
 | 
			
		||||
.el-drawer__body {
 | 
			
		||||
	width: 100%;
 | 
			
		||||
	height: 100%;
 | 
			
		||||
	overflow: auto;
 | 
			
		||||
}
 | 
			
		||||
.el-drawer__header {
 | 
			
		||||
	padding: 0 15px !important;
 | 
			
		||||
	height: 50px;
 | 
			
		||||
	display: flex;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	margin-bottom: 0 !important;
 | 
			
		||||
	border-bottom: 1px solid var(--prev-border-color-lighter);
 | 
			
		||||
	color: var(--prev-color-text-primary);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										4
									
								
								src/utils/componentSize.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/utils/componentSize.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
import { Local } from '@/utils/storage.js';
 | 
			
		||||
 | 
			
		||||
// 全局组件大小
 | 
			
		||||
export const globalComponentSize = Local.get('themeConfigPrev') ? Local.get('themeConfigPrev').globalComponentSize : '';
 | 
			
		||||
							
								
								
									
										134
									
								
								src/utils/formatTime.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								src/utils/formatTime.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,134 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 年(Y) 可用1-4个占位符
 | 
			
		||||
 * 月(m)、日(d)、小时(H)、分(M)、秒(S) 可用1-2个占位符
 | 
			
		||||
 * 星期(W) 可用1-3个占位符
 | 
			
		||||
 * 季度(q为阿拉伯数字,Q为中文数字)可用1或4个占位符
 | 
			
		||||
 *
 | 
			
		||||
 * let date = new Date()
 | 
			
		||||
 * formatDate(date, "YYYY-mm-dd HH:MM:SS")           // 2020-02-09 14:04:23
 | 
			
		||||
 * formatDate(date, "YYYY-mm-dd HH:MM:SS Q")         // 2020-02-09 14:09:03 一
 | 
			
		||||
 * formatDate(date, "YYYY-mm-dd HH:MM:SS WWW")       // 2020-02-09 14:45:12 星期日
 | 
			
		||||
 * formatDate(date, "YYYY-mm-dd HH:MM:SS QQQQ")      // 2020-02-09 14:09:36 第一季度
 | 
			
		||||
 * formatDate(date, "YYYY-mm-dd HH:MM:SS WWW QQQQ")  // 2020-02-09 14:46:12 星期日 第一季度
 | 
			
		||||
 */
 | 
			
		||||
export function formatDate(date, format) {
 | 
			
		||||
	let we = date.getDay(); // 星期
 | 
			
		||||
	let qut = Math.floor((date.getMonth() + 3) / 3).toString(); // 季度
 | 
			
		||||
	const opt = {
 | 
			
		||||
		'Y+': date.getFullYear().toString(), // 年
 | 
			
		||||
		'm+': (date.getMonth() + 1).toString(), // 月(月份从0开始,要+1)
 | 
			
		||||
		'd+': date.getDate().toString(), // 日
 | 
			
		||||
		'H+': date.getHours().toString(), // 时
 | 
			
		||||
		'M+': date.getMinutes().toString(), // 分
 | 
			
		||||
		'S+': date.getSeconds().toString(), // 秒
 | 
			
		||||
		'q+': qut, // 季度
 | 
			
		||||
	};
 | 
			
		||||
	const week = {
 | 
			
		||||
		// 中文数字 (星期)
 | 
			
		||||
		'0': '日',
 | 
			
		||||
		'1': '一',
 | 
			
		||||
		'2': '二',
 | 
			
		||||
		'3': '三',
 | 
			
		||||
		'4': '四',
 | 
			
		||||
		'5': '五',
 | 
			
		||||
		'6': '六',
 | 
			
		||||
	};
 | 
			
		||||
	const quarter = {
 | 
			
		||||
		// 中文数字(季度)
 | 
			
		||||
		'1': '一',
 | 
			
		||||
		'2': '二',
 | 
			
		||||
		'3': '三',
 | 
			
		||||
		'4': '四',
 | 
			
		||||
	};
 | 
			
		||||
	if (/(W+)/.test(format)) {
 | 
			
		||||
		format = format.replace(RegExp.$1, RegExp.$1.length > 1 ? (RegExp.$1.length > 2 ? '星期' + week[we] : '周' + week[we]) : week[we]);
 | 
			
		||||
	}
 | 
			
		||||
	if (/(Q+)/.test(format)) {
 | 
			
		||||
		// 输入一个Q,只输出一个中文数字,输入4个Q,则拼接上字符串
 | 
			
		||||
		format = format.replace(RegExp.$1, RegExp.$1.length == 4 ? '第' + quarter[qut] + '季度' : quarter[qut]);
 | 
			
		||||
	}
 | 
			
		||||
	for (let k in opt) {
 | 
			
		||||
		let r = new RegExp('(' + k + ')').exec(format);
 | 
			
		||||
		if (r) {
 | 
			
		||||
			// 若输入的长度不为1,则前面补零
 | 
			
		||||
			format = format.replace(r[1], RegExp.$1.length == 1 ? opt[k] : opt[k].padStart(RegExp.$1.length, '0'));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return format;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 10秒:  10 * 1000
 | 
			
		||||
 * 1分:   60 * 1000
 | 
			
		||||
 * 1小时: 60 * 60 * 1000
 | 
			
		||||
 * 24小时:60 * 60 * 24 * 1000
 | 
			
		||||
 * 3天:   60 * 60* 24 * 1000 * 3
 | 
			
		||||
 *
 | 
			
		||||
 * let data = new Date()
 | 
			
		||||
 * formatPast(data)                                           // 刚刚
 | 
			
		||||
 * formatPast(data - 11 * 1000)                               // 11秒前
 | 
			
		||||
 * formatPast(data - 2 * 60 * 1000)                           // 2分钟前
 | 
			
		||||
 * formatPast(data - 60 * 60 * 2 * 1000)                      // 2小时前
 | 
			
		||||
 * formatPast(data - 60 * 60 * 2 * 1000)                      // 2小时前
 | 
			
		||||
 * formatPast(data - 60 * 60 * 71 * 1000)                     // 2天前
 | 
			
		||||
 * formatPast("2020-06-01")                                   // 2020-06-01
 | 
			
		||||
 * formatPast("2020-06-01", "YYYY-mm-dd HH:MM:SS WWW QQQQ")   // 2020-06-01 08:00:00 星期一 第二季度
 | 
			
		||||
 */
 | 
			
		||||
export function formatPast(param, format = 'YYYY-mm-dd') {
 | 
			
		||||
	// 传入格式处理、存储转换值
 | 
			
		||||
	let t, s;
 | 
			
		||||
	// 获取js 时间戳
 | 
			
		||||
	let time = new Date().getTime();
 | 
			
		||||
	// 是否是对象
 | 
			
		||||
	typeof param === 'string' || 'object' ? (t = new Date(param).getTime()) : (t = param);
 | 
			
		||||
	// 当前时间戳 - 传入时间戳
 | 
			
		||||
	time = Number.parseInt(time - t);
 | 
			
		||||
	if (time < 10000) {
 | 
			
		||||
		// 10秒内
 | 
			
		||||
		return '刚刚';
 | 
			
		||||
	} else if (time < 60000 && time >= 10000) {
 | 
			
		||||
		// 超过10秒少于1分钟内
 | 
			
		||||
		s = Math.floor(time / 1000);
 | 
			
		||||
		return `${s}秒前`;
 | 
			
		||||
	} else if (time < 3600000 && time >= 60000) {
 | 
			
		||||
		// 超过1分钟少于1小时
 | 
			
		||||
		s = Math.floor(time / 60000);
 | 
			
		||||
		return `${s}分钟前`;
 | 
			
		||||
	} else if (time < 86400000 && time >= 3600000) {
 | 
			
		||||
		// 超过1小时少于24小时
 | 
			
		||||
		s = Math.floor(time / 3600000);
 | 
			
		||||
		return `${s}小时前`;
 | 
			
		||||
	} else if (time < 259200000 && time >= 86400000) {
 | 
			
		||||
		// 超过1天少于3天内
 | 
			
		||||
		s = Math.floor(time / 86400000);
 | 
			
		||||
		return `${s}天前`;
 | 
			
		||||
	} else {
 | 
			
		||||
		// 超过3天
 | 
			
		||||
		let date = typeof param === 'string' || 'object' ? new Date(param) : param;
 | 
			
		||||
		return formatDate(date, format);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * formatAxis(new Date())   // 上午好
 | 
			
		||||
 */
 | 
			
		||||
export function formatAxis(param) {
 | 
			
		||||
	let hour = new Date(param).getHours();
 | 
			
		||||
	if (hour < 6) {
 | 
			
		||||
		return '凌晨好';
 | 
			
		||||
	} else if (hour < 9) {
 | 
			
		||||
		return '早上好';
 | 
			
		||||
	} else if (hour < 12) {
 | 
			
		||||
		return '上午好';
 | 
			
		||||
	} else if (hour < 14) {
 | 
			
		||||
		return '中午好';
 | 
			
		||||
	} else if (hour < 17) {
 | 
			
		||||
		return '下午好';
 | 
			
		||||
	} else if (hour < 19) {
 | 
			
		||||
		return '傍晚好';
 | 
			
		||||
	} else if (hour < 22) {
 | 
			
		||||
		return '晚上好';
 | 
			
		||||
	} else {
 | 
			
		||||
		return '夜里好';
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										99
									
								
								src/utils/getStyleSheets.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/utils/getStyleSheets.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,99 @@
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
 | 
			
		||||
// 获取阿里字体图标
 | 
			
		||||
const getAlicdnIconfont = () => {
 | 
			
		||||
	return new Promise((resolve, reject) => {
 | 
			
		||||
		Vue.nextTick(() => {
 | 
			
		||||
			const styles = document.styleSheets;
 | 
			
		||||
			let sheetsList = [];
 | 
			
		||||
			let sheetsIconList = [];
 | 
			
		||||
			for (let i = 0; i < styles.length; i++) {
 | 
			
		||||
				if (styles[i].href && styles[i].href.indexOf('at.alicdn.com') > -1) {
 | 
			
		||||
					sheetsList.push(styles[i]);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			for (let i = 0; i < sheetsList.length; i++) {
 | 
			
		||||
				for (let j = 0; j < sheetsList[i].cssRules.length; j++) {
 | 
			
		||||
					if (sheetsList[i].cssRules[j].selectorText && sheetsList[i].cssRules[j].selectorText.indexOf('.icon-') > -1) {
 | 
			
		||||
						sheetsIconList.push(
 | 
			
		||||
							`${sheetsList[i].cssRules[j].selectorText.substring(1, sheetsList[i].cssRules[j].selectorText.length).replace(/\\:\\:before/gi, '')}`
 | 
			
		||||
						);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (sheetsIconList.length > 0) resolve(sheetsIconList);
 | 
			
		||||
			else reject('未获取到值,请刷新重试');
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 初始化获取 css 样式,获取 element plus 自带图标
 | 
			
		||||
const getElementPlusIconfont = () => {
 | 
			
		||||
	return new Promise((resolve, reject) => {
 | 
			
		||||
		Vue.nextTick(() => {
 | 
			
		||||
			const styles = document.styleSheets;
 | 
			
		||||
			let sheetsIconList = [];
 | 
			
		||||
			for (let i = 0; i < styles.length; i++) {
 | 
			
		||||
				for (let j = 0; j < styles[i].cssRules.length; j++) {
 | 
			
		||||
					if (styles[i].cssRules[j].selectorText && styles[i].cssRules[j].selectorText.indexOf('.el-icon-') === 0) {
 | 
			
		||||
						sheetsIconList.push(
 | 
			
		||||
							`${styles[i].cssRules[j].selectorText.substring(1, styles[i].cssRules[j].selectorText.length).replace(/\\:\\:before/gi, '')}`
 | 
			
		||||
						);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (sheetsIconList.length > 0) resolve(sheetsIconList);
 | 
			
		||||
			else reject('未获取到值,请刷新重试');
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 初始化获取 css 样式,这里使用 fontawesome 的图标
 | 
			
		||||
const getAwesomeIconfont = () => {
 | 
			
		||||
	return new Promise((resolve, reject) => {
 | 
			
		||||
		Vue.nextTick(() => {
 | 
			
		||||
			const styles = document.styleSheets;
 | 
			
		||||
			let sheetsList = [];
 | 
			
		||||
			let sheetsIconList = [];
 | 
			
		||||
			for (let i = 0; i < styles.length; i++) {
 | 
			
		||||
				if (styles[i].href && styles[i].href.indexOf('netdna.bootstrapcdn.com') > -1) {
 | 
			
		||||
					sheetsList.push(styles[i]);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			for (let i = 0; i < sheetsList.length; i++) {
 | 
			
		||||
				for (let j = 0; j < sheetsList[i].cssRules.length; j++) {
 | 
			
		||||
					if (
 | 
			
		||||
						sheetsList[i].cssRules[j].selectorText &&
 | 
			
		||||
						sheetsList[i].cssRules[j].selectorText.indexOf('.fa-') === 0 &&
 | 
			
		||||
						sheetsList[i].cssRules[j].selectorText.indexOf(',') === -1
 | 
			
		||||
					) {
 | 
			
		||||
						sheetsIconList.push(
 | 
			
		||||
							`${sheetsList[i].cssRules[j].selectorText.substring(1, sheetsList[i].cssRules[j].selectorText.length).replace(/\\:\\:before/gi, '')}`
 | 
			
		||||
						);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (sheetsIconList.length > 0) resolve(sheetsIconList);
 | 
			
		||||
			else reject('未获取到值,请刷新重试');
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 定义导出方法集合
 | 
			
		||||
const initIconfont = {
 | 
			
		||||
	// iconfont
 | 
			
		||||
	ali: () => {
 | 
			
		||||
		return getAlicdnIconfont();
 | 
			
		||||
	},
 | 
			
		||||
	// element plus
 | 
			
		||||
	ele: () => {
 | 
			
		||||
		return getElementPlusIconfont();
 | 
			
		||||
	},
 | 
			
		||||
	// fontawesome
 | 
			
		||||
	awe: () => {
 | 
			
		||||
		return getAwesomeIconfont();
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 导出方法
 | 
			
		||||
export default initIconfont;
 | 
			
		||||
							
								
								
									
										46
									
								
								src/utils/loading.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/utils/loading.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import loadingCss from '@/theme/loading.scss';
 | 
			
		||||
 | 
			
		||||
// 定义方法
 | 
			
		||||
export const PrevLoading = {
 | 
			
		||||
	// 载入 css
 | 
			
		||||
	setCss: () => {
 | 
			
		||||
		let link = document.createElement('link');
 | 
			
		||||
		link.rel = 'stylesheet';
 | 
			
		||||
		link.href = loadingCss;
 | 
			
		||||
		link.crossOrigin = 'anonymous';
 | 
			
		||||
		document.getElementsByTagName('head')[0].appendChild(link);
 | 
			
		||||
	},
 | 
			
		||||
	// 创建 loading
 | 
			
		||||
	start: () => {
 | 
			
		||||
		const bodys = document.body;
 | 
			
		||||
		const div = document.createElement('div');
 | 
			
		||||
		div.setAttribute('class', 'loading-prev');
 | 
			
		||||
		const htmls = `
 | 
			
		||||
			<div class="loading-prev-box">
 | 
			
		||||
			<div class="loading-prev-box-warp">
 | 
			
		||||
				<div class="loading-prev-box-item"></div>
 | 
			
		||||
				<div class="loading-prev-box-item"></div>
 | 
			
		||||
				<div class="loading-prev-box-item"></div>
 | 
			
		||||
				<div class="loading-prev-box-item"></div>
 | 
			
		||||
				<div class="loading-prev-box-item"></div>
 | 
			
		||||
				<div class="loading-prev-box-item"></div>
 | 
			
		||||
				<div class="loading-prev-box-item"></div>
 | 
			
		||||
				<div class="loading-prev-box-item"></div>
 | 
			
		||||
				<div class="loading-prev-box-item"></div>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
		`;
 | 
			
		||||
		div.innerHTML = htmls;
 | 
			
		||||
		bodys.insertBefore(div, bodys.childNodes[0]);
 | 
			
		||||
	},
 | 
			
		||||
	// 移除 loading
 | 
			
		||||
	done: () => {
 | 
			
		||||
		Vue.nextTick(() => {
 | 
			
		||||
			setTimeout(() => {
 | 
			
		||||
				const el = document.querySelector('.loading-prev');
 | 
			
		||||
				el && el.parentNode?.removeChild(el);
 | 
			
		||||
			}, 1000);
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										65
									
								
								src/utils/request.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								src/utils/request.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
			
		||||
import store from '@/store';
 | 
			
		||||
import router, { resetRouter } from '@/router/index';
 | 
			
		||||
import axios from 'axios';
 | 
			
		||||
import { Message, MessageBox } from 'element-ui';
 | 
			
		||||
import { Session } from '@/utils/storage';
 | 
			
		||||
 | 
			
		||||
// 创建 axios 实例
 | 
			
		||||
const service = axios.create({
 | 
			
		||||
	baseURL: process.env.VUE_APP_BASE_API,
 | 
			
		||||
	timeout: 50000,
 | 
			
		||||
	headers: { 'Content-Type': 'application/json' },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// 添加请求拦截器
 | 
			
		||||
service.interceptors.request.use(
 | 
			
		||||
	(config) => {
 | 
			
		||||
		// 在发送请求之前做些什么 token
 | 
			
		||||
		if (Session.get('token')) {
 | 
			
		||||
			config.headers.common['Authorization'] = `${Session.get('token')}`;
 | 
			
		||||
		}
 | 
			
		||||
		return config;
 | 
			
		||||
	},
 | 
			
		||||
	(error) => {
 | 
			
		||||
		// 对请求错误做些什么
 | 
			
		||||
		return Promise.reject(error);
 | 
			
		||||
	}
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
// 添加响应拦截器
 | 
			
		||||
service.interceptors.response.use(
 | 
			
		||||
	(response) => {
 | 
			
		||||
		// 对响应数据做点什么
 | 
			
		||||
		const res = response.data;
 | 
			
		||||
		if (res.code && res.code !== 0) {
 | 
			
		||||
			// `token` 过期或者账号已在别处登录
 | 
			
		||||
			if (res.code === 401 || res.code === 4001) {
 | 
			
		||||
				// 清除浏览器全部临时缓存
 | 
			
		||||
				Session.clear();
 | 
			
		||||
				router.push('/login');
 | 
			
		||||
				store.commit('setMenuData', {});
 | 
			
		||||
				resetRouter(); // 重置路由
 | 
			
		||||
				MessageBox.alert('你已被登出,请重新登录', '提示', {})
 | 
			
		||||
					.then(() => {})
 | 
			
		||||
					.catch(() => {});
 | 
			
		||||
			}
 | 
			
		||||
			return Promise.reject(service.interceptors.response.error);
 | 
			
		||||
		} else {
 | 
			
		||||
			return response.data;
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	(error) => {
 | 
			
		||||
		// 对响应错误做点什么
 | 
			
		||||
		if (error.message.indexOf('timeout') != -1) {
 | 
			
		||||
			Message.error('网络超时');
 | 
			
		||||
		} else if (error.message == 'Network Error') {
 | 
			
		||||
			Message.error('网络连接错误');
 | 
			
		||||
		} else {
 | 
			
		||||
			Message.error(error.response.data.message);
 | 
			
		||||
		}
 | 
			
		||||
		return Promise.reject(error);
 | 
			
		||||
	}
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
// 导出 axios 实例
 | 
			
		||||
export default service;
 | 
			
		||||
							
								
								
									
										39
									
								
								src/utils/setIconfont.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/utils/setIconfont.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
// 字体图标 url
 | 
			
		||||
const cssCdnUrlList = ['//at.alicdn.com/t/font_2348547_zjuiclx86c.css', '//netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css'];
 | 
			
		||||
// 第三方 js url
 | 
			
		||||
const jsCdnUrlList = [];
 | 
			
		||||
 | 
			
		||||
// 动态设置字体图标
 | 
			
		||||
export function setCssCdn() {
 | 
			
		||||
	if (cssCdnUrlList.length <= 0) return false;
 | 
			
		||||
	cssCdnUrlList.map((v) => {
 | 
			
		||||
		let link = document.createElement('link');
 | 
			
		||||
		link.rel = 'stylesheet';
 | 
			
		||||
		link.href = v;
 | 
			
		||||
		link.crossOrigin = 'anonymous';
 | 
			
		||||
		document.getElementsByTagName('head')[0].appendChild(link);
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 批量设置第三方js
 | 
			
		||||
export function setJsCdn() {
 | 
			
		||||
	if (jsCdnUrlList.length <= 0) return false;
 | 
			
		||||
	jsCdnUrlList.map((v) => {
 | 
			
		||||
		let link = document.createElement('script');
 | 
			
		||||
		link.src = v;
 | 
			
		||||
		document.body.appendChild(link);
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 设置执行函数
 | 
			
		||||
const setIntroduction = {
 | 
			
		||||
	cssCdn: () => {
 | 
			
		||||
		setCssCdn();
 | 
			
		||||
	},
 | 
			
		||||
	jsCdn: () => {
 | 
			
		||||
		setJsCdn();
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 导出函数方法
 | 
			
		||||
export default setIntroduction;
 | 
			
		||||
							
								
								
									
										41
									
								
								src/utils/storage.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/utils/storage.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
// 1、window.localStorage 浏览器永久缓存
 | 
			
		||||
export const Local = {
 | 
			
		||||
	// 设置永久缓存
 | 
			
		||||
	set(key, val) {
 | 
			
		||||
		window.localStorage.setItem(key, JSON.stringify(val));
 | 
			
		||||
	},
 | 
			
		||||
	// 获取永久缓存
 | 
			
		||||
	get(key) {
 | 
			
		||||
		let json = window.localStorage.getItem(key);
 | 
			
		||||
		return JSON.parse(json);
 | 
			
		||||
	},
 | 
			
		||||
	// 移除永久缓存
 | 
			
		||||
	remove(key) {
 | 
			
		||||
		window.localStorage.removeItem(key);
 | 
			
		||||
	},
 | 
			
		||||
	// 移除全部永久缓存
 | 
			
		||||
	clear() {
 | 
			
		||||
		window.localStorage.clear();
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 2、window.sessionStorage 浏览器临时缓存
 | 
			
		||||
export const Session = {
 | 
			
		||||
	// 设置临时缓存
 | 
			
		||||
	set(key, val) {
 | 
			
		||||
		window.sessionStorage.setItem(key, JSON.stringify(val));
 | 
			
		||||
	},
 | 
			
		||||
	// 获取临时缓存
 | 
			
		||||
	get(key) {
 | 
			
		||||
		let json = window.sessionStorage.getItem(key);
 | 
			
		||||
		return JSON.parse(json);
 | 
			
		||||
	},
 | 
			
		||||
	// 移除临时缓存
 | 
			
		||||
	remove(key) {
 | 
			
		||||
		window.sessionStorage.removeItem(key);
 | 
			
		||||
	},
 | 
			
		||||
	// 移除全部临时缓存
 | 
			
		||||
	clear() {
 | 
			
		||||
		window.sessionStorage.clear();
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										63
									
								
								src/utils/theme.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/utils/theme.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
import { Message } from 'element-ui';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 颜色转换函数
 | 
			
		||||
 * @method hexToRgb hex 颜色转 rgb 颜色
 | 
			
		||||
 * @method rgbToHex rgb 颜色转 Hex 颜色
 | 
			
		||||
 * @method getDarkColor 加深颜色值
 | 
			
		||||
 * @method getLightColor 变浅颜色值
 | 
			
		||||
 */
 | 
			
		||||
export function useChangeColor() {
 | 
			
		||||
	// str 颜色值字符串
 | 
			
		||||
	const hexToRgb = (str) => {
 | 
			
		||||
		let hexs = '';
 | 
			
		||||
		let reg = /^#?[0-9A-Fa-f]{6}$/;
 | 
			
		||||
		if (!reg.test(str)) {
 | 
			
		||||
			Message.warning('输入错误的hex');
 | 
			
		||||
			return '';
 | 
			
		||||
		}
 | 
			
		||||
		str = str.replace('#', '');
 | 
			
		||||
		hexs = str.match(/../g);
 | 
			
		||||
		for (let i = 0; i < 3; i++) hexs[i] = parseInt(hexs[i], 16);
 | 
			
		||||
		return hexs;
 | 
			
		||||
	};
 | 
			
		||||
	// r 代表红色 | g 代表绿色 | b 代表蓝色
 | 
			
		||||
	const rgbToHex = (r, g, b) => {
 | 
			
		||||
		let reg = /^\d{1,3}$/;
 | 
			
		||||
		if (!reg.test(r) || !reg.test(g) || !reg.test(b)) {
 | 
			
		||||
			Message.warning('输入错误的rgb颜色值');
 | 
			
		||||
			return '';
 | 
			
		||||
		}
 | 
			
		||||
		let hexs = [r.toString(16), g.toString(16), b.toString(16)];
 | 
			
		||||
		for (let i = 0; i < 3; i++) if (hexs[i].length == 1) hexs[i] = `0${hexs[i]}`;
 | 
			
		||||
		return `#${hexs.join('')}`;
 | 
			
		||||
	};
 | 
			
		||||
	// color 颜色值字符串 | level 变浅的程度,限0-1之间
 | 
			
		||||
	const getDarkColor = (color, level) => {
 | 
			
		||||
		let reg = /^#?[0-9A-Fa-f]{6}$/;
 | 
			
		||||
		if (!reg.test(color)) {
 | 
			
		||||
			Message.warning('输入错误的hex颜色值');
 | 
			
		||||
			return '';
 | 
			
		||||
		}
 | 
			
		||||
		let rgb = useChangeColor().hexToRgb(color);
 | 
			
		||||
		for (let i = 0; i < 3; i++) rgb[i] = Math.floor(rgb[i] * (1 - level));
 | 
			
		||||
		return useChangeColor().rgbToHex(rgb[0], rgb[1], rgb[2]);
 | 
			
		||||
	};
 | 
			
		||||
	// color 颜色值字符串 | level 加深的程度,限0-1之间
 | 
			
		||||
	const getLightColor = (color, level) => {
 | 
			
		||||
		let reg = /^#?[0-9A-Fa-f]{6}$/;
 | 
			
		||||
		if (!reg.test(color)) {
 | 
			
		||||
			Message.warning('输入错误的hex颜色值');
 | 
			
		||||
			return '';
 | 
			
		||||
		}
 | 
			
		||||
		let rgb = useChangeColor().hexToRgb(color);
 | 
			
		||||
		for (let i = 0; i < 3; i++) rgb[i] = Math.floor((255 - rgb[i]) * level + rgb[i]);
 | 
			
		||||
		return useChangeColor().rgbToHex(rgb[0], rgb[1], rgb[2]);
 | 
			
		||||
	};
 | 
			
		||||
	return {
 | 
			
		||||
		hexToRgb,
 | 
			
		||||
		rgbToHex,
 | 
			
		||||
		getDarkColor,
 | 
			
		||||
		getLightColor,
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										283
									
								
								src/utils/toolsValidate.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								src/utils/toolsValidate.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,283 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 2020.11.29 lyt 整理
 | 
			
		||||
 * 工具类集合,适用于平时开发
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 验证百分比(不可以小数)
 | 
			
		||||
 * @param val 当前值字符串
 | 
			
		||||
 * @returns 返回处理后的字符串
 | 
			
		||||
 */
 | 
			
		||||
export function verifyNumberPercentage(val) {
 | 
			
		||||
	// 匹配空格
 | 
			
		||||
	let v = val.replace(/(^\s*)|(\s*$)/g, '');
 | 
			
		||||
	// 只能是数字和小数点,不能是其他输入
 | 
			
		||||
	v = v.replace(/[^\d]/g, '');
 | 
			
		||||
	// 不能以0开始
 | 
			
		||||
	v = v.replace(/^0/g, '');
 | 
			
		||||
	// 数字超过100,赋值成最大值100
 | 
			
		||||
	v = v.replace(/^[1-9]\d\d{1,3}$/, '100');
 | 
			
		||||
	// 返回结果
 | 
			
		||||
	return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 验证百分比(可以小数)
 | 
			
		||||
 * @param val 当前值字符串
 | 
			
		||||
 * @returns 返回处理后的字符串
 | 
			
		||||
 */
 | 
			
		||||
export function verifyNumberPercentageFloat(val) {
 | 
			
		||||
	let v = verifyNumberIntegerAndFloat(val);
 | 
			
		||||
	// 数字超过100,赋值成最大值100
 | 
			
		||||
	v = v.replace(/^[1-9]\d\d{1,3}$/, '100');
 | 
			
		||||
	// 超过100之后不给再输入值
 | 
			
		||||
	v = v.replace(/^100\.$/, '100');
 | 
			
		||||
	// 返回结果
 | 
			
		||||
	return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 小数或整数(不可以负数)
 | 
			
		||||
export function verifyNumberIntegerAndFloat(val) {
 | 
			
		||||
	// 匹配空格
 | 
			
		||||
	let v = val.replace(/(^\s*)|(\s*$)/g, '');
 | 
			
		||||
	// 只能是数字和小数点,不能是其他输入
 | 
			
		||||
	v = v.replace(/[^\d.]/g, '');
 | 
			
		||||
	// 以0开始只能输入一个
 | 
			
		||||
	v = v.replace(/^0{2}$/g, '0');
 | 
			
		||||
	// 保证第一位只能是数字,不能是点
 | 
			
		||||
	v = v.replace(/^\./g, '');
 | 
			
		||||
	// 小数只能出现1位
 | 
			
		||||
	v = v.replace('.', '$#$').replace(/\./g, '').replace('$#$', '.');
 | 
			
		||||
	// 小数点后面保留2位
 | 
			
		||||
	v = v.replace(/^(\\-)*(\d+)\.(\d\d).*$/, '$1$2.$3');
 | 
			
		||||
	// 返回结果
 | 
			
		||||
	return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 正整数验证
 | 
			
		||||
export function verifiyNumberInteger(val) {
 | 
			
		||||
	// 匹配空格
 | 
			
		||||
	let v = val.replace(/(^\s*)|(\s*$)/g, '');
 | 
			
		||||
	// 去掉 '.' , 防止贴贴的时候出现问题 如 0.1.12.12
 | 
			
		||||
	v = v.replace(/[\\.]*/g, '');
 | 
			
		||||
	// 去掉以 0 开始后面的数, 防止贴贴的时候出现问题 如 00121323
 | 
			
		||||
	v = v.replace(/(^0[\d]*)$/g, '0');
 | 
			
		||||
	// 首位是0,只能出现一次
 | 
			
		||||
	v = v.replace(/^0\d$/g, '0');
 | 
			
		||||
	// 只匹配数字
 | 
			
		||||
	v = v.replace(/[^\d]/g, '');
 | 
			
		||||
	// 返回结果
 | 
			
		||||
	return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 去掉中文及空格
 | 
			
		||||
export function verifyCnAndSpace(val) {
 | 
			
		||||
	// 匹配中文与空格
 | 
			
		||||
	let v = val.replace(/[\u4e00-\u9fa5\s]+/g, '');
 | 
			
		||||
	// 匹配空格
 | 
			
		||||
	v = v.replace(/(^\s*)|(\s*$)/g, '');
 | 
			
		||||
	// 返回结果
 | 
			
		||||
	return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 去掉英文及空格
 | 
			
		||||
export function verifyEnAndSpace(val) {
 | 
			
		||||
	// 匹配英文与空格
 | 
			
		||||
	let v = val.replace(/[a-zA-Z]+/g, '');
 | 
			
		||||
	// 匹配空格
 | 
			
		||||
	v = v.replace(/(^\s*)|(\s*$)/g, '');
 | 
			
		||||
	// 返回结果
 | 
			
		||||
	return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 禁止输入空格
 | 
			
		||||
export function verifyAndSpace(val) {
 | 
			
		||||
	// 匹配空格
 | 
			
		||||
	let v = val.replace(/(^\s*)|(\s*$)/g, '');
 | 
			
		||||
	// 返回结果
 | 
			
		||||
	return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 金额用 `,` 区分开
 | 
			
		||||
export function verifyNumberComma(val) {
 | 
			
		||||
	// 调用小数或整数(不可以负数)方法
 | 
			
		||||
	let v = verifyNumberIntegerAndFloat(val);
 | 
			
		||||
	// 字符串转成数组
 | 
			
		||||
	v = v.toString().split('.');
 | 
			
		||||
	// \B 匹配非单词边界,两边都是单词字符或者两边都是非单词字符
 | 
			
		||||
	v[0] = v[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
 | 
			
		||||
	// 数组转字符串
 | 
			
		||||
	v = v.join('.');
 | 
			
		||||
	// 返回结果
 | 
			
		||||
	return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 匹配文字变色(搜索时)
 | 
			
		||||
export function verifyTextColor(val, text = '', color = 'red') {
 | 
			
		||||
	// 返回内容,添加颜色
 | 
			
		||||
	let v = text.replace(new RegExp(val, 'gi'), `<span style='color: ${color}'>${val}</span>`);
 | 
			
		||||
	// 返回结果
 | 
			
		||||
	return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 数字转中文大写
 | 
			
		||||
export function verifyNumberCnUppercase(val, unit = '仟佰拾亿仟佰拾万仟佰拾元角分', v = '') {
 | 
			
		||||
	// 当前内容字符串添加 2个0,为什么??
 | 
			
		||||
	val += '00';
 | 
			
		||||
	// 返回某个指定的字符串值在字符串中首次出现的位置,没有出现,则该方法返回 -1
 | 
			
		||||
	let lookup = val.indexOf('.');
 | 
			
		||||
	// substring:不包含结束下标内容,substr:包含结束下标内容
 | 
			
		||||
	if (lookup >= 0) val = val.substring(0, lookup) + val.substr(lookup + 1, 2);
 | 
			
		||||
	// 根据内容 val 的长度,截取返回对应大写
 | 
			
		||||
	unit = unit.substr(unit.length - val.length);
 | 
			
		||||
	// 循环截取拼接大写
 | 
			
		||||
	for (let i = 0; i < val.length; i++) {
 | 
			
		||||
		v += '零壹贰叁肆伍陆柒捌玖'.substr(val.substr(i, 1), 1) + unit.substr(i, 1);
 | 
			
		||||
	}
 | 
			
		||||
	// 正则处理
 | 
			
		||||
	v = v
 | 
			
		||||
		.replace(/零角零分$/, '整')
 | 
			
		||||
		.replace(/零[仟佰拾]/g, '零')
 | 
			
		||||
		.replace(/零{2,}/g, '零')
 | 
			
		||||
		.replace(/零([亿|万])/g, '$1')
 | 
			
		||||
		.replace(/零+元/, '元')
 | 
			
		||||
		.replace(/亿零{0,3}万/, '亿')
 | 
			
		||||
		.replace(/^元/, '零元');
 | 
			
		||||
	// 返回结果
 | 
			
		||||
	return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 手机号码
 | 
			
		||||
export function verifyPhone(val) {
 | 
			
		||||
	// false: 手机号码不正确
 | 
			
		||||
	if (!/^((12[0-9])|(13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\d{8}$/.test(val)) return false;
 | 
			
		||||
	// true: 手机号码正确
 | 
			
		||||
	else return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 国内电话号码
 | 
			
		||||
export function verifyTelPhone(val) {
 | 
			
		||||
	// false: 国内电话号码不正确
 | 
			
		||||
	if (!/\d{3}-\d{8}|\d{4}-\d{7}/.test(val)) return false;
 | 
			
		||||
	// true: 国内电话号码正确
 | 
			
		||||
	else return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 登录账号 (字母开头,允许5-16字节,允许字母数字下划线)
 | 
			
		||||
export function verifyAccount(val) {
 | 
			
		||||
	// false: 登录账号不正确
 | 
			
		||||
	if (!/^[a-zA-Z][a-zA-Z0-9_]{4,15}$/.test(val)) return false;
 | 
			
		||||
	// true: 登录账号正确
 | 
			
		||||
	else return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 密码 (以字母开头,长度在6~16之间,只能包含字母、数字和下划线)
 | 
			
		||||
export function verifyPassword(val) {
 | 
			
		||||
	// false: 密码不正确
 | 
			
		||||
	if (!/^[a-zA-Z]\w{5,15}$/.test(val)) return false;
 | 
			
		||||
	// true: 密码正确
 | 
			
		||||
	else return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 强密码 (字母+数字+特殊字符,长度在6-16之间)
 | 
			
		||||
export function verifyPasswordPowerful(val) {
 | 
			
		||||
	// false: 强密码不正确
 | 
			
		||||
	if (
 | 
			
		||||
		!/^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&\\.*]+$)(?![a-zA-z\d]+$)(?![a-zA-z!@#$%^&\\.*]+$)(?![\d!@#$%^&\\.*]+$)[a-zA-Z\d!@#$%^&\\.*]{6,16}$/.test(val)
 | 
			
		||||
	)
 | 
			
		||||
		return false;
 | 
			
		||||
	// true: 强密码正确
 | 
			
		||||
	else return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 密码强度
 | 
			
		||||
export function verifyPasswordStrength(val) {
 | 
			
		||||
	let v = '';
 | 
			
		||||
	// 弱:纯数字,纯字母,纯特殊字符
 | 
			
		||||
	if (/^(?:\d+|[a-zA-Z]+|[!@#$%^&\\.*]+){6,16}$/.test(val)) v = '弱';
 | 
			
		||||
	// 中:字母+数字,字母+特殊字符,数字+特殊字符
 | 
			
		||||
	if (/^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&\\.*]+$)[a-zA-Z\d!@#$%^&\\.*]{6,16}$/.test(val)) v = '中';
 | 
			
		||||
	// 强:字母+数字+特殊字符
 | 
			
		||||
	if (
 | 
			
		||||
		/^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&\\.*]+$)(?![a-zA-z\d]+$)(?![a-zA-z!@#$%^&\\.*]+$)(?![\d!@#$%^&\\.*]+$)[a-zA-Z\d!@#$%^&\\.*]{6,16}$/.test(val)
 | 
			
		||||
	)
 | 
			
		||||
		v = '强';
 | 
			
		||||
	// 返回结果
 | 
			
		||||
	return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IP地址
 | 
			
		||||
export function verifyIPAddress(val) {
 | 
			
		||||
	// false: IP地址不正确
 | 
			
		||||
	if (
 | 
			
		||||
		!/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/.test(
 | 
			
		||||
			val
 | 
			
		||||
		)
 | 
			
		||||
	)
 | 
			
		||||
		return false;
 | 
			
		||||
	// true: IP地址正确
 | 
			
		||||
	else return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 邮箱
 | 
			
		||||
export function verifyEmail(val) {
 | 
			
		||||
	// false: 邮箱不正确
 | 
			
		||||
	if (
 | 
			
		||||
		!/^(([^<>()\\[\]\\.,;:\s@"]+(\.[^<>()\\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
 | 
			
		||||
			val
 | 
			
		||||
		)
 | 
			
		||||
	)
 | 
			
		||||
		return false;
 | 
			
		||||
	// true: 邮箱正确
 | 
			
		||||
	else return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 身份证
 | 
			
		||||
export function verifyIdCard(val) {
 | 
			
		||||
	// false: 身份证不正确
 | 
			
		||||
	if (!/^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/.test(val)) return false;
 | 
			
		||||
	// true: 身份证正确
 | 
			
		||||
	else return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 姓名
 | 
			
		||||
export function verifyFullName(val) {
 | 
			
		||||
	// false: 姓名不正确
 | 
			
		||||
	if (!/^[\u4e00-\u9fa5]{1,6}(·[\u4e00-\u9fa5]{1,6}){0,2}$/.test(val)) return false;
 | 
			
		||||
	// true: 姓名正确
 | 
			
		||||
	else return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 邮政编码
 | 
			
		||||
export function verifyPostalCode(val) {
 | 
			
		||||
	// false: 邮政编码不正确
 | 
			
		||||
	if (!/^[1-9][0-9]{5}$/.test(val)) return false;
 | 
			
		||||
	// true: 邮政编码正确
 | 
			
		||||
	else return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// url
 | 
			
		||||
export function verifyUrl(val) {
 | 
			
		||||
	// false: url不正确
 | 
			
		||||
	if (
 | 
			
		||||
		!/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(
 | 
			
		||||
			val
 | 
			
		||||
		)
 | 
			
		||||
	)
 | 
			
		||||
		return false;
 | 
			
		||||
	// true: url正确
 | 
			
		||||
	else return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 车牌号
 | 
			
		||||
export function verifyCarNum(val) {
 | 
			
		||||
	// false: 车牌号不正确
 | 
			
		||||
	if (
 | 
			
		||||
		!/^(([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z](([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳使领]))$/.test(
 | 
			
		||||
			val
 | 
			
		||||
		)
 | 
			
		||||
	)
 | 
			
		||||
		return false;
 | 
			
		||||
	// true:车牌号正确
 | 
			
		||||
	else return true;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										95
									
								
								src/views/error/401.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								src/views/error/401.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="error">
 | 
			
		||||
		<div class="error-flex">
 | 
			
		||||
			<div class="left">
 | 
			
		||||
				<div class="left-item">
 | 
			
		||||
					<div class="left-item-animation left-item-num">401</div>
 | 
			
		||||
					<div class="left-item-animation left-item-title">{{ $t('message.noAccess.accessTitle') }}</div>
 | 
			
		||||
					<div class="left-item-animation left-item-msg">{{ $t('message.noAccess.accessMsg') }}</div>
 | 
			
		||||
					<div class="left-item-animation left-item-btn">
 | 
			
		||||
						<el-button type="primary" round @click="onSetAuth">{{ $t('message.noAccess.accessBtn') }}</el-button>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="right">
 | 
			
		||||
				<img
 | 
			
		||||
					src="https://img-blog.csdnimg.cn/3333f265772a4fa89287993500ecbf96.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbHl0LXRvcA==,size_16,color_FFFFFF,t_70,g_se,x_16"
 | 
			
		||||
				/>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { Session } from '@/utils/storage';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'noAuth',
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 重新授权
 | 
			
		||||
		onSetAuth() {
 | 
			
		||||
			// 清除缓存/token等
 | 
			
		||||
			Session.clear();
 | 
			
		||||
			// 使用 reload 时,不需要调用 resetRoute() 重置路由
 | 
			
		||||
			window.location.reload();
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.error {
 | 
			
		||||
	height: 100%;
 | 
			
		||||
	background-color: white;
 | 
			
		||||
	display: flex;
 | 
			
		||||
	.error-flex {
 | 
			
		||||
		margin: auto;
 | 
			
		||||
		display: flex;
 | 
			
		||||
		height: 350px;
 | 
			
		||||
		width: 900px;
 | 
			
		||||
		.left {
 | 
			
		||||
			flex: 1;
 | 
			
		||||
			height: 100%;
 | 
			
		||||
			align-items: center;
 | 
			
		||||
			display: flex;
 | 
			
		||||
			.left-item {
 | 
			
		||||
				.left-item-animation {
 | 
			
		||||
					opacity: 0;
 | 
			
		||||
					animation-name: error-num;
 | 
			
		||||
					animation-duration: 0.5s;
 | 
			
		||||
					animation-fill-mode: forwards;
 | 
			
		||||
				}
 | 
			
		||||
				.left-item-num {
 | 
			
		||||
					color: #d6e0f6;
 | 
			
		||||
					font-size: 55px;
 | 
			
		||||
				}
 | 
			
		||||
				.left-item-title {
 | 
			
		||||
					font-size: 20px;
 | 
			
		||||
					color: #333333;
 | 
			
		||||
					margin: 15px 0 5px 0;
 | 
			
		||||
					animation-delay: 0.1s;
 | 
			
		||||
				}
 | 
			
		||||
				.left-item-msg {
 | 
			
		||||
					color: #c0bebe;
 | 
			
		||||
					font-size: 12px;
 | 
			
		||||
					margin-bottom: 30px;
 | 
			
		||||
					animation-delay: 0.2s;
 | 
			
		||||
				}
 | 
			
		||||
				.left-item-btn {
 | 
			
		||||
					animation-delay: 0.2s;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		.right {
 | 
			
		||||
			flex: 1;
 | 
			
		||||
			opacity: 0;
 | 
			
		||||
			animation-name: error-img;
 | 
			
		||||
			animation-duration: 2s;
 | 
			
		||||
			animation-fill-mode: forwards;
 | 
			
		||||
			img {
 | 
			
		||||
				width: 100%;
 | 
			
		||||
				height: 100%;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										91
									
								
								src/views/error/404.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								src/views/error/404.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,91 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="error">
 | 
			
		||||
		<div class="error-flex">
 | 
			
		||||
			<div class="left">
 | 
			
		||||
				<div class="left-item">
 | 
			
		||||
					<div class="left-item-animation left-item-num">404</div>
 | 
			
		||||
					<div class="left-item-animation left-item-title">{{ $t('message.notFound.foundTitle') }}</div>
 | 
			
		||||
					<div class="left-item-animation left-item-msg">{{ $t('message.notFound.foundMsg') }}</div>
 | 
			
		||||
					<div class="left-item-animation left-item-btn">
 | 
			
		||||
						<el-button type="primary" round @click="onGoHome">{{ $t('message.notFound.foundBtn') }}</el-button>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="right">
 | 
			
		||||
				<img
 | 
			
		||||
					src="https://img-blog.csdnimg.cn/9eb1d85a417f4ed1ba7107f149ce3da1.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbHl0LXRvcA==,size_16,color_FFFFFF,t_70,g_se,x_16"
 | 
			
		||||
				/>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'noFound',
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 去首页
 | 
			
		||||
		onGoHome() {
 | 
			
		||||
			this.$router.push('/');
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.error {
 | 
			
		||||
	height: 100%;
 | 
			
		||||
	background-color: white;
 | 
			
		||||
	display: flex;
 | 
			
		||||
	.error-flex {
 | 
			
		||||
		margin: auto;
 | 
			
		||||
		display: flex;
 | 
			
		||||
		height: 350px;
 | 
			
		||||
		width: 900px;
 | 
			
		||||
		.left {
 | 
			
		||||
			flex: 1;
 | 
			
		||||
			height: 100%;
 | 
			
		||||
			align-items: center;
 | 
			
		||||
			display: flex;
 | 
			
		||||
			.left-item {
 | 
			
		||||
				.left-item-animation {
 | 
			
		||||
					opacity: 0;
 | 
			
		||||
					animation-name: error-num;
 | 
			
		||||
					animation-duration: 0.5s;
 | 
			
		||||
					animation-fill-mode: forwards;
 | 
			
		||||
				}
 | 
			
		||||
				.left-item-num {
 | 
			
		||||
					color: #d6e0f6;
 | 
			
		||||
					font-size: 55px;
 | 
			
		||||
				}
 | 
			
		||||
				.left-item-title {
 | 
			
		||||
					font-size: 20px;
 | 
			
		||||
					color: #333333;
 | 
			
		||||
					margin: 15px 0 5px 0;
 | 
			
		||||
					animation-delay: 0.1s;
 | 
			
		||||
				}
 | 
			
		||||
				.left-item-msg {
 | 
			
		||||
					color: #c0bebe;
 | 
			
		||||
					font-size: 12px;
 | 
			
		||||
					margin-bottom: 30px;
 | 
			
		||||
					animation-delay: 0.2s;
 | 
			
		||||
				}
 | 
			
		||||
				.left-item-btn {
 | 
			
		||||
					animation-delay: 0.2s;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		.right {
 | 
			
		||||
			flex: 1;
 | 
			
		||||
			opacity: 0;
 | 
			
		||||
			animation-name: error-img;
 | 
			
		||||
			animation-duration: 2s;
 | 
			
		||||
			animation-fill-mode: forwards;
 | 
			
		||||
			img {
 | 
			
		||||
				width: 100%;
 | 
			
		||||
				height: 100%;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										89
									
								
								src/views/fun/signCanvas/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								src/views/fun/signCanvas/index.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div>
 | 
			
		||||
		<el-card shadow="hover" header="在线签名演示">
 | 
			
		||||
			<el-alert
 | 
			
		||||
				title="感谢优秀的 `sign-canvas`,项目地址:https://github.com/langyuxiansheng/vue-sign-canvas"
 | 
			
		||||
				type="success"
 | 
			
		||||
				:closable="false"
 | 
			
		||||
				class="mb15"
 | 
			
		||||
			></el-alert>
 | 
			
		||||
			<el-button type="primary" size="small" icon="el-icon-edit" @click="onSignCanvasClick">点击进行签名</el-button>
 | 
			
		||||
		</el-card>
 | 
			
		||||
		<el-dialog title="在线签名" :visible.sync="signVisible" :close-on-click-modal="true" :close-on-press-escape="true" :width="signDialogWidth">
 | 
			
		||||
			<sign-canvas class="sign-canvas" ref="SignCanvas" :options="signOptions" v-model="signValue" />
 | 
			
		||||
			<div slot="footer" class="dialog-footer">
 | 
			
		||||
				<el-button size="small" @click="onCancelSign">取消</el-button>
 | 
			
		||||
				<el-button type="danger" size="small" @click="onCanvasClear">清空</el-button>
 | 
			
		||||
				<el-button type="primary" size="small" @click="onSaveAsImg">保存</el-button>
 | 
			
		||||
			</div>
 | 
			
		||||
		</el-dialog>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import SignCanvas from 'sign-canvas';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'funSignCanvas',
 | 
			
		||||
	components: {
 | 
			
		||||
		SignCanvas,
 | 
			
		||||
	},
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			signVisible: false,
 | 
			
		||||
			signDialogWidth: '',
 | 
			
		||||
			signValue: '',
 | 
			
		||||
			signOptions: {
 | 
			
		||||
				lastWriteSpeed: 1,
 | 
			
		||||
				lastWriteWidth: 2,
 | 
			
		||||
				lineCap: 'round',
 | 
			
		||||
				lineJoin: 'round',
 | 
			
		||||
				canvasWidth: 729,
 | 
			
		||||
				canvasHeight: 460,
 | 
			
		||||
				isShowBorder: false,
 | 
			
		||||
				bgColor: '#E6E6E6',
 | 
			
		||||
				borderWidth: 1,
 | 
			
		||||
				borderColor: '#ff787f',
 | 
			
		||||
				writeWidth: 5,
 | 
			
		||||
				maxWriteWidth: 30,
 | 
			
		||||
				minWriteWidth: 5,
 | 
			
		||||
				writeColor: '#101010',
 | 
			
		||||
				isSign: true,
 | 
			
		||||
				imgType: 'png',
 | 
			
		||||
			},
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.initSignConfig();
 | 
			
		||||
		window.addEventListener('resize', this.initSignConfig);
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 初始化配置信息
 | 
			
		||||
		initSignConfig() {
 | 
			
		||||
			this.signDialogWidth = `${document.body.offsetWidth / 2 + 40}px`;
 | 
			
		||||
			this.signOptions.canvasWidth = document.body.offsetWidth / 2;
 | 
			
		||||
			this.signOptions.canvasHeight = document.body.offsetHeight / 2;
 | 
			
		||||
		},
 | 
			
		||||
		// 打开签名弹窗
 | 
			
		||||
		onSignCanvasClick() {
 | 
			
		||||
			this.signVisible = true;
 | 
			
		||||
		},
 | 
			
		||||
		// 取消签名
 | 
			
		||||
		onCancelSign() {
 | 
			
		||||
			this.signVisible = false;
 | 
			
		||||
			this.onCanvasClear();
 | 
			
		||||
		},
 | 
			
		||||
		// 清空签名
 | 
			
		||||
		onCanvasClear() {
 | 
			
		||||
			this.$refs.SignCanvas.canvasClear();
 | 
			
		||||
		},
 | 
			
		||||
		// 保存签名
 | 
			
		||||
		onSaveAsImg() {
 | 
			
		||||
			const img = this.$refs.SignCanvas.saveAsImg();
 | 
			
		||||
			console.log(img);
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	destroyed() {
 | 
			
		||||
		window.removeEventListener('resize', this.initSignConfig);
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										121
									
								
								src/views/fun/tagsView/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								src/views/fun/tagsView/index.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,121 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div>
 | 
			
		||||
		<el-card shadow="hover" header="tagsView 非当前页演示">
 | 
			
		||||
			<el-form :model="formInline" size="small" label-width="40px" class="tags-view-form">
 | 
			
		||||
				<el-row :gutter="35">
 | 
			
		||||
					<el-col :xs="24" :sm="8" :md="8" :lg="6" :xl="4" class="tags-view-form-col">
 | 
			
		||||
						<el-form-item label="功能">
 | 
			
		||||
							<el-select v-model="formInline.selectId" placeholder="请选择" class="w100">
 | 
			
		||||
								<el-option v-for="item in selectOptions" :key="item.value" :label="item.label" :value="item.value"> </el-option>
 | 
			
		||||
							</el-select>
 | 
			
		||||
						</el-form-item>
 | 
			
		||||
					</el-col>
 | 
			
		||||
					<el-col :xs="24" :sm="8" :md="8" :lg="6" :xl="4" class="tags-view-form-col">
 | 
			
		||||
						<el-form-item label="路径">
 | 
			
		||||
							<el-input v-model="formInline.path" placeholder="路径如:/fun/tagsView"></el-input>
 | 
			
		||||
						</el-form-item>
 | 
			
		||||
					</el-col>
 | 
			
		||||
					<el-col :xs="24" :sm="8" :md="8" :lg="6" :xl="4">
 | 
			
		||||
						<el-form-item>
 | 
			
		||||
							<el-button type="primary" @click="onImplementClick" icon="el-icon-thumb">点击执行</el-button>
 | 
			
		||||
						</el-form-item>
 | 
			
		||||
					</el-col>
 | 
			
		||||
				</el-row>
 | 
			
		||||
			</el-form>
 | 
			
		||||
		</el-card>
 | 
			
		||||
		<el-card shadow="hover" header="tagsView 当前页演示" class="mt15">
 | 
			
		||||
			<div class="flex-warp">
 | 
			
		||||
				<div class="flex-warp-item">
 | 
			
		||||
					<div class="flex-warp-item-box">
 | 
			
		||||
						<el-button type="primary" size="small" icon="el-icon-refresh-right" @click="refreshCurrentTagsView">刷新当前页 </el-button>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="flex-warp-item">
 | 
			
		||||
					<div class="flex-warp-item-box">
 | 
			
		||||
						<el-button type="info" size="small" icon="el-icon-close" @click="closeCurrentTagsView">关闭当前页</el-button>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="flex-warp-item">
 | 
			
		||||
					<div class="flex-warp-item-box">
 | 
			
		||||
						<el-button type="warning" size="small" icon="el-icon-circle-close" @click="closeOtherTagsView">关闭其它 </el-button>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="flex-warp-item">
 | 
			
		||||
					<div class="flex-warp-item-box">
 | 
			
		||||
						<el-button type="danger" size="small" icon="el-icon-folder-delete" @click="closeAllTagsView">全部关闭 </el-button>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
		</el-card>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'funTagsView',
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			formInline: {
 | 
			
		||||
				path: '',
 | 
			
		||||
				selectId: 0,
 | 
			
		||||
			},
 | 
			
		||||
			selectOptions: [
 | 
			
		||||
				{
 | 
			
		||||
					value: 0,
 | 
			
		||||
					label: '刷新当前',
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					value: 1,
 | 
			
		||||
					label: '关闭当前',
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					value: 2,
 | 
			
		||||
					label: '关闭其它',
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					value: 3,
 | 
			
		||||
					label: '关闭全部',
 | 
			
		||||
				},
 | 
			
		||||
			],
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 0 刷新当前,1 关闭当前,2 关闭其它,3 关闭全部
 | 
			
		||||
		// 1、刷新当前 tagsView
 | 
			
		||||
		refreshCurrentTagsView() {
 | 
			
		||||
			this.bus.$emit('onCurrentContextmenuClick', {
 | 
			
		||||
				id: 0,
 | 
			
		||||
				path: this.$route.path,
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		// 2、关闭当前 tagsView
 | 
			
		||||
		closeCurrentTagsView() {
 | 
			
		||||
			this.bus.$emit('onCurrentContextmenuClick', {
 | 
			
		||||
				id: 1,
 | 
			
		||||
				path: this.$route.path,
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		// 3、关闭其它 tagsView
 | 
			
		||||
		closeOtherTagsView() {
 | 
			
		||||
			this.bus.$emit('onCurrentContextmenuClick', {
 | 
			
		||||
				id: 2,
 | 
			
		||||
				path: this.$route.path,
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		// 4、关闭全部 tagsView
 | 
			
		||||
		closeAllTagsView() {
 | 
			
		||||
			this.bus.$emit('onCurrentContextmenuClick', {
 | 
			
		||||
				id: 3,
 | 
			
		||||
				path: this.$route.path,
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		// 执行点击
 | 
			
		||||
		onImplementClick() {
 | 
			
		||||
			this.bus.$emit('onCurrentContextmenuClick', {
 | 
			
		||||
				id: this.formInline.selectId,
 | 
			
		||||
				path: this.formInline.path,
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										170
									
								
								src/views/home/index.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								src/views/home/index.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,170 @@
 | 
			
		||||
.home {
 | 
			
		||||
	width: 100%;
 | 
			
		||||
	overflow: hidden;
 | 
			
		||||
	.home-card-more {
 | 
			
		||||
		float: right;
 | 
			
		||||
		padding: 3px 0;
 | 
			
		||||
		font-size: 13px;
 | 
			
		||||
	}
 | 
			
		||||
	.home-card-time {
 | 
			
		||||
		float: right;
 | 
			
		||||
		font-size: 13px;
 | 
			
		||||
		width: 130px;
 | 
			
		||||
		margin-top: -4px;
 | 
			
		||||
	}
 | 
			
		||||
	.user-item {
 | 
			
		||||
		height: 198px;
 | 
			
		||||
		display: flex;
 | 
			
		||||
		align-items: center;
 | 
			
		||||
		.user-item-left {
 | 
			
		||||
			width: 100px;
 | 
			
		||||
			height: 130px;
 | 
			
		||||
			border-radius: 4px;
 | 
			
		||||
			overflow: hidden;
 | 
			
		||||
			img {
 | 
			
		||||
				width: 100%;
 | 
			
		||||
				height: 100%;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		.user-item-right {
 | 
			
		||||
			flex: 1;
 | 
			
		||||
			padding: 15px;
 | 
			
		||||
			.right-title {
 | 
			
		||||
				font-size: 20px;
 | 
			
		||||
			}
 | 
			
		||||
			.right-l-v {
 | 
			
		||||
				font-size: 13px;
 | 
			
		||||
				display: flex;
 | 
			
		||||
				.right-label {
 | 
			
		||||
					color: var(--prev-color-text-regular);
 | 
			
		||||
					width: 40px;
 | 
			
		||||
				}
 | 
			
		||||
				.right-value {
 | 
			
		||||
					flex: 1;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	.info {
 | 
			
		||||
		height: 198px;
 | 
			
		||||
		.info-scroll {
 | 
			
		||||
			height: 100%;
 | 
			
		||||
			overflow: hidden;
 | 
			
		||||
			.info-ul {
 | 
			
		||||
				list-style: none;
 | 
			
		||||
				.info-item {
 | 
			
		||||
					display: flex;
 | 
			
		||||
					font-size: 13px;
 | 
			
		||||
					color: var(--prev-color-text-regular);
 | 
			
		||||
					height: 28px;
 | 
			
		||||
					line-height: 28px;
 | 
			
		||||
					&:hover {
 | 
			
		||||
						color: var(--prev-color-primary);
 | 
			
		||||
						cursor: pointer;
 | 
			
		||||
					}
 | 
			
		||||
					.info-item-left {
 | 
			
		||||
						flex: 1;
 | 
			
		||||
						flex-shrink: 0;
 | 
			
		||||
						text-overflow: ellipsis;
 | 
			
		||||
						white-space: nowrap;
 | 
			
		||||
						overflow: hidden;
 | 
			
		||||
					}
 | 
			
		||||
					.info-item-right {
 | 
			
		||||
						width: 60px;
 | 
			
		||||
						text-align: right;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	.home-recommend-row {
 | 
			
		||||
		.home-recommend {
 | 
			
		||||
			position: relative;
 | 
			
		||||
			height: 100px;
 | 
			
		||||
			color: var(--prev-color-text-white);
 | 
			
		||||
			border-radius: 4px;
 | 
			
		||||
			overflow: hidden;
 | 
			
		||||
			cursor: pointer;
 | 
			
		||||
			&:hover {
 | 
			
		||||
				i {
 | 
			
		||||
					right: 0px !important;
 | 
			
		||||
					bottom: 0px !important;
 | 
			
		||||
					transition: all ease 0.3s;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			i {
 | 
			
		||||
				position: absolute;
 | 
			
		||||
				right: -10px;
 | 
			
		||||
				bottom: -10px;
 | 
			
		||||
				font-size: 70px;
 | 
			
		||||
				transform: rotate(-30deg);
 | 
			
		||||
				transition: all ease 0.3s;
 | 
			
		||||
			}
 | 
			
		||||
			.home-recommend-auto {
 | 
			
		||||
				padding: 15px;
 | 
			
		||||
				position: absolute;
 | 
			
		||||
				left: 0;
 | 
			
		||||
				top: 5%;
 | 
			
		||||
				.home-recommend-msg {
 | 
			
		||||
					font-size: 12px;
 | 
			
		||||
					margin-top: 10px;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	.charts {
 | 
			
		||||
		width: 100%;
 | 
			
		||||
		height: 282.6px;
 | 
			
		||||
		display: flex;
 | 
			
		||||
		padding: 12px 15px;
 | 
			
		||||
		.charts-left {
 | 
			
		||||
			flex: 1;
 | 
			
		||||
			height: 100%;
 | 
			
		||||
		}
 | 
			
		||||
		.charts-right {
 | 
			
		||||
			flex: 1;
 | 
			
		||||
			height: 100%;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	.home-charts {
 | 
			
		||||
		height: 282.6px;
 | 
			
		||||
		.home-charts-item {
 | 
			
		||||
			background-color: var(--prev-bg-main-color);
 | 
			
		||||
			padding: 19px 15px;
 | 
			
		||||
			border-radius: 2px;
 | 
			
		||||
			display: flex;
 | 
			
		||||
			align-items: center;
 | 
			
		||||
			margin-bottom: 12px;
 | 
			
		||||
			cursor: pointer;
 | 
			
		||||
			&:last-of-type {
 | 
			
		||||
				margin-bottom: 0;
 | 
			
		||||
			}
 | 
			
		||||
			&:hover {
 | 
			
		||||
				.home-charts-item-right {
 | 
			
		||||
					i {
 | 
			
		||||
						transform: rotate(45deg);
 | 
			
		||||
						transition: all ease 0.3s;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			.home-charts-item-left {
 | 
			
		||||
				flex: 1;
 | 
			
		||||
				.home-charts-item-title {
 | 
			
		||||
					font-size: 13px;
 | 
			
		||||
				}
 | 
			
		||||
				.home-charts-item-num {
 | 
			
		||||
					font-size: 20px;
 | 
			
		||||
					margin-top: 5px;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			.home-charts-item-right {
 | 
			
		||||
				i {
 | 
			
		||||
					font-size: 20px;
 | 
			
		||||
					padding: 8px;
 | 
			
		||||
					border-radius: 100%;
 | 
			
		||||
					transition: all ease 0.3s;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										405
									
								
								src/views/home/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										405
									
								
								src/views/home/index.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,405 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="home">
 | 
			
		||||
		<!-- 用户信息 -->
 | 
			
		||||
		<el-row :gutter="15">
 | 
			
		||||
			<el-col :md="24" :lg="16" :xl="16" class="mb15">
 | 
			
		||||
				<el-card shadow="hover">
 | 
			
		||||
					<div slot="header">
 | 
			
		||||
						<span>{{ $t('message.card.title1') }}</span>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="user-item">
 | 
			
		||||
						<div class="user-item-left">
 | 
			
		||||
							<img :src="getUserInfos.photo" />
 | 
			
		||||
						</div>
 | 
			
		||||
						<div class="user-item-right overflow">
 | 
			
		||||
							<el-row>
 | 
			
		||||
								<el-col :span="24" class="right-title mb15 one-text-overflow"
 | 
			
		||||
									>{{ currentTime }},{{ getUserInfos.userName }},{{ dailyMessage }}
 | 
			
		||||
								</el-col>
 | 
			
		||||
								<el-col :span="24">
 | 
			
		||||
									<el-col :xs="12" :sm="12" :md="8" class="right-l-v">
 | 
			
		||||
										<div class="right-label">昵称:</div>
 | 
			
		||||
										<div class="right-value">小柒</div>
 | 
			
		||||
									</el-col>
 | 
			
		||||
									<el-col :xs="12" :sm="12" :md="16" class="right-l-v">
 | 
			
		||||
										<div class="right-label">身份:</div>
 | 
			
		||||
										<div class="right-value">{{ userInfo.userName === 'admin' ? '超级管理' : '普通用户' }}</div>
 | 
			
		||||
									</el-col>
 | 
			
		||||
								</el-col>
 | 
			
		||||
								<el-col :span="24" class="mt5">
 | 
			
		||||
									<el-col :xs="12" :sm="12" :md="8" class="right-l-v">
 | 
			
		||||
										<div class="right-label one-text-overflow">IP:</div>
 | 
			
		||||
										<div class="right-value one-text-overflow">192.168.1.1</div>
 | 
			
		||||
									</el-col>
 | 
			
		||||
									<el-col :xs="12" :sm="12" :md="16" class="right-l-v">
 | 
			
		||||
										<div class="right-label one-text-overflow">时间:</div>
 | 
			
		||||
										<div class="right-value one-text-overflow">{{ userInfo.time }}</div>
 | 
			
		||||
									</el-col>
 | 
			
		||||
								</el-col>
 | 
			
		||||
								<el-col :span="24" class="mt15">
 | 
			
		||||
									<el-button size="small" icon="el-icon-edit-outline">修改信息 </el-button>
 | 
			
		||||
									<el-button size="small" icon="el-icon-position" type="primary">发布活动</el-button>
 | 
			
		||||
								</el-col>
 | 
			
		||||
							</el-row>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
				</el-card>
 | 
			
		||||
			</el-col>
 | 
			
		||||
			<el-col :md="24" :lg="8" :xl="8" class="mb15">
 | 
			
		||||
				<el-card shadow="hover">
 | 
			
		||||
					<div slot="header">
 | 
			
		||||
						<span>{{ $t('message.card.title2') }}</span>
 | 
			
		||||
						<el-button class="home-card-more" type="text" @click="onOpenGitee">{{ $t('message.card.title3') }}</el-button>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="info">
 | 
			
		||||
						<Scroll :data="newsInfoList" class="info-scroll" :class-option="optionSingleHeight">
 | 
			
		||||
							<ul class="info-ul">
 | 
			
		||||
								<li v-for="(v, k) in newsInfoList" :key="k" class="info-item" @click="onNewsInfoListClick(v)">
 | 
			
		||||
									<div class="info-item-left" v-text="v.title"></div>
 | 
			
		||||
									<div class="info-item-right" v-text="v.date"></div>
 | 
			
		||||
								</li>
 | 
			
		||||
							</ul>
 | 
			
		||||
						</Scroll>
 | 
			
		||||
					</div>
 | 
			
		||||
				</el-card>
 | 
			
		||||
			</el-col>
 | 
			
		||||
		</el-row>
 | 
			
		||||
 | 
			
		||||
		<!-- 推荐 -->
 | 
			
		||||
		<el-card shadow="hover">
 | 
			
		||||
			<div slot="header">
 | 
			
		||||
				<span>{{ $t('message.card.title4') }}</span>
 | 
			
		||||
				<el-button class="home-card-more" type="text" @click="onOpenGitee">{{ $t('message.card.title5') }}</el-button>
 | 
			
		||||
			</div>
 | 
			
		||||
			<el-row :gutter="15" class="home-recommend-row">
 | 
			
		||||
				<el-col :sm="24" :md="12" :lg="6" :xl="6" v-for="(v, k) in recommendList" :key="k">
 | 
			
		||||
					<div class="home-recommend" :style="{ 'background-color': v.bg }">
 | 
			
		||||
						<i :class="v.icon" :style="{ color: v.iconColor }"></i>
 | 
			
		||||
						<div class="home-recommend-auto">
 | 
			
		||||
							<div>{{ v.title }}</div>
 | 
			
		||||
							<div class="home-recommend-msg">{{ v.msg }}</div>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
				</el-col>
 | 
			
		||||
			</el-row>
 | 
			
		||||
		</el-card>
 | 
			
		||||
 | 
			
		||||
		<!-- charts -->
 | 
			
		||||
		<el-row :gutter="15" class="mt15">
 | 
			
		||||
			<el-col :md="24" :lg="8" :xl="8" class="mb15">
 | 
			
		||||
				<el-card shadow="hover">
 | 
			
		||||
					<div slot="header">
 | 
			
		||||
						<span>{{ $t('message.card.title6') }}</span>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="charts">
 | 
			
		||||
						<div class="charts-right">
 | 
			
		||||
							<div ref="homeStockRef" class="h100"></div>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
				</el-card>
 | 
			
		||||
			</el-col>
 | 
			
		||||
			<el-col :md="24" :lg="16" :xl="16" class="mb15">
 | 
			
		||||
				<el-card shadow="hover">
 | 
			
		||||
					<div slot="header">
 | 
			
		||||
						<span>{{ $t('message.card.title7') }}</span>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="charts">
 | 
			
		||||
						<div class="charts-left mr7">
 | 
			
		||||
							<div ref="homeLaboratoryRef" class="h100"></div>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
				</el-card>
 | 
			
		||||
			</el-col>
 | 
			
		||||
		</el-row>
 | 
			
		||||
 | 
			
		||||
		<!-- 履约超时预警 -->
 | 
			
		||||
		<el-row :gutter="15">
 | 
			
		||||
			<el-col :md="24" :lg="16" :xl="16" class="home-lg">
 | 
			
		||||
				<el-card shadow="hover">
 | 
			
		||||
					<div slot="header">
 | 
			
		||||
						<span>{{ $t('message.card.title8') }}</span>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="charts">
 | 
			
		||||
						<div class="charts-left mr7">
 | 
			
		||||
							<div ref="homeOvertimeRef" class="h100"></div>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
				</el-card>
 | 
			
		||||
			</el-col>
 | 
			
		||||
			<el-col :md="24" :lg="8" :xl="8">
 | 
			
		||||
				<el-card shadow="hover">
 | 
			
		||||
					<div slot="header">
 | 
			
		||||
						<span>{{ $t('message.card.title9') }}</span>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="home-charts">
 | 
			
		||||
						<div class="home-charts-item" v-for="(v, k) in chartsRightList" :key="k">
 | 
			
		||||
							<div class="home-charts-item-left">
 | 
			
		||||
								<div class="home-charts-item-title">{{ v.title }}</div>
 | 
			
		||||
								<div class="home-charts-item-num" :style="{ color: v.color }" :id="`titleNum${k + 1}`"></div>
 | 
			
		||||
							</div>
 | 
			
		||||
							<div class="home-charts-item-right">
 | 
			
		||||
								<i :class="v.icon" :style="{ 'background-color': v.iconBg, color: v.color }"></i>
 | 
			
		||||
							</div>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
				</el-card>
 | 
			
		||||
			</el-col>
 | 
			
		||||
		</el-row>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import * as echarts from 'echarts';
 | 
			
		||||
import Scroll from 'vue-seamless-scroll';
 | 
			
		||||
import { CountUp } from 'countup.js';
 | 
			
		||||
import { Session } from '@/utils/storage';
 | 
			
		||||
import { formatAxis, formatDate } from '@/utils/formatTime';
 | 
			
		||||
import { recommendList, chartsRightList, newsInfoList, dailyMessage } from './mock';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'home',
 | 
			
		||||
	components: { Scroll },
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			recommendList,
 | 
			
		||||
			chartsRightList,
 | 
			
		||||
			newsInfoList,
 | 
			
		||||
			userInfo: {},
 | 
			
		||||
			dailyMessage: {},
 | 
			
		||||
			charts: {
 | 
			
		||||
				theme: '',
 | 
			
		||||
				bgColor: '',
 | 
			
		||||
			},
 | 
			
		||||
			global: {
 | 
			
		||||
				homeChartOne: null,
 | 
			
		||||
				homeChartTwo: null,
 | 
			
		||||
				homeCharThree: null,
 | 
			
		||||
				dispose: [null, '', undefined],
 | 
			
		||||
			},
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	created() {
 | 
			
		||||
		this.initUserInfo();
 | 
			
		||||
		this.initDailyMessage();
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		currentTime() {
 | 
			
		||||
			return formatAxis(new Date());
 | 
			
		||||
		},
 | 
			
		||||
		optionSingleHeight() {
 | 
			
		||||
			return {
 | 
			
		||||
				singleHeight: 28,
 | 
			
		||||
				limitMoveNum: 8,
 | 
			
		||||
				waitTime: 2000,
 | 
			
		||||
			};
 | 
			
		||||
		},
 | 
			
		||||
		getUserInfos() {
 | 
			
		||||
			return this.$store.state.userInfos.userInfos;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.initHomeStock();
 | 
			
		||||
		this.initHomeLaboratory();
 | 
			
		||||
		this.initHomeOvertime();
 | 
			
		||||
		this.initNumCountUp();
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 初始化数字滚动
 | 
			
		||||
		initNumCountUp() {
 | 
			
		||||
			this.$nextTick(() => {
 | 
			
		||||
				new CountUp('titleNum1', Math.random() * 100000).start();
 | 
			
		||||
				new CountUp('titleNum2', Math.random() * 100000).start();
 | 
			
		||||
				new CountUp('titleNum3', Math.random() * 100000).start();
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		// 库存作业
 | 
			
		||||
		initHomeStock() {
 | 
			
		||||
			if (!this.global.dispose.some((b) => b === this.global.homeChartOne)) this.global.homeChartOne.dispose();
 | 
			
		||||
			this.global.homeChartOne = echarts.init(this.$refs.homeStockRef, this.charts.theme);
 | 
			
		||||
			const option = {
 | 
			
		||||
				backgroundColor: this.charts.bgColor,
 | 
			
		||||
				grid: {
 | 
			
		||||
					top: 50,
 | 
			
		||||
					right: 20,
 | 
			
		||||
					bottom: 30,
 | 
			
		||||
					left: 30,
 | 
			
		||||
				},
 | 
			
		||||
				tooltip: {
 | 
			
		||||
					trigger: 'item',
 | 
			
		||||
				},
 | 
			
		||||
				legend: {
 | 
			
		||||
					left: 'center',
 | 
			
		||||
				},
 | 
			
		||||
				series: [
 | 
			
		||||
					{
 | 
			
		||||
						name: '邮件营销',
 | 
			
		||||
						type: 'pie',
 | 
			
		||||
						radius: ['40%', '70%'],
 | 
			
		||||
						avoidLabelOverlap: false,
 | 
			
		||||
						itemStyle: {
 | 
			
		||||
							borderRadius: 10,
 | 
			
		||||
							borderColor: '#fff',
 | 
			
		||||
							borderWidth: 2,
 | 
			
		||||
						},
 | 
			
		||||
						data: [
 | 
			
		||||
							{ value: 580, name: '邮件营销' },
 | 
			
		||||
							{ value: 300, name: '视频广告' },
 | 
			
		||||
							{ value: 230, name: '联盟广告' },
 | 
			
		||||
						],
 | 
			
		||||
						top: 30,
 | 
			
		||||
					},
 | 
			
		||||
				],
 | 
			
		||||
			};
 | 
			
		||||
			this.global.homeChartOne.setOption(option);
 | 
			
		||||
			window.addEventListener('resize', () => {
 | 
			
		||||
				this.global.homeChartOne.resize();
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		// 履约情况
 | 
			
		||||
		initHomeLaboratory() {
 | 
			
		||||
			if (!this.global.dispose.some((b) => b === this.global.homeChartTwo)) this.global.homeChartTwo.dispose();
 | 
			
		||||
			this.global.homeChartTwo = echarts.init(this.$refs.homeLaboratoryRef, this.charts.theme);
 | 
			
		||||
			const option = {
 | 
			
		||||
				backgroundColor: this.charts.bgColor,
 | 
			
		||||
				grid: {
 | 
			
		||||
					top: 50,
 | 
			
		||||
					right: 20,
 | 
			
		||||
					bottom: 30,
 | 
			
		||||
					left: 30,
 | 
			
		||||
				},
 | 
			
		||||
				tooltip: {
 | 
			
		||||
					trigger: 'axis',
 | 
			
		||||
				},
 | 
			
		||||
				legend: {
 | 
			
		||||
					data: ['预购队列', '最新成交价'],
 | 
			
		||||
					right: 13,
 | 
			
		||||
				},
 | 
			
		||||
				xAxis: {
 | 
			
		||||
					data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子'],
 | 
			
		||||
				},
 | 
			
		||||
				yAxis: [
 | 
			
		||||
					{
 | 
			
		||||
						type: 'value',
 | 
			
		||||
						name: '价格',
 | 
			
		||||
					},
 | 
			
		||||
				],
 | 
			
		||||
				series: [
 | 
			
		||||
					{
 | 
			
		||||
						name: '预购队列',
 | 
			
		||||
						type: 'bar',
 | 
			
		||||
						data: [5, 20, 36, 10, 10, 20],
 | 
			
		||||
					},
 | 
			
		||||
					{
 | 
			
		||||
						name: '最新成交价',
 | 
			
		||||
						type: 'line',
 | 
			
		||||
						data: [15, 20, 16, 20, 30, 8],
 | 
			
		||||
					},
 | 
			
		||||
				],
 | 
			
		||||
			};
 | 
			
		||||
			this.global.homeChartTwo.setOption(option);
 | 
			
		||||
			window.addEventListener('resize', () => {
 | 
			
		||||
				this.global.homeChartTwo.resize();
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		// 缺货监控
 | 
			
		||||
		initHomeOvertime() {
 | 
			
		||||
			if (!this.global.dispose.some((b) => b === this.global.homeCharThree)) this.global.homeCharThree.dispose();
 | 
			
		||||
			this.global.homeCharThree = echarts.init(this.$refs.homeOvertimeRef, this.charts.theme);
 | 
			
		||||
			const option = {
 | 
			
		||||
				backgroundColor: this.charts.bgColor,
 | 
			
		||||
				grid: {
 | 
			
		||||
					top: 50,
 | 
			
		||||
					right: 20,
 | 
			
		||||
					bottom: 30,
 | 
			
		||||
					left: 30,
 | 
			
		||||
				},
 | 
			
		||||
				tooltip: {
 | 
			
		||||
					trigger: 'axis',
 | 
			
		||||
				},
 | 
			
		||||
				legend: {
 | 
			
		||||
					data: ['订单数量', '超时数量', '在线数量', '预警数量'],
 | 
			
		||||
					right: 13,
 | 
			
		||||
				},
 | 
			
		||||
				xAxis: {
 | 
			
		||||
					data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
 | 
			
		||||
				},
 | 
			
		||||
				yAxis: [
 | 
			
		||||
					{
 | 
			
		||||
						type: 'value',
 | 
			
		||||
						name: '数量',
 | 
			
		||||
					},
 | 
			
		||||
				],
 | 
			
		||||
				series: [
 | 
			
		||||
					{
 | 
			
		||||
						name: '订单数量',
 | 
			
		||||
						type: 'bar',
 | 
			
		||||
						data: [5, 20, 36, 10, 10, 20, 11, 13, 10, 9, 17, 19],
 | 
			
		||||
					},
 | 
			
		||||
					{
 | 
			
		||||
						name: '超时数量',
 | 
			
		||||
						type: 'bar',
 | 
			
		||||
						data: [15, 12, 26, 15, 11, 16, 31, 13, 5, 16, 13, 15],
 | 
			
		||||
					},
 | 
			
		||||
					{
 | 
			
		||||
						name: '在线数量',
 | 
			
		||||
						type: 'line',
 | 
			
		||||
						data: [15, 20, 16, 20, 30, 8, 16, 19, 12, 18, 19, 14],
 | 
			
		||||
					},
 | 
			
		||||
					{
 | 
			
		||||
						name: '预警数量',
 | 
			
		||||
						type: 'line',
 | 
			
		||||
						data: [10, 10, 13, 12, 15, 18, 19, 10, 12, 15, 11, 17],
 | 
			
		||||
					},
 | 
			
		||||
				],
 | 
			
		||||
			};
 | 
			
		||||
			this.global.homeCharThree.setOption(option);
 | 
			
		||||
			window.addEventListener('resize', () => {
 | 
			
		||||
				this.global.homeCharThree.resize();
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		// 随机语录
 | 
			
		||||
		initDailyMessage() {
 | 
			
		||||
			this.dailyMessage = dailyMessage[Math.floor(Math.random() * dailyMessage.length)];
 | 
			
		||||
		},
 | 
			
		||||
		// 初始化登录信息
 | 
			
		||||
		initUserInfo() {
 | 
			
		||||
			if (!Session.get('userInfo')) return false;
 | 
			
		||||
			this.userInfo = Session.get('userInfo');
 | 
			
		||||
			this.userInfo.time = formatDate(new Date(this.userInfo.time), 'YYYY-mm-dd HH:MM:SS');
 | 
			
		||||
		},
 | 
			
		||||
		// 消息通知当前项点击
 | 
			
		||||
		onNewsInfoListClick(v) {
 | 
			
		||||
			window.open(v.link);
 | 
			
		||||
		},
 | 
			
		||||
		// 跳转到 gitee
 | 
			
		||||
		onOpenGitee() {
 | 
			
		||||
			window.open('https://gitee.com/lyt-top/vue-next-admin');
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	watch: {
 | 
			
		||||
		// 监听 vuex 数据变化
 | 
			
		||||
		'$store.state.themeConfig.themeConfig.isIsDark': {
 | 
			
		||||
			handler(isIsDark) {
 | 
			
		||||
				this.$nextTick(() => {
 | 
			
		||||
					this.charts.theme = isIsDark ? 'dark' : '';
 | 
			
		||||
					this.charts.bgColor = isIsDark ? 'transparent' : '';
 | 
			
		||||
					setTimeout(() => {
 | 
			
		||||
						this.initHomeStock();
 | 
			
		||||
					}, 500);
 | 
			
		||||
					setTimeout(() => {
 | 
			
		||||
						this.initHomeLaboratory();
 | 
			
		||||
					}, 700);
 | 
			
		||||
					setTimeout(() => {
 | 
			
		||||
						this.initHomeOvertime();
 | 
			
		||||
					}, 1000);
 | 
			
		||||
				});
 | 
			
		||||
			},
 | 
			
		||||
			deep: true,
 | 
			
		||||
			immediate: true,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
@import './index.scss';
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										103
									
								
								src/views/home/mock.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								src/views/home/mock.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
			
		||||
// 首页模拟数据
 | 
			
		||||
export const recommendList = [
 | 
			
		||||
	{
 | 
			
		||||
		title: '优惠券',
 | 
			
		||||
		msg: '现金券、折扣券、营销必备',
 | 
			
		||||
		icon: 'el-icon-food',
 | 
			
		||||
		bg: '#48D18D',
 | 
			
		||||
		iconColor: '#64d89d',
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		title: '多人拼团',
 | 
			
		||||
		msg: '社交电商、开辟流量',
 | 
			
		||||
		icon: 'el-icon-shopping-bag-1',
 | 
			
		||||
		bg: '#F95959',
 | 
			
		||||
		iconColor: '#F86C6B',
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		title: '分销中心',
 | 
			
		||||
		msg: '轻松招募分销员,成功推广奖励',
 | 
			
		||||
		icon: 'el-icon-school',
 | 
			
		||||
		bg: '#8595F4',
 | 
			
		||||
		iconColor: '#92A1F4',
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		title: '秒杀',
 | 
			
		||||
		msg: '超低价抢购引导更多销量',
 | 
			
		||||
		icon: 'el-icon-alarm-clock',
 | 
			
		||||
		bg: '#FEBB50',
 | 
			
		||||
		iconColor: '#FDC566',
 | 
			
		||||
	},
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export const chartsRightList = [
 | 
			
		||||
	{
 | 
			
		||||
		title: '距离60分钟订单数量',
 | 
			
		||||
		num: 188,
 | 
			
		||||
		icon: 'el-icon-document',
 | 
			
		||||
		iconBg: '#C3E9FE',
 | 
			
		||||
		color: '#1890FF',
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		title: '距离30分钟订单数量',
 | 
			
		||||
		num: 15,
 | 
			
		||||
		icon: 'el-icon-tickets',
 | 
			
		||||
		iconBg: '#F1EBC5',
 | 
			
		||||
		color: '#FDB850',
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		title: '已超时数量',
 | 
			
		||||
		num: 6,
 | 
			
		||||
		icon: 'el-icon-document-delete',
 | 
			
		||||
		iconBg: '#F2D7C4',
 | 
			
		||||
		color: '#F8958C',
 | 
			
		||||
	},
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export const newsInfoList = [
 | 
			
		||||
	{
 | 
			
		||||
		title: '[发布] 2021年02月28日发布基于 vue3.x + vite v1.0.0 版本',
 | 
			
		||||
		date: '02/28',
 | 
			
		||||
		link: 'https://gitee.com/lyt-top/vue-next-admin',
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		title: '[发布] 2021年04月15日发布 vue2.x + webpack 重构版本',
 | 
			
		||||
		date: '04/15',
 | 
			
		||||
		link: 'https://gitee.com/lyt-top/vue-next-admin/tree/vue-prev-admin/',
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		title: '[重构] 2021年04月10日 重构 vue2.x + webpack v1.0.0 版本',
 | 
			
		||||
		date: '04/10',
 | 
			
		||||
		link: 'https://gitee.com/lyt-top/vue-next-admin/tree/vue-prev-admin/',
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		title: '[预览] 2020年12月08日,基于 vue3.x 版本后台模板的预览',
 | 
			
		||||
		date: '12/08',
 | 
			
		||||
		link: 'http://lyt-top.gitee.io/vue-next-admin-preview/#/login',
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		title: '[预览] 2020年11月15日,基于 vue2.x 版本后台模板的预览',
 | 
			
		||||
		date: '11/15',
 | 
			
		||||
		link: 'https://lyt-top.gitee.io/vue-prev-admin-preview/#/login',
 | 
			
		||||
	},
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export const dailyMessage = [
 | 
			
		||||
	'祝你开心每一天!',
 | 
			
		||||
	'忙碌了一周,停一停脚步!',
 | 
			
		||||
	'世间美好,与你环环相扣!',
 | 
			
		||||
	'永远相信美好的事情即将发生!',
 | 
			
		||||
	'每一天,遇见更好的自己!',
 | 
			
		||||
	'保持热爱,奔赴山海!',
 | 
			
		||||
	'生活明朗,万物可爱!',
 | 
			
		||||
	'愿每一天醒来都是美好的开始!',
 | 
			
		||||
	'没有希望的地方,就没有奋斗!',
 | 
			
		||||
	'我最珍贵的时光都行走在路上!',
 | 
			
		||||
	'成功,往往住在失败的隔壁!',
 | 
			
		||||
	'人只要不失去方向,就不会失去自己!',
 | 
			
		||||
	'每条堵住的路,都有一个出口!',
 | 
			
		||||
	'没有谁能击垮你,除非你自甘堕落!',
 | 
			
		||||
	'微笑着的人并非没有痛苦!',
 | 
			
		||||
	'生活变的再糟糕,也不妨碍我变得更好!',
 | 
			
		||||
	'你要悄悄努力,然后惊艳众人!',
 | 
			
		||||
];
 | 
			
		||||
							
								
								
									
										346
									
								
								src/views/login/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										346
									
								
								src/views/login/index.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,346 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="login">
 | 
			
		||||
		<div class="login-weaper">
 | 
			
		||||
			<div class="login-left">
 | 
			
		||||
				<div class="login-time">{{ time.txt }}</div>
 | 
			
		||||
				<div class="login-left-box">
 | 
			
		||||
					<div>
 | 
			
		||||
						<div class="logo">{{ getThemeConfig.globalViceTitle }}</div>
 | 
			
		||||
						<h2 class="title">{{ getThemeConfig.globalViceDes }}</h2>
 | 
			
		||||
						<div class="msg">
 | 
			
		||||
							<div class="msg-author">
 | 
			
		||||
								<span>{{ quotations.name }}</span>
 | 
			
		||||
								<span>{{ quotations.comeFrom }}</span>
 | 
			
		||||
							</div>
 | 
			
		||||
							<div class="msg-txt">{{ quotations.content }}</div>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="login-right">
 | 
			
		||||
				<div class="login-main">
 | 
			
		||||
					<h4 class="login-title">{{ getThemeConfig.globalTitle }}</h4>
 | 
			
		||||
					<el-form class="el-form login-form">
 | 
			
		||||
						<el-form-item style="margin-left: 0px" prop="userName">
 | 
			
		||||
							<el-input
 | 
			
		||||
								type="text"
 | 
			
		||||
								:placeholder="$t('message.login.placeholder1')"
 | 
			
		||||
								prefix-icon="el-icon-user"
 | 
			
		||||
								v-model="ruleForm.userName"
 | 
			
		||||
								clearable
 | 
			
		||||
								autocomplete="off"
 | 
			
		||||
							>
 | 
			
		||||
							</el-input>
 | 
			
		||||
						</el-form-item>
 | 
			
		||||
						<el-form-item style="margin-left: 0px" prop="password">
 | 
			
		||||
							<el-input
 | 
			
		||||
								type="password"
 | 
			
		||||
								:placeholder="$t('message.login.placeholder2')"
 | 
			
		||||
								prefix-icon="el-icon-lock"
 | 
			
		||||
								v-model="ruleForm.password"
 | 
			
		||||
								autocomplete="off"
 | 
			
		||||
								:show-password="true"
 | 
			
		||||
							>
 | 
			
		||||
							</el-input>
 | 
			
		||||
						</el-form-item>
 | 
			
		||||
						<el-form-item style="margin-left: 0px" prop="code">
 | 
			
		||||
							<div class="el-row" span="24">
 | 
			
		||||
								<div class="el-col el-col-16">
 | 
			
		||||
									<el-input
 | 
			
		||||
										type="text"
 | 
			
		||||
										maxlength="4"
 | 
			
		||||
										:placeholder="$t('message.login.placeholder3')"
 | 
			
		||||
										prefix-icon="el-icon-position"
 | 
			
		||||
										v-model="ruleForm.code"
 | 
			
		||||
										clearable
 | 
			
		||||
										autocomplete="off"
 | 
			
		||||
									></el-input>
 | 
			
		||||
								</div>
 | 
			
		||||
								<div class="el-col el-col-8">
 | 
			
		||||
									<div class="login-code">
 | 
			
		||||
										<span class="login-code-img">1234</span>
 | 
			
		||||
									</div>
 | 
			
		||||
								</div>
 | 
			
		||||
							</div>
 | 
			
		||||
						</el-form-item>
 | 
			
		||||
						<el-form-item style="margin: 40px 0px 0">
 | 
			
		||||
							<el-button type="primary" class="login-submit" @click="submitForm" :loading="submit.loading">
 | 
			
		||||
								<span>{{ $t('message.login.btnText') }}</span>
 | 
			
		||||
							</el-button>
 | 
			
		||||
						</el-form-item>
 | 
			
		||||
					</el-form>
 | 
			
		||||
					<div class="login-menu">
 | 
			
		||||
						<a href="javascript:;">{{ $t('message.login.link.one1') }}</a>
 | 
			
		||||
						<a href="javascript:;">{{ $t('message.login.link.one2') }}</a>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="vue-particles">
 | 
			
		||||
			<vue-particles color="#dedede" shapeType="star" linesColor="#dedede" hoverMode="grab" clickMode="push" style="height: 100%"></vue-particles>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { Session } from '@/utils/storage';
 | 
			
		||||
import { formatDate, formatAxis } from '@/utils/formatTime';
 | 
			
		||||
import { PrevLoading } from '@/utils/loading.js';
 | 
			
		||||
import { quotationsList } from './mock';
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'login',
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			quotationsList,
 | 
			
		||||
			quotations: {},
 | 
			
		||||
			isView: false,
 | 
			
		||||
			submit: {
 | 
			
		||||
				loading: false,
 | 
			
		||||
			},
 | 
			
		||||
			ruleForm: {
 | 
			
		||||
				userName: 'admin',
 | 
			
		||||
				password: '123456',
 | 
			
		||||
				code: '1234',
 | 
			
		||||
			},
 | 
			
		||||
			time: {
 | 
			
		||||
				txt: '',
 | 
			
		||||
				fun: null,
 | 
			
		||||
			},
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		// 获取当前时间
 | 
			
		||||
		currentTime() {
 | 
			
		||||
			return formatAxis(new Date());
 | 
			
		||||
		},
 | 
			
		||||
		// 获取布局配置信息
 | 
			
		||||
		getThemeConfig() {
 | 
			
		||||
			return this.$store.state.themeConfig.themeConfig;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	created() {
 | 
			
		||||
		this.initTime();
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.initRandomQuotations();
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		// 随机语录
 | 
			
		||||
		initRandomQuotations() {
 | 
			
		||||
			this.quotations = this.quotationsList[Math.floor(Math.random() * this.quotationsList.length)];
 | 
			
		||||
		},
 | 
			
		||||
		// 初始化左上角时间显示
 | 
			
		||||
		initTime() {
 | 
			
		||||
			this.time.txt = formatDate(new Date(), 'YYYY-mm-dd HH:MM:SS WWW QQQQ');
 | 
			
		||||
			this.time.fun = setInterval(() => {
 | 
			
		||||
				this.time.txt = formatDate(new Date(), 'YYYY-mm-dd HH:MM:SS WWW QQQQ');
 | 
			
		||||
			}, 1000);
 | 
			
		||||
		},
 | 
			
		||||
		// 登录按钮点击
 | 
			
		||||
		submitForm() {
 | 
			
		||||
			this.submit.loading = true;
 | 
			
		||||
			setTimeout(() => {
 | 
			
		||||
				let defaultRoles = [];
 | 
			
		||||
				let defaultAuthBtnList = [];
 | 
			
		||||
				// admin 页面权限标识,对应路由 meta.roles
 | 
			
		||||
				let adminRoles = ['admin'];
 | 
			
		||||
				// admin 按钮权限标识
 | 
			
		||||
				let adminAuthBtnList = ['btn.add', 'btn.del', 'btn.edit', 'btn.link'];
 | 
			
		||||
				// common 页面权限标识,对应路由 meta.roles
 | 
			
		||||
				let testAuthPageList = ['common'];
 | 
			
		||||
				// test 按钮权限标识
 | 
			
		||||
				let testAuthBtnList = ['btn.add', 'btn.link'];
 | 
			
		||||
				if (this.ruleForm.userName === 'admin') {
 | 
			
		||||
					defaultRoles = adminRoles;
 | 
			
		||||
					defaultAuthBtnList = adminAuthBtnList;
 | 
			
		||||
				} else {
 | 
			
		||||
					defaultRoles = testAuthPageList;
 | 
			
		||||
					defaultAuthBtnList = testAuthBtnList;
 | 
			
		||||
				}
 | 
			
		||||
				const userInfos = {
 | 
			
		||||
					userName: this.ruleForm.userName === 'admin' ? 'admin' : 'test',
 | 
			
		||||
					photo:
 | 
			
		||||
						this.ruleForm.userName === 'admin'
 | 
			
		||||
							? 'https://img0.baidu.com/it/u=1833472230,3849481738&fm=253&fmt=auto?w=200&h=200'
 | 
			
		||||
							: 'https://img2.baidu.com/it/u=2187913762,2708298335&fm=253&fmt=auto&app=138&f=JPEG?w=200&h=200',
 | 
			
		||||
					time: new Date().getTime(),
 | 
			
		||||
					roles: defaultRoles,
 | 
			
		||||
					authBtnList: defaultAuthBtnList,
 | 
			
		||||
				};
 | 
			
		||||
				// 存储 token 到浏览器缓存
 | 
			
		||||
				Session.set('token', Math.random().toString(36).substr(0));
 | 
			
		||||
				// 存储用户信息到浏览器缓存
 | 
			
		||||
				Session.set('userInfo', userInfos);
 | 
			
		||||
				// 存储用户信息到vuex
 | 
			
		||||
				this.$store.dispatch('userInfos/setUserInfos', userInfos);
 | 
			
		||||
				PrevLoading.start();
 | 
			
		||||
				this.$router.push('/');
 | 
			
		||||
				setTimeout(() => {
 | 
			
		||||
					this.$message.success(`${this.currentTime},${this.$t('message.login.signInText')}`);
 | 
			
		||||
				}, 300);
 | 
			
		||||
			}, 300);
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	destroyed() {
 | 
			
		||||
		clearInterval(this.time.fun);
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.login {
 | 
			
		||||
	height: 100%;
 | 
			
		||||
	width: 100%;
 | 
			
		||||
	overflow: hidden;
 | 
			
		||||
	display: flex;
 | 
			
		||||
	position: relative;
 | 
			
		||||
	.vue-particles {
 | 
			
		||||
		position: absolute;
 | 
			
		||||
		top: 0;
 | 
			
		||||
		left: 0;
 | 
			
		||||
		width: 100%;
 | 
			
		||||
		height: 100%;
 | 
			
		||||
		background: radial-gradient(ellipse at top left, rgba(105, 155, 200, 1) 0%, rgba(181, 197, 216, 1) 57%);
 | 
			
		||||
	}
 | 
			
		||||
	.login-weaper {
 | 
			
		||||
		margin: auto;
 | 
			
		||||
		height: 500px;
 | 
			
		||||
		display: flex;
 | 
			
		||||
		box-sizing: border-box;
 | 
			
		||||
		position: relative;
 | 
			
		||||
		z-index: 1;
 | 
			
		||||
		border: none;
 | 
			
		||||
		box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
 | 
			
		||||
		.login-left {
 | 
			
		||||
			width: 491px;
 | 
			
		||||
			padding: 20px;
 | 
			
		||||
			font-size: 16px;
 | 
			
		||||
			color: var(--prev-color-text-white);
 | 
			
		||||
			position: relative;
 | 
			
		||||
			background-color: var(--prev-color-primary);
 | 
			
		||||
			display: flex;
 | 
			
		||||
			flex-direction: column;
 | 
			
		||||
			border-top-left-radius: 4px;
 | 
			
		||||
			border-bottom-left-radius: 4px;
 | 
			
		||||
			.login-time {
 | 
			
		||||
				width: 100%;
 | 
			
		||||
				color: var(--prev-color-text-white);
 | 
			
		||||
				opacity: 0.9;
 | 
			
		||||
				font-size: 14px;
 | 
			
		||||
				overflow: hidden;
 | 
			
		||||
			}
 | 
			
		||||
			.login-left-box {
 | 
			
		||||
				flex: 1;
 | 
			
		||||
				overflow: hidden;
 | 
			
		||||
				position: relative;
 | 
			
		||||
				z-index: 1;
 | 
			
		||||
				display: flex;
 | 
			
		||||
				align-items: center;
 | 
			
		||||
				padding: 80px 45px;
 | 
			
		||||
				.logo {
 | 
			
		||||
					font-size: 22px;
 | 
			
		||||
					margin-bottom: 15px;
 | 
			
		||||
				}
 | 
			
		||||
				.title {
 | 
			
		||||
					color: var(--prev-color-text-white);
 | 
			
		||||
					font-weight: 300;
 | 
			
		||||
					letter-spacing: 2px;
 | 
			
		||||
					font-size: 16px;
 | 
			
		||||
				}
 | 
			
		||||
				.msg {
 | 
			
		||||
					color: var(--prev-color-text-white);
 | 
			
		||||
					font-size: 13px;
 | 
			
		||||
					margin-top: 35px;
 | 
			
		||||
					.msg-author {
 | 
			
		||||
						opacity: 0.6;
 | 
			
		||||
						span:last-of-type {
 | 
			
		||||
							margin-left: 15px;
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					.msg-txt {
 | 
			
		||||
						margin-top: 15px;
 | 
			
		||||
						line-height: 22px;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		.login-right {
 | 
			
		||||
			width: 491px;
 | 
			
		||||
			padding: 20px;
 | 
			
		||||
			position: relative;
 | 
			
		||||
			align-items: center;
 | 
			
		||||
			display: flex;
 | 
			
		||||
			background-color: var(--prev-bg-white);
 | 
			
		||||
			border-top-right-radius: 4px;
 | 
			
		||||
			border-bottom-right-radius: 4px;
 | 
			
		||||
			.login-main {
 | 
			
		||||
				margin: 0 auto;
 | 
			
		||||
				width: 70%;
 | 
			
		||||
				.login-title {
 | 
			
		||||
					color: var(--prev-color-text-primary);
 | 
			
		||||
					margin-bottom: 40px;
 | 
			
		||||
					font-weight: 500;
 | 
			
		||||
					font-size: 22px;
 | 
			
		||||
					text-align: center;
 | 
			
		||||
					letter-spacing: 4px;
 | 
			
		||||
				}
 | 
			
		||||
				.login-form {
 | 
			
		||||
					margin: 10px 0;
 | 
			
		||||
					i {
 | 
			
		||||
						color: var(--prev-color-text-primary);
 | 
			
		||||
					}
 | 
			
		||||
					.el-form-item {
 | 
			
		||||
						margin-bottom: 20px !important;
 | 
			
		||||
						.login-code {
 | 
			
		||||
							display: flex;
 | 
			
		||||
							align-items: center;
 | 
			
		||||
							justify-content: space-around;
 | 
			
		||||
							margin: 0 0 0 10px;
 | 
			
		||||
							user-select: none;
 | 
			
		||||
							.login-code-img {
 | 
			
		||||
								margin-top: 2px;
 | 
			
		||||
								width: 100px;
 | 
			
		||||
								height: 38px;
 | 
			
		||||
								border: 1px solid var(--prev-border-color-base);
 | 
			
		||||
								color: var(--prev-color-text-primary);
 | 
			
		||||
								font-size: 14px;
 | 
			
		||||
								font-weight: 700;
 | 
			
		||||
								letter-spacing: 5px;
 | 
			
		||||
								line-height: 38px;
 | 
			
		||||
								text-indent: 5px;
 | 
			
		||||
								text-align: center;
 | 
			
		||||
								cursor: pointer;
 | 
			
		||||
								transition: all ease 0.2s;
 | 
			
		||||
								border-radius: 4px;
 | 
			
		||||
								&:hover {
 | 
			
		||||
									border-color: var(--prev-border-color-hover);
 | 
			
		||||
									transition: all ease 0.2s;
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
						.login-submit {
 | 
			
		||||
							width: 100%;
 | 
			
		||||
							letter-spacing: 2px;
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				.login-menu {
 | 
			
		||||
					margin-top: 30px;
 | 
			
		||||
					width: 100%;
 | 
			
		||||
					text-align: left;
 | 
			
		||||
					a {
 | 
			
		||||
						color: var(--prev-color-text-secondary);
 | 
			
		||||
						font-size: 12px;
 | 
			
		||||
						margin: 0 8px;
 | 
			
		||||
						text-decoration: none;
 | 
			
		||||
						&:hover {
 | 
			
		||||
							color: var(--prev-color-primary);
 | 
			
		||||
							text-decoration: underline;
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										38
									
								
								src/views/login/mock.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/views/login/mock.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
export const quotationsList = [
 | 
			
		||||
	{
 | 
			
		||||
		name: '颜渊',
 | 
			
		||||
		comeFrom: '论语',
 | 
			
		||||
		content:
 | 
			
		||||
			'自己不喜欢的,就不要强加给别人。饥寒是自己不喜欢的,不要把它强加给别人;耻辱是自己不喜欢的,也不要把它强加给别人。将心比心,推己及人,从自己的利与害想到对别人的利与害,多替别人着想,这是终生应该奉行的原则。',
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		name: '荀子',
 | 
			
		||||
		comeFrom: '劝学',
 | 
			
		||||
		content:
 | 
			
		||||
			'木料经过木工用墨线(木工用具)划直线加工以后,就变直了;金属物品在磨刀石上磨砺后,就能锋利。人经过学习磨练,自我反省,就会变得聪慧明智,不犯错误,也越来越坚强。',
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		name: '里仁',
 | 
			
		||||
		comeFrom: '论语',
 | 
			
		||||
		content:
 | 
			
		||||
			'见到贤人,就应该想着向他学习;看见不贤的人,便应该自己反省,对不如自己的人喜欢讥笑、轻视,因而沾沾自喜;对比自己强的人喜欢贬低,甚至嫉妒、畏惧退缩,害怕与他们交往:这都是不正确的态度。',
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		name: '述而',
 | 
			
		||||
		comeFrom: '论语',
 | 
			
		||||
		content:
 | 
			
		||||
			'君子心地平坦宽广,小人却经常局促忧愁。君子襟怀坦白,安贫乐业,与人为善,知足常乐,所以能坦荡荡。小人欲念太多,患得患失,忧心忡忡,怨天尤人,局促不安,所以常心怀戚戚。',
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		name: '老子',
 | 
			
		||||
		comeFrom: '第六十四章',
 | 
			
		||||
		content:
 | 
			
		||||
			'千里遥远的路程是从脚下第一步开始的。任何事情的成功都是从头开始,从小到大逐渐积累的。万事开头难,没有个开头就不会有结果。任何事情都要从一点一滴的小事开始做起。',
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		name: '朱熹',
 | 
			
		||||
		comeFrom: '训学斋规',
 | 
			
		||||
		content:
 | 
			
		||||
			'读书有三到,谓心到,眼到,口到。心不在此,则眼看不仔细,心眼既不专一,却只漫浪诵读,决不能记,久也不能久也。三到之中,心到最急,心既到矣,眼口岂不到乎?',
 | 
			
		||||
	},
 | 
			
		||||
];
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user