Commit ff9cc7e2 authored by Z's avatar Z

Z: Dot: PC D2Admin is done.

parent 66d292d7
[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true
# 所有环境默认
# 页面 title 前缀
VUE_APP_TITLE=D2Admin
# 网络请求公用地址
VUE_APP_API=/api/
# 仓库地址
VUE_APP_REPO=https://github.com/d2-projects/d2-admin-start-kit
# 国际化配置
VUE_APP_I18N_LOCALE=zh-chs
VUE_APP_I18N_FALLBACK_LOCALE=en
# element 颜色
VUE_APP_ELEMENT_COLOR=#409EFF
# 开发环境
# 页面 title 前缀
VUE_APP_TITLE=D2Admin Dev
# 构建预览页面
# 指定构建模式
NODE_ENV=production
# 标记当前构建方式
VUE_APP_BUILD_MODE=PREVIEW
# 显示源码按钮
VUE_APP_SCOURCE_LINK=TRUE
# 部署路径
VUE_APP_PUBLIC_PATH=/d2-admin-start-kit/
# 构建预览页面
# 指定构建模式
NODE_ENV=production
# 标记当前构建方式
VUE_APP_BUILD_MODE=PREVIEW
# 显示源码按钮
VUE_APP_SCOURCE_LINK=TRUE
# 部署路径
VUE_APP_PUBLIC_PATH=/
# No Mock 构建
# 指定构建模式
NODE_ENV=production
# 标记当前是 No Mock 构建
VUE_APP_BUILD_MODE=NOMOCK
# 构建预览页面
# 指定构建模式
NODE_ENV=production
# 标记当前构建方式
VUE_APP_BUILD_MODE=PREVIEW
# 显示源码按钮
VUE_APP_SCOURCE_LINK=TRUE
# 部署路径
VUE_APP_PUBLIC_PATH=/d2-admin-start-kit/preview/
# 忽略目录
build/
tests/
node_modules/
# D2CRUD 演示
src/views/demo/d2-crud/
# node 覆盖率文件
coverage/
# 忽略文件
**/*-min.js
**/*.min.js
......@@ -5,13 +5,25 @@ module.exports = {
},
'extends': [
'plugin:vue/essential',
'eslint:recommended'
'@vue/standard'
],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-unused-vars': 'off'
},
parserOptions: {
parser: 'babel-eslint'
},
overrides: [
{
files: [
'**/__tests__/*.{j,t}s?(x)',
'**/tests/unit/**/*.spec.{j,t}s?(x)'
],
env: {
jest: true
}
}
]
}
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
module.exports = {
plugins: {
autoprefixer: {}
}
}
MIT License
Copyright (c) 2018 李杨
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.
# ybf_admin
[D2Admin](https://github.com/d2-projects/d2-admin) is a fully open source and free enterprise back-end product front-end integration solution, using the latest front-end technology stack, javascript files loading of local first screen less than 60kb, has prepared most of the project preparations, and with a lot of sample code to help the management system agile development.
## Project setup
```
npm install
```
[中文](https://github.com/d2-projects/d2-admin-start-kit/blob/master/README.zh.md) | **English**
### Compiles and hot-reloads for development
```
npm run serve
```
## Preview
### Compiles and minifies for production
```
npm run build
```
| server | link | server | status |
| --- | --- | --- | --- |
| d2.pub | [d2.pub/d2-admin-start-kit/preview](https://d2.pub/d2-admin-start-kit/preview) | China server | [![](https://github.com/d2-projects/d2-admin-start-kit/workflows/Deploy%20https%3A%2F%2Fd2.pub/badge.svg)](https://github.com/d2-projects/d2-admin-start-kit/actions?query=workflow%3A%22Deploy+https%3A%2F%2Fd2.pub%22) |
| cdn.d2.pub | [cdn.d2.pub/d2-admin-start-kit/preview](https://cdn.d2.pub/d2-admin-start-kit/preview) | qiniu CDN | [![](https://github.com/d2-projects/d2-admin-start-kit/workflows/Deploy%20https%3A%2F%2Fcdn.d2.pub/badge.svg)](https://github.com/d2-projects/d2-admin-start-kit/actions?query=workflow%3A%22Deploy+https%3A%2F%2Fcdn.d2.pub%22) |
| github | [d2-projects.github.io/d2-admin-start-kit](https://d2-projects.github.io/d2-admin-start-kit) | GitHub pages | [![](https://github.com/d2-projects/d2-admin-start-kit/workflows/Deploy%20Github/badge.svg)](https://github.com/d2-projects/d2-admin-start-kit/actions?query=workflow%3A%22Deploy+Github%22) |
| netlify | [d2-admin-start-kit.netlify.com](https://d2-admin-start-kit.netlify.com) | Netlify CDN | [![](https://api.netlify.com/api/v1/badges/08ff8c93-f0a8-497a-a081-440b31fb3aa4/deploy-status)](https://app.netlify.com/sites/d2-admin-start-kit/deploys) |
### Run your tests
```
npm run test
```
## Other synchronous repositories
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
| type | link |
| --- | --- |
| gitee | [https://gitee.com/fairyever/d2-admin](https://gitee.com/fairyever/d2-admin) |
| coding | [https://d2-projects.coding.net/p/d2-projects/d/d2-admin/git](https://d2-projects.coding.net/p/d2-projects/d/d2-admin/git) |
\ No newline at end of file
[D2Admin](https://github.com/d2-projects/d2-admin) 是一个完全 **开源免费** 的企业中后台产品前端集成方案,使用最新的前端技术栈,小于 60kb 的本地首屏 js 加载,已经做好大部分项目前期准备工作,并且带有大量示例代码,助力管理系统敏捷开发。
**中文** | [English](https://github.com/d2-projects/d2-admin-start-kit)
## 预览
| 位置 | 链接 | 部署位置 | 状态 |
| --- | --- | --- | --- |
| d2.pub | [d2.pub/d2-admin-start-kit/preview](https://d2.pub/d2-admin-start-kit/preview) | 中国服务器 | [![](https://github.com/d2-projects/d2-admin-start-kit/workflows/Deploy%20https%3A%2F%2Fd2.pub/badge.svg)](https://github.com/d2-projects/d2-admin-start-kit/actions?query=workflow%3A%22Deploy+https%3A%2F%2Fd2.pub%22) |
| cdn.d2.pub | [cdn.d2.pub/d2-admin-start-kit/preview](https://cdn.d2.pub/d2-admin-start-kit/preview) | 七牛云 CDN | [![](https://github.com/d2-projects/d2-admin-start-kit/workflows/Deploy%20https%3A%2F%2Fcdn.d2.pub/badge.svg)](https://github.com/d2-projects/d2-admin-start-kit/actions?query=workflow%3A%22Deploy+https%3A%2F%2Fcdn.d2.pub%22) |
| github | [d2-projects.github.io/d2-admin-start-kit](https://d2-projects.github.io/d2-admin-start-kit) | GitHub pages | [![](https://github.com/d2-projects/d2-admin-start-kit/workflows/Deploy%20Github/badge.svg)](https://github.com/d2-projects/d2-admin-start-kit/actions?query=workflow%3A%22Deploy+Github%22) |
| netlify | [d2-admin-start-kit.netlify.com](https://d2-admin-start-kit.netlify.com) | Netlify CDN | [![](https://api.netlify.com/api/v1/badges/08ff8c93-f0a8-497a-a081-440b31fb3aa4/deploy-status)](https://app.netlify.com/sites/d2-admin-start-kit/deploys) |
## 其它同步仓库
| 位置 | 链接 |
| --- | --- |
| 码云 | [https://gitee.com/fairyever/d2-admin-start-kit](https://gitee.com/fairyever/d2-admin-start-kit) |
| coding | [https://d2-projects.coding.net/p/d2-projects/d/d2-admin-start-kit/git](https://d2-projects.coding.net/p/d2-projects/d/d2-admin-start-kit/git) |
> 如果您在 github 仓库下载很慢,可以尝试使用我们的码云仓库克隆代码
\ No newline at end of file
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
],
// 允许两种编码引入方式共存,也就是 common 规范与 es6 规范的共存处理
sourceType: 'unambiguous'
}
<babeledit_project version="1.2">
<!--
BabelEdit project file
https://www.codeandweb.com/babeledit
This file contains meta data for all translations, but not the translation texts itself.
They are stored in framework-specific message files (.json / .vue / .yaml / .properties)
-->
<preset_collections/>
<framework>vue-json</framework>
<filename>d2-admin.babel</filename>
<source_root_dir></source_root_dir>
<folder_node>
<name></name>
<children>
<concept_node>
<name>_element</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>ja-JP</language>
<approved>false</approved>
</translation>
<translation>
<language>zh-CHS</language>
<approved>false</approved>
</translation>
<translation>
<language>zh-CHT</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>_name</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>ja-JP</language>
<approved>false</approved>
</translation>
<translation>
<language>zh-CHS</language>
<approved>false</approved>
</translation>
<translation>
<language>zh-CHT</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<folder_node>
<name>page</name>
<children>
<folder_node>
<name>demo</name>
<children>
<folder_node>
<name>playground</name>
<children>
<folder_node>
<name>locales</name>
<children>
<concept_node>
<name>text</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>ja-JP</language>
<approved>false</approved>
</translation>
<translation>
<language>zh-CHS</language>
<approved>false</approved>
</translation>
<translation>
<language>zh-CHT</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
</children>
</folder_node>
</children>
</folder_node>
</children>
</folder_node>
</children>
</folder_node>
<isTemplateProject>false</isTemplateProject>
<languages>
<language>
<code>en-US</code>
<source_id></source_id>
<source_file>src/locales/en.json</source_file>
</language>
<language>
<code>ja-JP</code>
<source_id></source_id>
<source_file>src/locales/ja.json</source_file>
</language>
<language>
<code>zh-CHS</code>
<source_id></source_id>
<source_file>src/locales/zh-chs.json</source_file>
</language>
<language>
<code>zh-CHT</code>
<source_id></source_id>
<source_file>src/locales/zh-cht.json</source_file>
</language>
</languages>
<translation_files>
<translation_file>
<file>src/locales/en.json</file>
</translation_file>
<translation_file>
<file>src/locales/ja.json</file>
</translation_file>
<translation_file>
<file>src/locales/zh-chs.json</file>
</translation_file>
<translation_file>
<file>src/locales/zh-cht.json</file>
</translation_file>
</translation_files>
<editor_configuration>
<save_empty_translations>true</save_empty_translations>
<copy_templates>
<copy_template>$t('%1')</copy_template>
<copy_template>{{ $t('%1') }}</copy_template>
<copy_template>this.$t('%1')</copy_template>
</copy_templates>
</editor_configuration>
<primary_language>zh-CHS</primary_language>
<configuration>
<indent>tab</indent>
<format>namespaced-json</format>
</configuration>
</babeledit_project>
module.exports = [
{ name: 'vue', library: 'Vue', js: 'https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js', css: '' },
{ name: 'vue-i18n', library: 'VueI18n', js: 'https://cdn.jsdelivr.net/npm/vue-i18n@8.15.1/dist/vue-i18n.js', css: '' },
{ name: 'vue-router', library: 'VueRouter', js: 'https://cdn.jsdelivr.net/npm/vue-router@3.1.3/dist/vue-router.js', css: '' },
{ name: 'vuex', library: 'Vuex', js: 'https://cdn.jsdelivr.net/npm/vuex@3.1.2/dist/vuex.js', css: '' },
{ name: 'axios', library: 'axios', js: 'https://cdn.jsdelivr.net/npm/axios@0.19.0/dist/axios.min.js', css: '' },
{ name: 'better-scroll', library: 'BScroll', js: 'https://cdn.jsdelivr.net/npm/better-scroll@1.15.2/dist/bscroll.min.js', css: '' },
{ name: 'element-ui', library: 'ELEMENT', js: 'https://cdn.jsdelivr.net/npm/element-ui@2.13.0/lib/index.js', css: 'https://cdn.jsdelivr.net/npm/element-ui@2.13.0/lib/theme-chalk/index.css' },
{ name: 'mockjs', library: 'Mock', js: 'https://cdn.jsdelivr.net/npm/mockjs@1.1.0/dist/mock.min.js', css: '' },
{ name: 'lodash', library: '_', js: 'https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js', css: '' },
{ name: 'ua-parser-js', library: 'UAParser', js: 'https://cdn.jsdelivr.net/npm/ua-parser-js@0.7.20/dist/ua-parser.min.js', css: '' },
{ name: 'js-cookie', library: 'Cookies', js: 'https://cdn.jsdelivr.net/npm/js-cookie@2.2.1/src/js.cookie.min.js', css: '' },
{ name: 'nprogress', library: 'NProgress', js: 'https://cdn.jsdelivr.net/npm/nprogress@0.2.0/nprogress.min.js', css: 'https://cdn.jsdelivr.net/npm/nprogress@0.2.0/nprogress.css' },
{ name: 'dayjs', library: 'dayjs', js: 'https://cdn.jsdelivr.net/npm/dayjs@1.8.17/dayjs.min.js', css: '' },
{ name: 'fuse.js', library: 'Fuse', js: 'https://cdn.jsdelivr.net/npm/fuse.js@3.4.6/dist/fuse.min.js', css: '' },
{ name: 'hotkeys-js', library: 'hotkeys', js: 'https://cdn.jsdelivr.net/npm/hotkeys-js@3.7.3/dist/hotkeys.js', css: '' },
{ name: 'qs', library: 'Qs', js: 'https://cdn.jsdelivr.net/npm/qs@6.9.1/dist/qs.js', css: '' },
{ name: 'lowdb', library: 'low', js: 'https://cdn.jsdelivr.net/npm/lowdb@1.0.0/dist/low.min.js', css: '' },
{ name: 'lowdb/adapters/LocalStorage', library: 'LocalStorage', js: 'https://cdn.jsdelivr.net/npm/lowdb@1.0.0/dist/LocalStorage.min.js', css: '' },
{ name: 'screenfull', library: 'screenfull', js: 'https://cdn.jsdelivr.net/npm/screenfull@5.0.0/dist/screenfull.min.js', css: '' },
{ name: 'sortablejs', library: 'Sortable', js: 'https://cdn.jsdelivr.net/npm/sortablejs@1.10.1/Sortable.min.js', css: '' }
]
module.exports = {
preset: '@vue/cli-plugin-unit-jest'
}
{
"compilerOptions": {
"target": "es2017",
"allowSyntheticDefaultImports": false,
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"exclude": ["node_modules", "dist"]
}
{
"name": "ybf_admin",
"version": "0.1.0",
"private": true,
"name": "d2-admin",
"version": "1.8.0",
"scripts": {
"serve": "vue-cli-service serve",
"serve": "vue-cli-service serve --open",
"start": "npm run serve",
"dev": "npm run serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
"build:nomock": "vue-cli-service build --mode nomock",
"build:preview": "NODE_OPTIONS=--max_old_space_size=4096 vue-cli-service build --mode preview",
"build:github": "NODE_OPTIONS=--max_old_space_size=4096 vue-cli-service build --mode github",
"build:netlify": "NODE_OPTIONS=--max_old_space_size=4096 vue-cli-service build --mode netlify",
"lint": "vue-cli-service lint --fix",
"test:unit": "vue-cli-service test:unit",
"i18n:report": "vue-cli-service i18n:report --src './src/**/*.?(js|vue)' --locales './src/locales/**/*.json'",
"analyz": "npm_config_report=true npm run build"
},
"dependencies": {
"core-js": "^3.4.4",
"axios": "^0.19.0",
"better-scroll": "^1.15.2",
"core-js": "^3.4.3",
"dayjs": "^1.8.17",
"element-ui": "^2.13.0",
"vue": "^2.6.10",
"flex.css": "^1.1.7",
"fuse.js": "^3.4.6",
"hotkeys-js": "^3.7.3",
"js-cookie": "^2.2.1",
"lodash": "^4.17.15",
"lowdb": "^1.0.0",
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
"qs": "^6.9.1",
"screenfull": "^5.0.0",
"sortablejs": "^1.10.1",
"ua-parser-js": "^0.7.20",
"vue": "^2.6.11",
"vue-i18n": "^8.15.1",
"vue-router": "^3.1.3",
"vuex": "^3.1.2"
},
"devDependencies": {
"@d2-projects/vue-filename-injector": "^1.1.0",
"@kazupon/vue-i18n-loader": "^0.4.1",
"@vue/cli-plugin-babel": "^4.1.0",
"@vue/cli-plugin-eslint": "^4.1.0",
"@vue/cli-plugin-router": "^4.1.0",
"@vue/cli-plugin-unit-jest": "^4.1.0",
"@vue/cli-plugin-vuex": "^4.1.0",
"@vue/cli-service": "^4.1.0",
"@vue/eslint-config-standard": "^4.0.0",
"@vue/test-utils": "1.0.0-beta.29",
"babel-eslint": "^10.0.3",
"compression-webpack-plugin": "^3.0.1",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.0.0",
"vue-template-compiler": "^2.6.10"
"sass": "^1.23.7",
"sass-loader": "^8.0.0",
"svg-sprite-loader": "^4.1.6",
"text-loader": "^0.0.1",
"vue-cli-plugin-i18n": "^0.6.0",
"vue-template-compiler": "^2.6.10",
"webpack-bundle-analyzer": "^3.6.0",
"webpack-theme-color-replacer": "^1.3.3"
}
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32" fill="white">
<path opacity=".25" d="M16 0 A16 16 0 0 0 16 32 A16 16 0 0 0 16 0 M16 4 A12 12 0 0 1 16 28 A12 12 0 0 1 16 4"/>
<path d="M16 0 A16 16 0 0 1 32 16 L28 16 A12 12 0 0 0 16 4z">
<animateTransform attributeName="transform" type="rotate" from="0 16 16" to="360 16 16" dur="0.8s" repeatCount="indefinite" />
</path>
</svg>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<html>
<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">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>亿百分后台管理</title>
<link rel="icon" href="<%= BASE_URL %>icon.ico">
<!-- 使用 CDN 加速的 CSS 文件,配置在 vue.config.js 下 -->
<% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.css) { %>
<link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="preload" as="style">
<link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet">
<% } %>
<!-- 使用 CDN 加速的 JS 文件,配置在 vue.config.js 下 -->
<% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %>
<link href="<%= htmlWebpackPlugin.options.cdn.js[i] %>" rel="preload" as="script">
<% } %>
<title><%= VUE_APP_TITLE %></title>
<style>
html, body, #app { height: 100%; margin: 0px; padding: 0px; width: 100%; }
.d2-home { background-color: #303133; height: 100%; display: flex; flex-direction: column; }
.d2-home__main { user-select: none; width: 100%; flex-grow: 1; display: flex; justify-content: center; align-items: center; flex-direction: column; }
.d2-home__footer { width: 100%; flex-grow: 0; text-align: center; padding: 1em 0; }
.d2-home__footer > a { font-size: 12px; color: #ABABAB; text-decoration: none; }
.d2-home__loading { height: 32px; width: 32px; margin-bottom: 20px; }
</style>
<script>
var _hmt = _hmt || [];
var hmid = "bc38887aa5588add05a38704342ad7e8";
(function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?" + hmid; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s);})();
</script>
</head>
<body>
<noscript>
<strong>We're sorry but ybf_admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
<strong>
Sorry, D2Admin will not work properly without JavaScript support. Enable JavaScript for browsers and continue.
</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
<div id="app">
<div class="d2-home">
<div class="d2-home__main">
<img
class="d2-home__loading"
src="./image/loading/loading-spin.svg"
alt="loading">
</div>
<div class="d2-home__footer">
<a
href="https://github.com/d2-projects/d2-admin"
target="_blank">
https://github.com/d2-projects/d2-admin
</a>
</div>
</div>
</div>
<!-- 使用 CDN 加速的 JS 文件,配置在 vue.config.js 下 -->
<% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %>
<script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
<% } %>
</body>
</html>
<template>
<div id="app">
<div id="nav">
</div>
<router-view/>
</div>
</template>
<style>
<script>
import util from '@/libs/util'
export default {
name: 'app',
watch: {
'$i18n.locale': 'i18nHandle'
},
created () {
this.i18nHandle(this.$i18n.locale)
},
methods: {
i18nHandle (val, oldVal) {
util.cookies.set('lang', val)
document.querySelector('html').setAttribute('lang', val)
}
}
}
</script>
<style lang="scss">
@import '~@/assets/style/public-class.scss';
</style>
import request from '@/plugin/axios'
export function AccountLogin (data) {
return request({
url: '/login',
method: 'post',
data
})
}
// 过渡动画 横向渐变
.fade-transverse-leave-active,
.fade-transverse-enter-active {
transition: all .5s;
}
.fade-transverse-enter {
opacity: 0;
transform: translateX(-30px);
}
.fade-transverse-leave-to {
opacity: 0;
transform: translateX(30px);
}
// 过渡动画 缩放渐变
.fade-scale-leave-active,
.fade-scale-enter-active {
transition: all .3s;
}
.fade-scale-enter {
opacity: 0;
transform: scale(1.2);
}
.fade-scale-leave-to {
opacity: 0;
transform: scale(0.8);
}
// 优化显示
html, body {
margin: 0px;
height: 100%;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
#app {
@extend %full;
a {
text-decoration: none;
}
}
}
\ No newline at end of file
// element 样式补丁
.el-card {
&.is-always-shadow {
box-shadow: 0 0 8px 0 rgba(232,237,250,.6), 0 2px 4px 0 rgba(232,237,250,.5);
}
&.is-hover-shadow {
&:hover {
box-shadow: 0 0 8px 0 rgba(232,237,250,.6), 0 2px 4px 0 rgba(232,237,250,.5);
}
}
}
.el-menu--horizontal {
border-bottom: none !important;
}
.el-tabs__item:focus.is-active.is-focus:not(:active) {
box-shadow: none !important;
}
\ No newline at end of file
#nprogress {
.bar {
background: $color-primary !important;
}
.peg {
box-shadow: 0 0 10px $color-primary, 0 0 5px $color-primary !important;
}
}
\ No newline at end of file
@import 'public';
// 补丁 base
@import '~@/assets/style/fixed/base.scss';
// 补丁 element
@import '~@/assets/style/fixed/element.scss';
// 动画
@import '~@/assets/style/animate/vue-transition.scss';
// 在这里写公用的class
// 注意 这个文件里只写class
// mixin等内容请在 public.scss 里书写
// 文字相关
.#{$prefix}-text-center {
text-align: center;
}
// 浮动相关
.#{$prefix}-fl {
float: left;
}
.#{$prefix}-fr {
float: right;
}
// 边距相关
$sizes: (0, 5, 10, 15, 20);
@for $index from 1 to 6 {
.#{$prefix}-m-#{nth($sizes, $index)} { margin: #{nth($sizes, $index)}px !important; }
.#{$prefix}-mt-#{nth($sizes, $index)} { margin-top: #{nth($sizes, $index)}px !important; }
.#{$prefix}-mr-#{nth($sizes, $index)} { margin-right: #{nth($sizes, $index)}px !important; }
.#{$prefix}-mb-#{nth($sizes, $index)} { margin-bottom: #{nth($sizes, $index)}px !important; }
.#{$prefix}-ml-#{nth($sizes, $index)} { margin-left: #{nth($sizes, $index)}px !important; }
.#{$prefix}-p-#{nth($sizes, $index)} { padding: #{nth($sizes, $index)}px !important; }
.#{$prefix}-pt-#{nth($sizes, $index)} { padding-top: #{nth($sizes, $index)}px !important; }
.#{$prefix}-pr-#{nth($sizes, $index)} { padding-right: #{nth($sizes, $index)}px !important; }
.#{$prefix}-pb-#{nth($sizes, $index)} { padding-bottom: #{nth($sizes, $index)}px !important; }
.#{$prefix}-pl-#{nth($sizes, $index)} { padding-left: #{nth($sizes, $index)}px !important; }
}
// 快速使用
.#{$prefix}-m { margin: 20px !important; }
.#{$prefix}-mt { margin-top: 20px !important; }
.#{$prefix}-mr { margin-right: 20px !important; }
.#{$prefix}-mb { margin-bottom: 20px !important; }
.#{$prefix}-ml { margin-left: 20px !important; }
.#{$prefix}-p { padding: 20px !important; }
.#{$prefix}-pt { padding-top: 20px !important; }
.#{$prefix}-pr { padding-right: 20px !important; }
.#{$prefix}-pb { padding-bottom: 20px !important; }
.#{$prefix}-pl { padding-left: 20px !important; }
@import '~@/assets/style/unit/color.scss';
// 工具类名统一前缀
$prefix: d2;
// 禁止用户选中 鼠标变为手形
%unable-select {
user-select: none;
cursor: pointer;
}
// 填满父元素
// 组要父元素 position: relative | absolute;
%full {
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
}
// flex 垂直水平居中
%flex-center-row {
display: flex;
justify-content: center;
align-items: center;
flex-direction: row;
}
%flex-center-col {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
// 将元素模拟成卡片外观
%card {
border: 1px solid #dddee1;
border-color: #e9eaec;
background: #fff;
border-radius: 4px;
font-size: 14px;
position: relative;
}
\ No newline at end of file
@import './setting.scss';
@import '../theme.scss';
// 主题名称
$theme-name: 'd2';
// 主题背景颜色
$theme-bg-color: #ebf1f6;
// 主题背景图片遮罩
$theme-bg-mask: rgba(#000, 0);
// container组件
$theme-container-background-color: rgba(#FFF, 1);
$theme-container-header-footer-background-color: #FFF;
$theme-container-border-inner: 1px solid #cfd7e5;
$theme-container-border-outer: 1px solid #cfd7e5;
$theme-multiple-page-control-color: $color-text-normal;
$theme-multiple-page-control-color-active: #2f74ff;
$theme-multiple-page-control-nav-prev-color: #cfd7e5;
$theme-multiple-page-control-nav-next-color: #cfd7e5;
$theme-multiple-page-control-border-color: #cfd7e5;
$theme-multiple-page-control-border-color-active: #FFF;
$theme-multiple-page-control-background-color: rgba(#000, .03);
$theme-multiple-page-control-background-color-active: #FFF;
// 顶栏和侧边栏中展开的菜单 hover 状态下
$theme-menu-item-color-hover: #293849;
$theme-menu-item-background-color-hover: #ecf5ff;
// 顶栏上的文字颜色
// $theme-header-item-color: $color-text-normal;
$theme-header-item-color: #E8E9FF;
// $theme-header-item-background-color: transparent;
$theme-header-item-background-color: #4E59C7;
// 顶栏上的项目在 hover 时
$theme-header-item-color-hover: #FFFFFF;
$theme-header-item-background-color-hover: rgba(#2B36A1, .5);
// 顶栏上的项目在 focus 时
$theme-header-item-color-focus: #FFFFFF;
$theme-header-item-background-color-focus: rgba(#2B36A1, .5);
// 顶栏上的项目在 active 时
$theme-header-item-color-active: #FFFFFF;
$theme-header-item-background-color-active: rgba(#2B36A1, .5);
// 侧边栏上的文字颜色
$theme-aside-item-color: $color-text-normal;
$theme-aside-item-background-color: transparent;
// 侧边栏上的项目在 hover 时
$theme-aside-item-color-hover: #2f74ff;
$theme-aside-item-background-color-hover: rgba(#FFF, .5);
// 侧边栏上的项目在 focus 时
$theme-aside-item-color-focus: #2f74ff;
$theme-aside-item-background-color-focus: rgba(#FFF, .5);
// 侧边栏上的项目在 active 时
$theme-aside-item-color-active: #2f74ff;
$theme-aside-item-background-color-active: rgba(#FFF, .5);
// 侧边栏菜单为空的时候显示的元素
$theme-aside-menu-empty-icon-color: $color-text-normal;
$theme-aside-menu-empty-text-color: $color-text-normal;
$theme-aside-menu-empty-background-color: rgba(#000, .03);
$theme-aside-menu-empty-icon-color-hover: $color-text-main;
$theme-aside-menu-empty-text-color-hover: $color-text-main;
$theme-aside-menu-empty-background-color-hover: rgba(#000, .05);
\ No newline at end of file
@import './setting.scss';
@import '../theme.scss';
// 主题名称
$theme-name: 'line';
// 主题背景颜色
$theme-bg-color: #f8f8f9;
// 主题背景图片遮罩
$theme-bg-mask: rgba(#000, 0);
// container组件
$theme-container-background-color: rgba(#FFF, .8);
$theme-container-header-footer-background-color: #FFF;
$theme-container-border-inner: 1px solid $color-border-2;
$theme-container-border-outer: 1px solid #cfd7e5;
$theme-multiple-page-control-color: #FFF;
$theme-multiple-page-control-color-active: $color-text-normal;
$theme-multiple-page-control-nav-prev-color: #cfd7e5;
$theme-multiple-page-control-nav-next-color: #cfd7e5;
$theme-multiple-page-control-border-color: #cfd7e5;
$theme-multiple-page-control-border-color-active: #FFF;
$theme-multiple-page-control-background-color: #cfd7e5;
$theme-multiple-page-control-background-color-active: #FFF;
// 顶栏和侧边栏中展开的菜单 hover 状态下
$theme-menu-item-color-hover: #293849;
$theme-menu-item-background-color-hover: #EFEFEF;
// 顶栏上的文字颜色
$theme-header-item-color: $color-text-normal;
$theme-header-item-background-color: transparent;
// 顶栏上的项目在 hover 时
$theme-header-item-color-hover: $color-text-main;
$theme-header-item-background-color-hover: rgba(#000, .02);
// 顶栏上的项目在 focus 时
$theme-header-item-color-focus: $color-text-main;
$theme-header-item-background-color-focus: rgba(#000, .02);
// 顶栏上的项目在 active 时
$theme-header-item-color-active: $color-text-main;
$theme-header-item-background-color-active: rgba(#000, .03);
// 侧边栏上的文字颜色
$theme-aside-item-color: $color-text-normal;
$theme-aside-item-background-color: transparent;
// 侧边栏上的项目在 hover 时
$theme-aside-item-color-hover: $color-text-main;
$theme-aside-item-background-color-hover: rgba(#000, .02);
// 侧边栏上的项目在 focus 时
$theme-aside-item-color-focus: $color-text-main;
$theme-aside-item-background-color-focus: rgba(#000, .02);
// 侧边栏上的项目在 active 时
$theme-aside-item-color-active: $color-text-main;
$theme-aside-item-background-color-active: rgba(#000, .03);
// 侧边栏菜单为空的时候显示的元素
$theme-aside-menu-empty-icon-color: $color-text-normal;
$theme-aside-menu-empty-text-color: $color-text-normal;
$theme-aside-menu-empty-background-color: rgba(#000, .03);
$theme-aside-menu-empty-icon-color-hover: $color-text-main;
$theme-aside-menu-empty-text-color-hover: $color-text-main;
$theme-aside-menu-empty-background-color-hover: rgba(#000, .05);
\ No newline at end of file
@import '~@/assets/style/theme/theme-base.scss';
@import '~@/assets/style/theme/d2/index.scss';
@import '~@/assets/style/theme/line/index.scss';
@import '~@/assets/style/theme/star/index.scss';
@import '~@/assets/style/theme/tomorrow-night-blue/index.scss';
@import '~@/assets/style/theme/violet/index.scss';
\ No newline at end of file
@import './setting.scss';
@import '../theme.scss';
// 主题名称
$theme-name: 'star';
// 主题背景颜色
$theme-bg-color: #EFF4F8;
// 主题背景图片遮罩
$theme-bg-mask: rgba(#000, .3);
// container组件
$theme-container-background-color: rgba(#FFF, .9);
$theme-container-header-footer-background-color: #FFF;
$theme-container-border-inner: 1px solid $color-border-1;
$theme-container-border-outer: 1px solid #114450;
$theme-multiple-page-control-color: #FFF;
$theme-multiple-page-control-color-active: $color-text-normal;
$theme-multiple-page-control-nav-prev-color: #FFF;
$theme-multiple-page-control-nav-next-color: #FFF;
$theme-multiple-page-control-border-color: #114450;
$theme-multiple-page-control-border-color-active: #FFF;
$theme-multiple-page-control-background-color: rgba(#FFF, .5);
$theme-multiple-page-control-background-color-active: #FFF;
// 顶栏和侧边栏中展开的菜单 hover 状态下
$theme-menu-item-color-hover: #293849;
$theme-menu-item-background-color-hover: #ecf5ff;
// 顶栏上的文字颜色
$theme-header-item-color: #FFF;
$theme-header-item-background-color: transparent;
// 顶栏上的项目在 hover 时
$theme-header-item-color-hover: #FFF;
$theme-header-item-background-color-hover: rgba(#000, .2);
// 顶栏上的项目在 focus 时
$theme-header-item-color-focus: #FFF;
$theme-header-item-background-color-focus: rgba(#000, .2);
// 顶栏上的项目在 active 时
$theme-header-item-color-active: #FFF;
$theme-header-item-background-color-active: rgba(#000, .3);
// 侧边栏上的文字颜色
$theme-aside-item-color: #FFF;
$theme-aside-item-background-color: transparent;
// 侧边栏上的项目在 hover 时
$theme-aside-item-color-hover: #FFF;
$theme-aside-item-background-color-hover: rgba(#000, .2);
// 侧边栏上的项目在 focus 时
$theme-aside-item-color-focus: #FFF;
$theme-aside-item-background-color-focus: rgba(#000, .2);
// 侧边栏上的项目在 active 时
$theme-aside-item-color-active: #FFF;
$theme-aside-item-background-color-active: rgba(#000, .3);
// 侧边栏菜单为空的时候显示的元素
$theme-aside-menu-empty-icon-color: #FFF;
$theme-aside-menu-empty-text-color: #FFF;
$theme-aside-menu-empty-background-color: rgba(#FFF, .2);
$theme-aside-menu-empty-icon-color-hover: #FFF;
$theme-aside-menu-empty-text-color-hover: #FFF;
$theme-aside-menu-empty-background-color-hover: rgba(#FFF, .3);
\ No newline at end of file
// 减小弹出菜单的项目高度
.el-menu--popup {
.el-menu-item {
height: 36px;
line-height: 36px;
}
.el-submenu__title {
height: 36px;
line-height: 36px;
}
}
// 整体框架结构
.d2-layout-header-aside-group {
height: 100%;
width: 100%;
min-width: 900px;
background-size: cover;
background-position: center;
overflow: hidden;
position: relative;
// 背景上面的半透明遮罩
.d2-layout-header-aside-mask {
@extend %full;
}
// 内容层
.d2-layout-header-aside-content {
@extend %full;
.d2-theme-header {
height: 60px;
.d2-theme-header-menu {
overflow: hidden;
&.is-scrollable {
position: relative;
padding: 0 20px;
.d2-theme-header-menu__prev, .d2-theme-header-menu__next {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
}
.d2-theme-header-menu__content {
overflow: hidden;
.d2-theme-header-menu__scroll {
white-space: nowrap;
position: relative;
-webkit-transition: -webkit-transform .3s;
transition: -webkit-transform .3s;
transition: transform .3s;
transition: transform .3s, -webkit-transform .3s;
transition: transform .3s,-webkit-transform .3s;
float: left;
}
}
.d2-theme-header-menu__prev, .d2-theme-header-menu__next {
height: 60px;
position: absolute;
top: 0;
font-size: 20px;
cursor: pointer;
display: none;
}
.d2-theme-header-menu__prev {
left: 0;
border-top-left-radius: 2px;
border-bottom-left-radius: 2px;
}
.d2-theme-header-menu__next {
right: 0;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
}
}
}
.d2-theme-container {
.d2-theme-container-aside {
transition: width .3s;
position: relative;
.d2-layout-header-aside-menu-side {
@extend %full;
overflow: hidden;
}
}
.d2-theme-container-main {
padding: 0px;
position: relative;
overflow: hidden;
.d2-theme-container-main-layer {
position: absolute;
top: 0px;
bottom: 0px;
// left: 0px;
// Z-Style
left: 20px;
right: 0px;
}
.d2-theme-container-main-body {
position: relative;
}
}
}
}
}
// 主题公用
.d2-layout-header-aside-group {
&.grayMode {
-webkit-filter: grayscale(100%);
-moz-filter: grayscale(100%);
-ms-filter: grayscale(100%);
-o-filter: grayscale(100%);
filter: grayscale(100%);
filter: gray;
}
// 主体
.d2-layout-header-aside-content {
// [布局] 顶栏
.d2-theme-header {
// logo区域
.logo-group {
transition: width .3s;
float: left;
text-align: center;
img {
height: 60px;
}
}
// 折叠侧边栏切换按钮
.toggle-aside-btn {
float: left;
height: 60px;
width: 60px;
display: flex;
justify-content: center;
align-items: center;
@extend %unable-select;
i {
font-size: 20px;
margin-top: 4px;
}
}
// [菜单] 顶栏
.el-menu {
float: left;
border-bottom: none;
background-color: transparent;
%header-menu-item {
@extend %unable-select;
i.fa {
font-size: 16px;
margin-right: 4px;
}
}
.el-menu-item {
@extend %header-menu-item;
border-bottom: none;
}
.el-submenu {
@extend %header-menu-item;
.el-submenu__title {
border-bottom: none;
}
}
}
// 顶栏右侧的按钮
.d2-header-right {
float: right;
height: 60px;
display: flex;
align-items: center;
.btn-text {
padding: 14px 12px;
border-radius: 4px;
margin: 0px !important;
&.el-color-picker.el-color-picker--mini {
padding: 9px 6px;
}
}
.el-dropdown {
@extend %unable-select;
}
}
}
// [布局] 顶栏下面
.d2-theme-container {
// 侧边栏
.d2-theme-container-aside {
%d2-theme-container-aside-menu-icon {
width: 20px;
text-align: center;
font-size: 16px;
}
// [菜单] 正常状态
.el-menu {
@extend %unable-select;
background-color: transparent;
border-right: none;
.el-menu-item {
i {
@extend %d2-theme-container-aside-menu-icon;
}
}
}
.el-submenu {
@extend %unable-select;
.el-submenu__title {
i {
@extend %d2-theme-container-aside-menu-icon;
}
.el-submenu__icon-arrow {
margin-top: -10px;
}
}
}
// 菜单为空的时候显示的信息
.d2-layout-header-aside-menu-empty {
height: 160px;
margin: 10px;
margin-top: 0px;
border-radius: 4px;
@extend %unable-select;
i {
font-size: 30px;
margin-bottom: 10px;
}
span {
font-size: 14px;
}
}
// [菜单] 折叠状态
.el-menu--collapse {
background-color: transparent;
.el-submenu__title {
text-align: center;
}
}
}
// 右下 主体
.d2-theme-container-main {
// 主体部分分为多页面控制器 和主体
.d2-theme-container-main-header {
height: 41px;
// 多页面控制器
.d2-multiple-page-control-group {
padding-right: 20px;
.d2-multiple-page-control-content {
overflow: auto;
position: relative;
.d2-multiple-page-control-content-inner {
.d2-multiple-page-control {
.el-tabs__header.is-top {
margin: 0px;
}
.el-tabs__nav {
overflow: hidden;
}
}
}
}
.d2-multiple-page-control-btn {
position: relative;
bottom: -1px;
.el-dropdown {
.el-button-group {
.el-button:first-child {
border-bottom-left-radius: 0px;
}
.el-button:last-child {
border-bottom-right-radius: 0px;
}
}
}
}
}
}
// 主体
.d2-theme-container-main-body {
// 布局组件
.container-component {
@extend %full;
overflow: hidden;
// 填充式布局组件
.d2-container-full {
position: absolute;
top: 0px;
right: 20px;
bottom: 0px;
left: 0px;
display: flex;
flex-direction: column;
overflow: hidden;
.d2-container-full__header {
padding: 20px;
}
.d2-container-full__body {
flex-grow: 1;
height: 100%;
padding: 20px 20px;
overflow: auto;
position: relative;
}
.d2-container-full__footer {
padding: 20px;
}
}
// 填充式布局组件 - 滚动优化
.d2-container-full-bs {
position: absolute;
top: 0px;
right: 20px;
bottom: 0px;
left: 0px;
display: flex;
flex-direction: column;
overflow: hidden;
.d2-container-full-bs__header {
padding: 20px;
}
.d2-container-full-bs__body {
flex-grow: 1;
overflow: hidden;
position: relative;
.d2-container-full-bs__body-wrapper-inner {
padding: 20px;
position: relative;
}
}
.d2-container-full-bs__footer {
padding: 20px;
}
}
// 隐形布局组件
.d2-container-ghost {
position: absolute;
top: 0px;
right: 20px;
bottom: 0px;
left: 0px;
display: flex;
flex-direction: column;
overflow: hidden;
.d2-container-ghost__header {
padding: 20px;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
.d2-container-ghost__body {
flex-grow: 1;
overflow: auto;
position: relative;
}
.d2-container-ghost__footer {
padding: 20px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
}
// 隐形布局组件 - 滚动优化
.d2-container-ghost-bs {
position: absolute;
top: 0px;
right: 20px;
bottom: 0px;
left: 0px;
display: flex;
flex-direction: column;
overflow: hidden;
.d2-container-ghost-bs__header {
padding: 20px;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
.d2-container-ghost-bs__body {
flex-grow: 1;
overflow: hidden;
position: relative;
}
.d2-container-ghost-bs__footer {
padding: 20px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
}
// 卡片式布局组件
.d2-container-card {
position: absolute;
top: 0px;
right: 20px;
bottom: 0px;
left: 0px;
display: flex;
flex-direction: column;
overflow: hidden;
.d2-container-card__header {
padding: 20px;
}
.d2-container-card__body {
flex-grow: 1;
overflow: auto;
.d2-container-card__body-card {
position: relative;
margin-bottom: 20px;
padding: 20px;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
}
.d2-container-card__footer {
padding: 20px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
}
// 卡片式布局组件 - 滚动优化
.d2-container-card-bs {
position: absolute;
top: 0px;
right: 20px;
bottom: 0px;
left: 0px;
display: flex;
flex-direction: column;
overflow: hidden;
.d2-container-card-bs__header {
padding: 20px;
}
.d2-container-card-bs__body {
position: relative;
flex-grow: 1;
overflow: hidden;
.d2-container-card-bs__body-wrapper-inner {
padding-bottom: 20px;
}
.d2-container-card-bs__body-card {
position: relative;
padding: 20px;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
}
.d2-container-card-bs__footer {
padding: 20px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
}
}
}
}
}
}
}
// 每个主题特有的设置
.theme-#{$theme-name} {
.el-card {
&.d2-card {
border: $theme-container-border-outer;
.el-card__header {
border-bottom: $theme-container-border-outer;
}
}
}
// 背景图片和遮罩
.d2-layout-header-aside-group {
background-color: $theme-bg-color;
.d2-layout-header-aside-mask {
background: $theme-bg-mask;
}
}
// 菜单项目
@mixin theme-menu-hover-style {
color: $theme-menu-item-color-hover;
i.fa {
color: $theme-menu-item-color-hover;
}
background: $theme-menu-item-background-color-hover;
}
%el-menu-icon {
i {
display: inline-block;
width: 14px;
text-align: center;
margin-right: 5px;
}
svg {
margin: 0px;
height: 14px;
width: 14px;
margin-right: 5px;
}
}
.el-submenu__title {
@extend %unable-select;
@extend %el-menu-icon;
}
.el-menu-item {
@extend %unable-select;
@extend %el-menu-icon;
}
.el-submenu__title:hover {
@include theme-menu-hover-style;
}
.el-menu-item:hover {
@include theme-menu-hover-style;
}
.el-menu--horizontal .el-menu-item:not(.is-disabled):hover {
@include theme-menu-hover-style;
}
.el-menu--horizontal .el-menu .el-submenu__title:hover {
@include theme-menu-hover-style;
}
// 顶栏
.d2-theme-header {
// 顶栏菜单空间不足时显示的滚动控件
.d2-theme-header-menu {
.d2-theme-header-menu__prev, .d2-theme-header-menu__next {
color: $theme-header-item-color;
background: $theme-header-item-background-color;
&:hover {
color: $theme-header-item-color-hover;
background: $theme-header-item-background-color-hover;
}
}
}
// 切换按钮
.toggle-aside-btn {
i {
color: $theme-header-item-color;
background: $theme-header-item-background-color;
&:hover {
color: $theme-header-item-color-hover;
}
}
}
// 顶栏菜单
.el-menu {
.el-menu-item {
transition: border-top-color 0s;
color: $theme-header-item-color;
background: $theme-header-item-background-color;
i.fa { color: inherit; }
&:hover {
color: $theme-header-item-color-hover;
background: $theme-header-item-background-color-hover;
i.fa { color: inherit; }
}
&:focus {
color: $theme-header-item-color-focus;
background: $theme-header-item-background-color-focus;
i.fa { color: inherit; }
}
&.is-active {
color: $theme-header-item-color-active;
background: $theme-header-item-background-color-active;
i.fa { color: inherit; }
}
}
.el-submenu {
&.is-active {
.el-submenu__title {
color: $theme-header-item-color-active;
background: $theme-header-item-background-color-active;
i.fa { color: inherit; }
}
}
.el-submenu__title {
transition: border-top-color 0s;
color: $theme-header-item-color;
background: $theme-header-item-background-color;
i.fa { color: inherit; }
.el-submenu__icon-arrow {
color: $theme-header-item-color;
}
&:hover {
color: $theme-header-item-color-hover;
background: $theme-header-item-background-color-hover;
i.fa { color: inherit; }
.el-submenu__icon-arrow {
color: $theme-header-item-color-hover;
}
}
&:focus {
color: $theme-header-item-color-focus;
background: $theme-header-item-background-color-focus;
i.fa { color: inherit; }
.el-submenu__icon-arrow {
color: $theme-header-item-color-focus;
}
}
}
}
}
// 顶栏右侧
.d2-header-right {
.btn-text {
color: $theme-header-item-color;
&.can-hover {
&:hover {
color: $theme-header-item-color-hover;
background: $theme-header-item-background-color-hover;
}
}
}
}
}
// [布局] 顶栏下面
.d2-theme-container {
// 侧边栏
.d2-theme-container-aside {
// 菜单为空的时候显示的信息
.d2-layout-header-aside-menu-empty {
background: $theme-aside-menu-empty-background-color;
i {
color: $theme-aside-menu-empty-icon-color;
}
span {
color: $theme-aside-menu-empty-text-color;
}
&:hover {
background: $theme-aside-menu-empty-background-color-hover;
i {
color: $theme-aside-menu-empty-icon-color-hover;
}
span {
color: $theme-aside-menu-empty-text-color-hover;
}
}
}
// [菜单] 正常状态
.el-menu {
.el-menu-item {
color: $theme-aside-item-color;
background: $theme-aside-item-background-color;
i {
color: $theme-aside-item-color;
}
&:hover {
color: $theme-aside-item-color-hover;
fill: $theme-aside-item-color-hover;
background: $theme-aside-item-background-color-hover;
i {
color: $theme-aside-item-color-hover;
}
}
&:focus {
color: $theme-aside-item-color-focus;
fill: $theme-aside-item-color-focus;
background: $theme-aside-item-background-color-focus;
i {
color: $theme-aside-item-color-focus;
}
}
&.is-active {
color: $theme-aside-item-color-active;
fill: $theme-aside-item-color-active;
background: $theme-aside-item-background-color-active;
i {
color: $theme-aside-item-color-active;
}
}
}
}
.el-submenu {
.el-submenu__title {
color: $theme-aside-item-color;
background: $theme-aside-item-background-color;
i {
color: $theme-aside-item-color;
}
.el-submenu__icon-arrow {
color: $theme-aside-item-color;
}
&:hover {
color: $theme-aside-item-color-hover;
background: $theme-aside-item-background-color-hover;
i {
color: $theme-aside-item-color-hover;
}
.el-submenu__icon-arrow {
color: $theme-aside-item-color-hover;
}
}
}
}
}
.d2-theme-container-main {
// 主体部分分为多页面控制器 和主体
.d2-theme-container-main-header {
// 多页面控制器
.d2-multiple-page-control {
.el-tabs__header.is-top {
border-bottom-color: $theme-multiple-page-control-border-color;
}
.el-tabs__nav {
border-color: $theme-multiple-page-control-border-color;
.el-tabs__item {
@extend %unable-select;
color: $theme-multiple-page-control-color;
background-color: $theme-multiple-page-control-background-color;
border-left-color: $theme-multiple-page-control-border-color;
&:first-child {
border-left: none;
&:hover {
padding: 0px 20px;
}
.el-icon-close {
display: none;
}
}
}
.el-tabs__item.is-active {
color: $theme-multiple-page-control-color-active;
background-color: $theme-multiple-page-control-background-color-active;
border-bottom-color: $theme-multiple-page-control-border-color-active;
}
}
%el-tabs__nav {
font-size: 20px;
}
.el-tabs__nav-prev {
@extend %el-tabs__nav;
color: $theme-multiple-page-control-nav-prev-color;
}
.el-tabs__nav-next {
@extend %el-tabs__nav;
color: $theme-multiple-page-control-nav-next-color;
}
}
// 多页控制器的关闭控制
.d2-multiple-page-control-btn {
.el-dropdown {
.el-button-group {
.el-button {
border-color: $theme-multiple-page-control-border-color;
}
}
}
}
}
// 主体
.d2-theme-container-main-body {
// 布局组件
.container-component {
// [组件]
// d2-container-full 填充型
.d2-container-full {
border: $theme-container-border-outer;
border-top: none;
border-bottom: none;
.d2-container-full__header {
border-bottom: $theme-container-border-inner;
background: $theme-container-header-footer-background-color;
}
.d2-container-full__body {
background: $theme-container-background-color;
}
.d2-container-full__footer {
border-top: $theme-container-border-inner;
background: $theme-container-header-footer-background-color;
}
}
// [组件]
// d2-container-full-bs 填充型 滚动优化
.d2-container-full-bs {
border: $theme-container-border-outer;
border-top: none;
border-bottom: none;
.d2-container-full-bs__header {
border-bottom: $theme-container-border-inner;
background: $theme-container-header-footer-background-color;
}
.d2-container-full-bs__body {
background: $theme-container-background-color;
}
.d2-container-full-bs__footer {
border-top: $theme-container-border-inner;
background: $theme-container-header-footer-background-color;
}
}
// [组件]
// d2-container-ghost 隐形布局组件
.d2-container-ghost {
.d2-container-ghost__header {
border-bottom: $theme-container-border-outer;
border-left: $theme-container-border-outer;
border-right: $theme-container-border-outer;
background: $theme-container-header-footer-background-color;
}
.d2-container-ghost__footer {
border-top: $theme-container-border-outer;
border-left: $theme-container-border-outer;
border-right: $theme-container-border-outer;
background: $theme-container-header-footer-background-color;
}
}
// [组件]
// d2-container-ghost-bs 隐形布局组件 滚动优化
.d2-container-ghost-bs {
.d2-container-ghost-bs__header {
border-bottom: $theme-container-border-outer;
border-left: $theme-container-border-outer;
border-right: $theme-container-border-outer;
background: $theme-container-header-footer-background-color;
}
.d2-container-ghost-bs__footer {
border-top: $theme-container-border-outer;
border-left: $theme-container-border-outer;
border-right: $theme-container-border-outer;
background: $theme-container-header-footer-background-color;
}
}
// [组件]
// d2-container-card 卡片型
.d2-container-card {
.d2-container-card__header {
border-bottom: $theme-container-border-inner;
border-left: $theme-container-border-outer;
border-right: $theme-container-border-outer;
background: $theme-container-header-footer-background-color;
}
.d2-container-card__body {
.d2-container-card__body-card {
background: $theme-container-background-color;
border-left: $theme-container-border-outer;
border-right: $theme-container-border-outer;
border-bottom: $theme-container-border-outer;
}
}
.d2-container-card__footer {
border-top: $theme-container-border-outer;
border-left: $theme-container-border-outer;
border-right: $theme-container-border-outer;
background: $theme-container-header-footer-background-color;
}
}
// [组件]
// d2-container-card-bs 卡片型 滚动优化
.d2-container-card-bs {
.d2-container-card-bs__header {
border-bottom: $theme-container-border-inner;
border-left: $theme-container-border-outer;
border-right: $theme-container-border-outer;
background: $theme-container-header-footer-background-color;
}
.d2-container-card-bs__body {
.d2-container-card-bs__body-card {
background: $theme-container-background-color;
border-left: $theme-container-border-outer;
border-right: $theme-container-border-outer;
border-bottom: $theme-container-border-outer;
}
}
.d2-container-card-bs__footer {
border-top: $theme-container-border-outer;
border-left: $theme-container-border-outer;
border-right: $theme-container-border-outer;
background: $theme-container-header-footer-background-color;
}
}
}
}
}
}
}
@import './setting.scss';
@import '../theme.scss';
// 主题名称
$theme-name: 'tomorrow-night-blue';
// 主题背景颜色
$theme-bg-color: #002253;
// 主题背景图片遮罩
$theme-bg-mask: rgba(#000, 0);
// container组件
$theme-container-background-color: rgba(#FFF, 1);
$theme-container-header-footer-background-color: #FFF;
$theme-container-border-inner: 1px solid $color-border-1;
$theme-container-border-outer: 1px solid #002253;
$theme-multiple-page-control-color: #FFF;
$theme-multiple-page-control-color-active: $color-text-normal;
$theme-multiple-page-control-nav-prev-color: #FFF;
$theme-multiple-page-control-nav-next-color: #FFF;
$theme-multiple-page-control-border-color: #002253;
$theme-multiple-page-control-border-color-active: #FFF;
$theme-multiple-page-control-background-color: rgba(#FFF, .2);
$theme-multiple-page-control-background-color-active: #FFF;
// 顶栏和侧边栏中展开的菜单 hover 状态下
$theme-menu-item-color-hover: #293849;
$theme-menu-item-background-color-hover: #ecf5ff;
// 顶栏上的文字颜色
$theme-header-item-color: #FF929A;
$theme-header-item-background-color: transparent;
// 顶栏上的项目在 hover 时
$theme-header-item-color-hover: #FFEBA4;
$theme-header-item-background-color-hover: rgba(#FFF, .05);
// 顶栏上的项目在 focus 时
$theme-header-item-color-focus: #FFB870;
$theme-header-item-background-color-focus: rgba(#FFF, .05);
// 顶栏上的项目在 active 时
$theme-header-item-color-active: #FFB870;
$theme-header-item-background-color-active: rgba(#FFF, .05);
// 侧边栏上的文字颜色
$theme-aside-item-color: #FF929A;
$theme-aside-item-background-color: transparent;
// 侧边栏上的项目在 hover 时
$theme-aside-item-color-hover: #FFEBA4;
$theme-aside-item-background-color-hover: rgba(#FFF, .05);
// 侧边栏上的项目在 focus 时
$theme-aside-item-color-focus: #FFB870;
$theme-aside-item-background-color-focus: rgba(#FFF, .05);
// 侧边栏上的项目在 active 时
$theme-aside-item-color-active: #FFB870;
$theme-aside-item-background-color-active: rgba(#FFF, .05);
// 侧边栏菜单为空的时候显示的元素
$theme-aside-menu-empty-icon-color: #FFB870;
$theme-aside-menu-empty-text-color: #FFB870;
$theme-aside-menu-empty-background-color: rgba(#FFF, .1);
$theme-aside-menu-empty-icon-color-hover: #FFEBA4;
$theme-aside-menu-empty-text-color-hover: #FFEBA4;
$theme-aside-menu-empty-background-color-hover: rgba(#FFF, .2);
\ No newline at end of file
@import './setting.scss';
@import '../theme.scss';
.theme-#{$theme-name} {
.d2-layout-header-aside-group {
background: #bc00e3;
background: linear-gradient(120deg, #bc00e3 0%, #4EFFFB 100%);
}
}
\ No newline at end of file
// 主题名称
$theme-name: 'violet';
// 主题背景颜色
$theme-bg-color: #000;
// 主题背景图片遮罩
$theme-bg-mask: rgba(#000, 0);
// container组件
$theme-container-background-color: #FFF;
$theme-container-header-footer-background-color: #FFF;
$theme-container-border-inner: 1px solid $color-border-2;
$theme-container-border-outer: 1px solid #8C40E2;
$theme-multiple-page-control-color: #FFF;
$theme-multiple-page-control-color-active: $color-text-normal;
$theme-multiple-page-control-nav-prev-color: #FFF;
$theme-multiple-page-control-nav-next-color: #FFF;
$theme-multiple-page-control-border-color: #8C40E2;
$theme-multiple-page-control-border-color-active: #FFF;
$theme-multiple-page-control-background-color: rgba(#FFF, .3);
$theme-multiple-page-control-background-color-active: #FFF;
// 顶栏和侧边栏中展开的菜单 hover 状态下
$theme-menu-item-color-hover: #293849;
$theme-menu-item-background-color-hover: #ecf5ff;
// 顶栏上的文字颜色
$theme-header-item-color: #FFF;
$theme-header-item-background-color: transparent;
// 顶栏上的项目在 hover 时
$theme-header-item-color-hover: #FFF;
$theme-header-item-background-color-hover: linear-gradient(-180deg, rgba(255,255,255,0.18) 0%, rgba(255,255,255,0.12) 100%);
// 顶栏上的项目在 focus 时
$theme-header-item-color-focus: #FFF;
$theme-header-item-background-color-focus: linear-gradient(-180deg, rgba(255,255,255,0.18) 0%, rgba(255,255,255,0.12) 100%);
// 顶栏上的项目在 active 时
$theme-header-item-color-active: #FFF;
$theme-header-item-background-color-active: linear-gradient(-180deg, rgba(255,255,255,0.18) 0%, rgba(255,255,255,0.12) 100%);
// 侧边栏上的文字颜色
$theme-aside-item-color: #FFF;
$theme-aside-item-background-color: transparent;
// 侧边栏上的项目在 hover 时
$theme-aside-item-color-hover: #FFF;
$theme-aside-item-background-color-hover: linear-gradient(90deg, rgba(255,255,255,0.28) 0%, rgba(255,255,255,0.00) 100%);
// 侧边栏上的项目在 focus 时
$theme-aside-item-color-focus: #FFF;
$theme-aside-item-background-color-focus: linear-gradient(90deg, rgba(255,255,255,0.28) 0%, rgba(255,255,255,0.00) 100%);
// 侧边栏上的项目在 active 时
$theme-aside-item-color-active: #FFF;
$theme-aside-item-background-color-active: linear-gradient(90deg, rgba(255,255,255,0.28) 0%, rgba(255,255,255,0.00) 100%);
// 侧边栏菜单为空的时候显示的元素
$theme-aside-menu-empty-icon-color: #FFF;
$theme-aside-menu-empty-text-color: #FFF;
$theme-aside-menu-empty-background-color: rgba(#000, .1);
$theme-aside-menu-empty-icon-color-hover: #FFF;
$theme-aside-menu-empty-text-color-hover: #FFF;
$theme-aside-menu-empty-background-color-hover: rgba(#000, .15);
\ No newline at end of file
// 主色
$color-primary: #409EFF;
// 辅助色
$color-info: #909399;
$color-success: #67C23A;
$color-warning: #E6A23C;
$color-danger: #F56C6C;
// 文字
$color-text-main: #303133;
$color-text-normal: #606266;
$color-text-sub: #909399;
$color-text-placehoder: #C0C4CC;
// 边框
$color-border-1: #DCDFE6;
$color-border-2: #E4E7ED;
$color-border-3: #EBEEF5;
$color-border-4: #F2F6FC;
// 背景
$color-bg: #f8f8f9;
\ No newline at end of file
<svg viewBox="0 0 88 84" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 49.3 (51167) - http://www.bohemiancoding.com/sketch -->
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="page" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Tablet" transform="translate(-1077.000000, -135.000000)">
<g id="Group" transform="translate(1077.000000, 132.000000)">
<path d="M0.74,85.8 L0.74,71.44 L3.72,71.44 C5.7600102,71.44 7.2566619,71.5899985 8.21,71.89 C9.1633381,72.1900015 9.9866632,72.6633301 10.68,73.31 C11.3733368,73.9566699 11.9066648,74.746662 12.28,75.68 C12.6533352,76.613338 12.84,77.7033271 12.84,78.95 C12.84,80.1966729 12.5500029,81.3699945 11.97,82.47 C11.3899971,83.5700055 10.6033383,84.3999972 9.61,84.96 C8.6166617,85.5200028 7.186676,85.8 5.32,85.8 L0.74,85.8 Z M2.12,84.44 L3.78,84.44 C5.513342,84.44 6.7699961,84.3533342 7.55,84.18 C8.3300039,84.0066658 9.0133304,83.6633359 9.6,83.15 C10.1866696,82.6366641 10.6333318,82.013337 10.94,81.28 C11.2466682,80.546663 11.4,79.7066714 11.4,78.76 C11.4,77.8133286 11.2233351,76.940004 10.87,76.14 C10.5166649,75.339996 10.0133366,74.6800026 9.36,74.16 C8.7066634,73.6399974 7.9366711,73.2900009 7.05,73.11 C6.1633289,72.9299991 4.8600086,72.84 3.14,72.84 L2.12,72.84 L2.12,84.44 Z M16.2,75.94 L14.82,75.94 C14.886667,74.473326 15.3733288,73.2966711 16.28,72.41 C17.1866712,71.5233289 18.2833269,71.08 19.57,71.08 C20.8566731,71.08 21.9233291,71.4966625 22.77,72.33 C23.6166709,73.1633375 24.04,74.179994 24.04,75.38 C24.04,76.2733378 23.8033357,77.0999962 23.33,77.86 C22.8566643,78.6200038 22.1400048,79.5199948 21.18,80.56 L17.6,84.42 L24.24,84.42 L24.24,85.8 L14.48,85.8 L19.96,79.88 C20.9200048,78.8399948 21.6066646,78.020003 22.02,77.42 C22.4333354,76.819997 22.64,76.1333372 22.64,75.36 C22.64,74.5866628 22.3366697,73.9066696 21.73,73.32 C21.1233303,72.7333304 20.3700045,72.44 19.47,72.44 C18.5699955,72.44 17.8233363,72.7433303 17.23,73.35 C16.6366637,73.9566697 16.2933338,74.8199944 16.2,75.94 Z M32.58,70.86 L39.28,85.8 L37.74,85.8 L35.48,80.9 L29.28,80.9 L27.04,85.8 L25.44,85.8 L32.22,70.86 L32.58,70.86 Z M32.4,74.04 L29.94,79.44 L34.84,79.44 L32.4,74.04 Z M51.88,71.08 L51.88,85.8 L50.54,85.8 L50.54,83.98 C49.3266606,85.4333406 47.9366745,86.16 46.37,86.16 C44.8033255,86.16 43.486672,85.6066722 42.42,84.5 C41.353328,83.3933278 40.82,82.0666744 40.82,80.52 C40.82,78.9733256 41.3599946,77.6500055 42.44,76.55 C43.5200054,75.4499945 44.8133258,74.9 46.32,74.9 C48.053342,74.9 49.4599946,75.6399926 50.54,77.12 L50.54,71.08 L51.88,71.08 Z M50.62,80.56 C50.62,79.3466606 50.220004,78.3200042 49.42,77.48 C48.619996,76.6399958 47.620006,76.22 46.42,76.22 C45.219994,76.22 44.2166707,76.6499957 43.41,77.51 C42.6033293,78.3700043 42.2,79.3833275 42.2,80.55 C42.2,81.7166725 42.6133292,82.733329 43.44,83.6 C44.2666708,84.466671 45.2433277,84.9 46.37,84.9 C47.4966723,84.9 48.4866624,84.4900041 49.34,83.67 C50.1933376,82.8499959 50.62,81.8133396 50.62,80.56 Z M54.98,75.18 L56.34,75.18 L56.34,77.02 C57.2866714,75.6066596 58.4999926,74.9 59.98,74.9 C60.7666706,74.9 61.4699969,75.1233311 62.09,75.57 C62.7100031,76.0166689 63.1266656,76.6466626 63.34,77.46 C63.7800022,76.6333292 64.3399966,76.0000022 65.02,75.56 C65.7000034,75.1199978 66.4833289,74.9 67.37,74.9 C68.2566711,74.9 69.0599964,75.2433299 69.78,75.93 C70.5000036,76.6166701 70.86,77.9733232 70.86,80 L70.86,85.8 L69.46,85.8 L69.46,80 C69.46,79.0266618 69.4000006,78.3100023 69.28,77.85 C69.1599994,77.3899977 68.900002,77.0033349 68.5,76.69 C68.099998,76.3766651 67.5700033,76.22 66.91,76.22 C66.2499967,76.22 65.6333362,76.4399978 65.06,76.88 C64.4866638,77.3200022 64.0933344,77.8799966 63.88,78.56 C63.6666656,79.2400034 63.56,80.2666598 63.56,81.64 L63.56,85.8 L62.22,85.8 L62.22,80.36 C62.22,79.226661 62.1600006,78.4166691 62.04,77.93 C61.9199994,77.4433309 61.6533354,77.0366683 61.24,76.71 C60.8266646,76.3833317 60.320003,76.22 59.72,76.22 C59.119997,76.22 58.5566693,76.3966649 58.03,76.75 C57.5033307,77.1033351 57.0900015,77.5866636 56.79,78.2 C56.4899985,78.8133364 56.34,79.8466594 56.34,81.3 L56.34,85.8 L54.98,85.8 L54.98,75.18 Z M73.1,72.22 C73.1,71.9133318 73.2099989,71.6466678 73.43,71.42 C73.6500011,71.1933322 73.9166651,71.08 74.23,71.08 C74.5433349,71.08 74.8099989,71.1899989 75.03,71.41 C75.2500011,71.6300011 75.36,71.8966651 75.36,72.21 C75.36,72.5233349 75.2500011,72.7899989 75.03,73.01 C74.8099989,73.2300011 74.5433349,73.34 74.23,73.34 C73.9166651,73.34 73.6500011,73.2266678 73.43,73 C73.2099989,72.7733322 73.1,72.5133348 73.1,72.22 Z M73.54,75.18 L74.92,75.18 L74.92,85.8 L73.54,85.8 L73.54,75.18 Z M77.74,75.18 L79.12,75.18 L79.12,77.08 C80.2133388,75.6266594 81.5399922,74.9 83.1,74.9 C83.900004,74.9 84.6199968,75.1166645 85.26,75.55 C85.9000032,75.9833355 86.353332,76.5499965 86.62,77.25 C86.886668,77.9500035 87.02,78.9799932 87.02,80.34 L87.02,85.8 L85.66,85.8 L85.66,80.74 C85.66,79.4999938 85.6033339,78.6600022 85.49,78.22 C85.3766661,77.7799978 85.2033345,77.4066682 84.97,77.1 C84.7366655,76.7933318 84.4400018,76.5600008 84.08,76.4 C83.7199982,76.2399992 83.2833359,76.16 82.77,76.16 C82.2566641,76.16 81.7533358,76.2866654 81.26,76.54 C80.7666642,76.7933346 80.3466684,77.1466644 80,77.6 C79.6533316,78.0533356 79.4200006,78.5199976 79.3,79 C79.1799994,79.4800024 79.12,80.4466594 79.12,81.9 L79.12,85.8 L77.74,85.8 L77.74,75.18 Z" id="D2Admin" fill="#409EFF"></path>
<g id="logo-no-shadow" transform="translate(11.000000, 0.000000)">
<path d="M44.2833805,33.4299717 L6.05798302,56.3652102 C4.16366196,57.5018028 1.70662094,56.8875426 0.570028297,54.9932215 C0.197031333,54.3715599 8.87839274e-17,53.6602143 0,52.9352385 L-4.4408921e-16,7.06476152 C-7.1463071e-16,4.85562252 1.790861,3.06476152 4,3.06476152 C4.72497578,3.06476152 5.43632142,3.26179285 6.05798302,3.63478981 L44.2833805,26.5700283 C46.1777016,27.7066209 46.7919618,30.163662 45.6553692,32.057983 C45.3175701,32.6209814 44.8463789,33.0921727 44.2833805,33.4299717 Z" id="Triangle-Copy" fill="#35495E" transform="translate(25.000000, 30.000000) rotate(-180.000000) translate(-25.000000, -30.000000) "></path>
<path d="M60.2833805,33.4299717 L22.057983,56.3652102 C20.163662,57.5018028 17.7066209,56.8875426 16.5700283,54.9932215 C16.1970313,54.3715599 16,53.6602143 16,52.9352385 L16,7.06476152 C16,4.85562252 17.790861,3.06476152 20,3.06476152 C20.7249758,3.06476152 21.4363214,3.26179285 22.057983,3.63478981 L60.2833805,26.5700283 C62.1777016,27.7066209 62.7919618,30.163662 61.6553692,32.057983 C61.3175701,32.6209814 60.8463789,33.0921727 60.2833805,33.4299717 Z" id="Triangle" fill="#409EFF"></path>
<path d="M42.4688663,31.7973091 L24.0289915,42.8612339 C23.081831,43.4295303 21.8533105,43.1224001 21.2850141,42.1752396 C21.0985157,41.8644088 21,41.508736 21,41.1462481 L21,19.0183984 C21,17.9138289 21.8954305,17.0183984 23,17.0183984 C23.3624879,17.0183984 23.7181607,17.116914 24.0289915,17.3034125 L42.4688663,28.3673374 C43.4160268,28.9356337 43.7231569,30.1641542 43.1548606,31.1113147 C42.9859611,31.3928139 42.7503655,31.6284096 42.4688663,31.7973091 Z" id="Triangle-Copy" fill="#FFFFFF" transform="translate(31.000000, 30.082670) rotate(-180.000000) translate(-31.000000, -30.082670) "></path>
<path d="M37.5708451,30.8574929 L30.5144958,35.0913025 C30.0409155,35.3754507 29.4266552,35.2218856 29.1425071,34.7483054 C29.0492578,34.59289 29,34.4150536 29,34.2338096 L29,25.7661904 C29,25.2139056 29.4477153,24.7661904 30,24.7661904 C30.1812439,24.7661904 30.3590804,24.8154482 30.5144958,24.9086975 L37.5708451,29.1425071 C38.0444254,29.4266552 38.1979905,30.0409155 37.9138423,30.5144958 C37.8293925,30.6552454 37.7115947,30.7730432 37.5708451,30.8574929 Z" id="Triangle" fill="#409EFF"></path>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<svg viewBox="0 0 60 54" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<desc>D2Admin</desc>
<defs></defs>
<g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="logo-no-shadow" transform="translate(-3.000000, -3.000000)">
<path d="M44.2833805,33.4299717 L6.05798302,56.3652102 C4.16366196,57.5018028 1.70662094,56.8875426 0.570028297,54.9932215 C0.197031333,54.3715599 8.87839274e-17,53.6602143 0,52.9352385 L-4.4408921e-16,7.06476152 C-7.1463071e-16,4.85562252 1.790861,3.06476152 4,3.06476152 C4.72497578,3.06476152 5.43632142,3.26179285 6.05798302,3.63478981 L44.2833805,26.5700283 C46.1777016,27.7066209 46.7919618,30.163662 45.6553692,32.057983 C45.3175701,32.6209814 44.8463789,33.0921727 44.2833805,33.4299717 Z" id="Triangle-Copy" fill="#35495E" transform="translate(25.000000, 30.000000) rotate(-180.000000) translate(-25.000000, -30.000000) "></path>
<path d="M60.2833805,33.4299717 L22.057983,56.3652102 C20.163662,57.5018028 17.7066209,56.8875426 16.5700283,54.9932215 C16.1970313,54.3715599 16,53.6602143 16,52.9352385 L16,7.06476152 C16,4.85562252 17.790861,3.06476152 20,3.06476152 C20.7249758,3.06476152 21.4363214,3.26179285 22.057983,3.63478981 L60.2833805,26.5700283 C62.1777016,27.7066209 62.7919618,30.163662 61.6553692,32.057983 C61.3175701,32.6209814 60.8463789,33.0921727 60.2833805,33.4299717 Z" id="Triangle" fill="#409EFF"></path>
<path d="M42.4688663,31.7973091 L24.0289915,42.8612339 C23.081831,43.4295303 21.8533105,43.1224001 21.2850141,42.1752396 C21.0985157,41.8644088 21,41.508736 21,41.1462481 L21,19.0183984 C21,17.9138289 21.8954305,17.0183984 23,17.0183984 C23.3624879,17.0183984 23.7181607,17.116914 24.0289915,17.3034125 L42.4688663,28.3673374 C43.4160268,28.9356337 43.7231569,30.1641542 43.1548606,31.1113147 C42.9859611,31.3928139 42.7503655,31.6284096 42.4688663,31.7973091 Z" id="Triangle-Copy" fill="#FFFFFF" transform="translate(31.000000, 30.082670) rotate(-180.000000) translate(-31.000000, -30.082670) "></path>
<path d="M37.5708451,30.8574929 L30.5144958,35.0913025 C30.0409155,35.3754507 29.4266552,35.2218856 29.1425071,34.7483054 C29.0492578,34.59289 29,34.4150536 29,34.2338096 L29,25.7661904 C29,25.2139056 29.4477153,24.7661904 30,24.7661904 C30.1812439,24.7661904 30.3590804,24.8154482 30.5144958,24.9086975 L37.5708451,29.1425071 C38.0444254,29.4266552 38.1979905,30.0409155 37.9138423,30.5144958 C37.8293925,30.6552454 37.7115947,30.7730432 37.5708451,30.8574929 Z" id="Triangle" fill="#409EFF"></path>
</g>
</g>
</svg>
\ No newline at end of file
import Vue from 'vue'
const requireAll = requireContext => requireContext.keys().map(requireContext)
const req = require.context('./icons', false, /\.svg$/)
const iconMap = requireAll(req)
Vue.prototype.$IconSvg = iconMap.map(e => e.default.id.slice(3))
<template>
<div class="d2-container-card-bs">
<div v-if="$slots.header" class="d2-container-card-bs__header" ref="header">
<slot name="header"/>
</div>
<div class="d2-container-card-bs__body" ref="wrapper">
<div class="d2-container-card-bs__body-wrapper-inner">
<div class="d2-container-card-bs__body-card">
<slot/>
</div>
</div>
</div>
<div v-if="$slots.footer" class="d2-container-card-bs__footer" ref="footer">
<slot name="footer"/>
</div>
</div>
</template>
<script>
import bs from './mixins/bs'
export default {
name: 'd2-container-card-bs',
mixins: [
bs
]
}
</script>
<template>
<div class="d2-container-card">
<div v-if="$slots.header" class="d2-container-card__header" ref="header">
<slot name="header"/>
</div>
<div class="d2-container-card__body" ref="body">
<div class="d2-container-card__body-card">
<slot/>
</div>
</div>
<div v-if="$slots.footer" class="d2-container-card__footer" ref="footer">
<slot name="footer"/>
</div>
</div>
</template>
<script>
import scroll from './mixins/normal'
export default {
name: 'd2-container-card',
mixins: [
scroll
],
mounted () {
// 增加滚动事件监听
this.addScrollListener()
},
beforeDestroy () {
// 移除滚动事件监听
this.removeScrollListener()
}
}
</script>
<template>
<div class="d2-container-full-bs">
<div v-if="$slots.header" class="d2-container-full-bs__header" ref="header">
<slot name="header"/>
</div>
<div class="d2-container-full-bs__body" ref="wrapper">
<div class="d2-container-full-bs__body-wrapper-inner">
<slot/>
</div>
</div>
<div v-if="$slots.footer" class="d2-container-full-bs__footer" ref="footer">
<slot name="footer"/>
</div>
</div>
</template>
<script>
import bs from './mixins/bs'
export default {
name: 'd2-container-card-bs',
mixins: [
bs
]
}
</script>
<template>
<div class="d2-container-full">
<div v-if="$slots.header" class="d2-container-full__header" ref="header">
<slot name="header"/>
</div>
<div class="d2-container-full__body" ref="body">
<slot/>
</div>
<div v-if="$slots.footer" class="d2-container-full__footer" ref="footer">
<slot name="footer"/>
</div>
</div>
</template>
<script>
import scroll from './mixins/normal'
export default {
name: 'd2-container-full',
mixins: [
scroll
],
mounted () {
// 增加滚动事件监听
this.addScrollListener()
},
beforeDestroy () {
// 移除滚动事件监听
this.removeScrollListener()
}
}
</script>
<template>
<div class="d2-container-ghost-bs">
<div v-if="$slots.header" class="d2-container-ghost-bs__header" ref="header">
<slot name="header"/>
</div>
<div class="d2-container-ghost-bs__body" ref="wrapper">
<!-- https://github.com/d2-projects/d2-admin/issues/181 -->
<div>
<slot/>
</div>
</div>
<div v-if="$slots.footer" class="d2-container-ghost-bs__footer" ref="footer">
<slot name="footer"/>
</div>
</div>
</template>
<script>
import bs from './mixins/bs'
export default {
name: 'd2-container-card-bs',
mixins: [
bs
]
}
</script>
<template>
<div class="d2-container-ghost">
<div v-if="$slots.header" class="d2-container-ghost__header" ref="header">
<slot name="header"/>
</div>
<div class="d2-container-ghost__body" ref="body">
<slot/>
</div>
<div v-if="$slots.footer" class="d2-container-ghost__footer" ref="footer">
<slot name="footer"/>
</div>
</div>
</template>
<script>
import scroll from './mixins/normal'
export default {
name: 'd2-container-ghost',
mixins: [
scroll
],
mounted () {
// 增加滚动事件监听
this.addScrollListener()
},
beforeDestroy () {
// 移除滚动事件监听
this.removeScrollListener()
}
}
</script>
<template>
<div
v-if="show"
class="d2-source"
:class="{ 'd2-source--active': isActive }"
@click="handleClick">
<d2-icon name="code"/> 本页源码
</div>
</template>
<script>
import { last, get } from 'lodash'
export default {
data () {
return {
isActive: false,
path: ''
}
},
computed: {
show () {
return process.env.VUE_APP_SCOURCE_LINK === 'TRUE'
}
},
watch: {
$route: {
handler (to) {
this.path = get(last(to.matched), 'components.default.__source')
},
immediate: true
}
},
mounted () {
// 一秒后显示按钮
setTimeout(() => {
this.isActive = true
}, 500)
},
methods: {
// 点击按钮的时候跳转到源代码
handleClick () {
this.$open(`${process.env.VUE_APP_REPO}/blob/master/${this.path}`)
}
}
}
</script>
<style lang="scss" scoped>
.d2-source {
$borderRadius: 4px;
$paddingLR: 15px;
$paddingTB: 7px;
$fontSize: 12px;
$rightOuter: $paddingLR / 2;
opacity: 0;
position: fixed;
z-index: 9999;
right: - $borderRadius - $rightOuter;
bottom: 20px;
font-size: $fontSize;
line-height: $fontSize;
font-weight: bold;
border-radius: $borderRadius;
padding: $paddingTB $paddingLR;
padding-right: $borderRadius + $paddingLR;
background-color: rgba(#000, .7);
border: 1px solid #000;
color: #FFF;
transition: all .3s;
@extend %unable-select;
&.d2-source--active {
opacity: 1;
}
&:hover {
right: - $borderRadius;
background-color: rgba(#000, .9);
}
}
</style>
import BScroll from 'better-scroll'
export default {
props: {
// 滚动优化的选项
betterScrollOptions: {
type: Object,
required: false,
default: () => ({})
}
},
data () {
return {
BS: null
}
},
mounted () {
this.scrollInit()
},
beforeDestroy () {
this.scrollDestroy()
},
methods: {
scrollInit () {
// 初始化 bs
this.BS = new BScroll(this.$refs.wrapper, Object.assign({
mouseWheel: true,
click: true,
scrollbar: {
fade: true,
interactive: false
}
}, this.betterScrollOptions))
// 滚动时发出事件 并且统一返回的数据格式
this.BS.on('scroll', ({ x, y }) => this.$emit('scroll', {
x: -x,
y: -y
}))
},
scrollDestroy () {
// https://github.com/d2-projects/d2-admin/issues/75
try {
this.BS.destroy()
} catch (e) {
delete this.BS
this.BS = null
}
},
// 外部调用的方法 返回顶部
scrollToTop () {
if (this.BS) this.BS.scrollTo(0, 0, 300)
},
// 手动发出滚动事件
scroll () {
if (this.BS) {
this.$emit('scroll', {
x: -this.BS.x,
y: -this.BS.y
})
}
}
}
}
// 提供滚动方面的功能
// 非滚动优化模式通用
import { throttle } from 'lodash'
// 生成滚动事件的 handler
function handleMaker (wait) {
return throttle(e => {
this.$emit('scroll', {
x: e.target.scrollLeft,
y: e.target.scrollTop
})
}, wait)
}
export default {
props: {
// 滚动事件节流间隔
scrollDelay: {
type: Number,
required: false,
default: 10
}
},
data () {
return {
handleScroll: null
}
},
watch: {
scrollDelay (val) {
// 移除旧的监听
this.removeScrollListener()
// 生成新的 handle 方法
this.handleScroll = handleMaker.call(this, val)
// 添加新的监听
this.addScrollListener()
}
},
methods: {
// 增加滚动事件监听
addScrollListener () {
if (typeof this.handleScroll !== 'function') {
// mounted 生命周期内调用这个方法的时候会进入这里的判断
this.handleScroll = handleMaker.call(this, this.scrollDelay)
}
// 添加监听
this.$refs.body.addEventListener('scroll', this.handleScroll)
},
// 移除滚动事件监听
removeScrollListener () {
this.$refs.body.removeEventListener('scroll', this.handleScroll)
},
// 外部调用的方法 返回顶部
scrollToTop () {
const smoothscroll = () => {
const body = this.$refs.body
const currentScroll = body.scrollTop
if (currentScroll > 0) {
window.requestAnimationFrame(smoothscroll)
body.scrollTo(0, currentScroll - (currentScroll / 5))
}
}
smoothscroll()
}
}
}
// 组件
import d2ContainerFull from './components/d2-container-full.vue'
import d2ContainerFullBs from './components/d2-container-full-bs.vue'
import d2ContainerGhost from './components/d2-container-ghost.vue'
import d2ContainerGhostBs from './components/d2-container-ghost-bs.vue'
import d2ContainerCard from './components/d2-container-card.vue'
import d2ContainerCardBs from './components/d2-container-card-bs.vue'
import d2Source from './components/d2-source.vue'
export default {
name: 'd2-container',
props: {
// 容器样式
type: {
type: String,
required: false,
default: 'full'
},
// 滚动优化
betterScroll: {
type: Boolean,
required: false,
default: false
}
},
computed: {
// 始终返回渲染组件
component () {
if (this.type === 'card' && !this.betterScroll) return d2ContainerCard
if (this.type === 'card' && this.betterScroll) return d2ContainerCardBs
if (this.type === 'ghost' && !this.betterScroll) return d2ContainerGhost
if (this.type === 'ghost' && this.betterScroll) return d2ContainerGhostBs
if (this.type === 'full' && !this.betterScroll) return d2ContainerFull
if (this.type === 'full' && this.betterScroll) return d2ContainerFullBs
else {
return 'div'
}
}
},
render (h) {
const slots = [ this.$slots.default ]
if (this.$slots.header) slots.push(h('template', { slot: 'header' }, [ this.$slots.header ]))
if (this.$slots.footer) slots.push(h('template', { slot: 'footer' }, [ this.$slots.footer ]))
return h('div', {
ref: 'container',
class: 'container-component'
}, [
h(this.component, {
ref: 'component',
props: this.$attrs,
on: {
scroll: e => this.$emit('scroll', e)
}
}, slots),
h(d2Source)
])
},
methods: {
// 返回顶部
scrollToTop () {
this.$refs.component.scrollToTop()
// 如果开启了 better scroll 还需要手动触发一遍 scroll 事件
const bs = this.$refs.component.BS
if (bs) this.$refs.component.scroll()
},
// 用法同原生方法 scrollBy
scrollBy (x = 0, y = 0, time = 300) {
if (this.betterScroll) {
const bs = this.$refs.component.BS
if (bs) {
bs.scrollBy(-x, -y, time)
// 手动触发一遍 scroll 事件
this.$refs.component.scroll()
}
} else {
this.$refs.component.$refs.body.scrollBy(x, y)
}
},
// 用法同原生方法 scrollTo
scrollTo (x = 0, y = 0, time = 300) {
if (this.betterScroll) {
const bs = this.$refs.component.BS
if (bs) {
bs.scrollTo(-x, -y, time)
// 手动触发一遍 scroll 事件
this.$refs.component.scroll()
}
} else {
this.$refs.component.$refs.body.scrollTo(x, y)
}
},
// 用法同原生方法 scrollTop
scrollTop (top = 0, time = 300) {
if (this.betterScroll) {
const bs = this.$refs.component.BS
if (bs) {
bs.scrollTo(bs.x, -top, time)
// 手动触发一遍 scroll 事件
this.$refs.component.scroll()
}
} else {
this.$refs.component.$refs.body.scrollTop = top
}
}
}
}
<template>
<svg aria-hidden="true">
<use :xlink:href="icon"></use>
</svg>
</template>
<script>
export default {
name: 'd2-icon-svg',
props: {
name: {
type: String,
required: true
}
},
computed: {
icon () {
return `#d2-${this.name}`
}
}
}
</script>
/*!
* Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
*/@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}
This source diff could not be displayed because it is too large. You can view the blob instead.
<template>
<i class="fa" :class="`fa-${name}`" aria-hidden="true"></i>
</template>
<script>
import './font-awesome-4.7.0/css/font-awesome.min.css'
export default {
name: 'd2-icon',
props: {
name: {
type: String,
required: false,
default: 'font-awesome'
}
}
}
</script>
import Vue from 'vue'
import d2Container from './d2-container'
// 注意 有些组件使用异步加载会有影响
Vue.component('d2-container', d2Container)
Vue.component('d2-icon', () => import('./d2-icon'))
Vue.component('d2-icon-svg', () => import('./d2-icon-svg/index.vue'))
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import util from '@/libs/util'
Vue.use(VueI18n)
function loadLocaleMessages () {
const locales = require.context('./locales', true, /[A-Za-z0-9-_,\s]+\.json$/i)
const messages = {}
for (const key of locales.keys()) {
const matched = key.match(/([A-Za-z0-9-_]+)\./i)
if (matched && matched.length > 1) {
const locale = matched[1]
const localeElementUI = require(`element-ui/lib/locale/lang/${locales(key)._element}`)
messages[locale] = {
...locales(key),
...localeElementUI ? localeElementUI.default : {}
}
}
}
return messages
}
const messages = loadLocaleMessages()
Vue.prototype.$languages = Object.keys(messages).map(langlage => ({
label: messages[langlage]._name,
value: langlage
}))
const i18n = new VueI18n({
locale: util.cookies.get('lang') || process.env.VUE_APP_I18N_LOCALE,
fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE,
messages
})
export default i18n
<template>
<div
class="d2-contentmenu-list"
@click="rowClick">
<div
v-for="item in menulist"
:key="item.value"
:data-value="item.value"
class="d2-contentmenu-item"
flex="cross:center main:center">
<d2-icon
v-if="item.icon"
:name="item.icon"/>
<div
class="d2-contentmenu-item-title"
flex-box="1">
{{item.title}}
</div>
</div>
</div>
</template>
<script>
export default {
name: 'd2-contextmenu-list',
props: {
menulist: {
type: Array,
default: () => []
}
},
methods: {
rowClick (event) {
let target = event.target
while (!target.dataset.value) {
target = target.parentNode
}
this.$emit('rowClick', target.dataset.value)
}
}
}
</script>
<style lang="scss">
.d2-contentmenu-list {
.d2-contentmenu-item {
padding: 8px 20px 8px 15px;
margin: 0;
font-size: 14px;
color: #606266;
cursor: pointer;
&:hover {
background: #ecf5ff;
color: #66b1ff;
}
.d2-contentmenu-item-title {
margin-left: 10px;
}
}
}
</style>
<template>
<div
class="d2-contextmenu"
v-show="flag"
:style="style">
<slot/>
</div>
</template>
<script>
export default {
name: 'd2-contextmenu',
props: {
visible: {
type: Boolean,
default: false
},
x: {
type: Number,
default: 0
},
y: {
type: Number,
default: 0
}
},
computed: {
flag: {
get () {
if (this.visible) {
// 注册全局监听事件 [ 目前只考虑鼠标解除触发 ]
window.addEventListener('mousedown', this.watchContextmenu)
}
return this.visible
},
set (newVal) {
this.$emit('update:visible', newVal)
}
},
style () {
return {
left: this.x + 'px',
top: this.y + 'px',
display: this.visible ? 'block' : 'none '
}
}
},
methods: {
watchContextmenu (event) {
if (!this.$el.contains(event.target) || event.button !== 0) this.flag = false
window.removeEventListener('mousedown', this.watchContextmenu)
}
},
mounted () {
// 将菜单放置到body下
document.querySelector('body').appendChild(this.$el)
}
}
</script>
<style>
.d2-contextmenu {
position: absolute;
padding: 5px 0;
z-index: 2018;
background: #FFF;
border: 1px solid #cfd7e5;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
}
</style>
<template>
<el-color-picker
class="btn-text can-hover"
:value="value"
:predefine="predefine"
size="mini"
@change="set"/>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
name: 'd2-header-color',
data () {
return {
predefine: [
'#ff4500',
'#ff8c00',
'#ffd700',
'#90ee90',
'#00ced1',
'#1e90ff',
'#c71585'
]
}
},
computed: {
...mapState('d2admin/color', [
'value'
])
},
watch: {
value (value) {
this.set(value)
}
},
methods: {
...mapActions('d2admin/color', [
'set'
])
}
}
</script>
<template>
<el-tooltip
effect="dark"
:content="active ? '退出全屏' : '全屏'"
placement="bottom">
<el-button class="d2-mr btn-text can-hover" type="text" @click="toggle">
<d2-icon v-if="active" name="compress"/>
<d2-icon v-else name="arrows-alt" style="font-size: 16px"/>
</el-button>
</el-tooltip>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
computed: {
...mapState('d2admin/fullscreen', [
'active'
])
},
methods: {
...mapActions('d2admin/fullscreen', [
'toggle'
])
}
}
</script>
<template>
<el-dropdown
placement="bottom"
size="small"
@command="onChangeLocale">
<el-button class="d2-mr btn-text can-hover" type="text">
<d2-icon name="language" style="font-size: 16px;"/>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
v-for="language in $languages"
:key="language.value"
:command="language.value">
<d2-icon :name="$i18n.locale === language.value ? 'dot-circle-o' : 'circle-o'" class="d2-mr-5"/>
{{ language.label }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<script>
import localeMixin from '@/locales/mixin.js'
export default {
mixins: [
localeMixin
]
}
</script>
<template>
<el-tooltip
effect="dark"
:content="tooltipContent"
placement="bottom">
<el-button
class="d2-ml-0 d2-mr btn-text can-hover"
type="text"
@click="handleClick">
<el-badge
v-if="logLength > 0"
:max="99"
:value="logLengthError"
:is-dot="logLengthError === 0">
<d2-icon
:name="logLengthError === 0 ? 'dot-circle-o' : 'bug'"
style="font-size: 20px"/>
</el-badge>
<d2-icon
v-else
name="dot-circle-o"
style="font-size: 20px"/>
</el-button>
</el-tooltip>
</template>
<script>
import { mapGetters, mapMutations } from 'vuex'
export default {
computed: {
...mapGetters('d2admin', {
logLength: 'log/length',
logLengthError: 'log/lengthError'
}),
tooltipContent () {
return this.logLength === 0
? '没有日志或异常'
: `${this.logLength} 条日志${this.logLengthError > 0
? ` | 包含 ${this.logLengthError} 个异常`
: ''}`
}
},
methods: {
...mapMutations('d2admin/log', [
'clean'
]),
handleClick () {
this.$router.push({
name: 'log'
})
}
}
}
</script>
<template>
<el-button class="d2-mr btn-text can-hover" type="text" @click="handleClick">
<d2-icon name="search" style="font-size: 18px;"/>
</el-button>
</template>
<script>
export default {
methods: {
handleClick () {
this.$emit('click')
}
}
}
</script>
<template>
<el-dropdown placement="bottom" size="small" @command="handleChange">
<el-button class="d2-mr btn-text can-hover" type="text">
<d2-icon name="font" style="font-size: 16px;"/>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="item in options" :key="item.value" :command="item.value">
<d2-icon :name="iconName(item.value)" class="d2-mr-5"/>{{item.label}}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<script>
import { mapState, mapMutations, mapActions } from 'vuex'
export default {
name: 'd2-header-size',
data () {
return {
options: [
{ label: '默认', value: 'default' },
{ label: '中', value: 'medium' },
{ label: '小', value: 'small' },
{ label: '最小', value: 'mini' }
]
}
},
computed: {
...mapState('d2admin/size', [
'value'
])
},
methods: {
...mapMutations({
pageKeepAliveClean: 'd2admin/page/keepAliveClean'
}),
...mapActions({
sizeSet: 'd2admin/size/set'
}),
handleChange (value) {
this.sizeSet(value)
this.$notify({
title: '提示',
dangerouslyUseHTMLString: true,
message: '已更新页面内 <b>组件</b> 的 <b>默认尺寸</b><br/>例如按钮大小,<b>非字号</b>',
type: 'success'
})
},
iconName (name) {
return name === this.value ? 'dot-circle-o' : 'circle-o'
}
}
}
</script>
<template>
<el-table
:data="list"
v-bind="table">
<el-table-column
prop="title"
align="center"
width="160"/>
<el-table-column
label="预览"
width="120">
<div
slot-scope="scope"
class="theme-preview"
:style="{
backgroundImage: `url(${$baseUrl}${scope.row.preview})`
}">
</div>
</el-table-column>
<el-table-column
prop="address"
align="center">
<template slot-scope="scope">
<el-button
v-if="activeName === scope.row.name"
type="success"
icon="el-icon-check"
round>
已激活
</el-button>
<el-button
v-else
round
@click="handleSelectTheme(scope.row.name)">
使用
</el-button>
</template>
</el-table-column>
</el-table>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
name: 'd2-theme-list',
data () {
return {
table: {
showHeader: false,
border: true
}
}
},
computed: {
...mapState('d2admin/theme', [
'list',
'activeName'
])
},
methods: {
...mapActions('d2admin/theme', [
'set'
]),
handleSelectTheme (name) {
this.set(name)
}
}
}
</script>
<style lang="scss" scoped>
.theme-preview {
height: 50px;
width: 100px;
border-radius: 4px;
background-size: cover;
border: 1px solid $color-border-1;
}
</style>
<template>
<div>
<el-tooltip
effect="dark"
content="主题"
placement="bottom">
<el-button
class="d2-ml-0 d2-mr btn-text can-hover"
type="text"
@click="dialogVisible = true">
<d2-icon
name="diamond"
style="font-size: 16px"/>
</el-button>
</el-tooltip>
<el-dialog
title="主题"
width="600px"
:visible.sync="dialogVisible"
:append-to-body="true">
<d2-theme-list style="margin-top: -25px;"/>
</el-dialog>
</div>
</template>
<script>
import themeList from './components/d2-theme-list'
export default {
components: {
'd2-theme-list': themeList
},
data () {
return {
dialogVisible: false
}
}
}
</script>
<template>
<el-dropdown size="small" class="d2-mr">
<span class="btn-text">{{info.name ? `你好 ${info.name}` : '未登录'}}</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="logOff">
<d2-icon name="power-off" class="d2-mr-5"/>
注销
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
computed: {
...mapState('d2admin/user', [
'info'
])
},
methods: {
...mapActions('d2admin/account', [
'logout'
]),
/**
* @description 登出
*/
logOff () {
this.logout({
confirm: true
})
}
}
}
</script>
// 创建 el-menu-item
export function elMenuItem (createElement, menu) {
return createElement('el-menu-item', { props: { index: menu.path } }, [
...menu.icon ? [
createElement('i', { attrs: { class: `fa fa-${menu.icon}` } })
] : [],
...menu.icon === undefined & !menu.iconSvg ? [
createElement('i', { attrs: { class: 'fa fa-file-o' } })
] : [],
...menu.iconSvg ? [
createElement('d2-icon-svg', { props: { name: menu.iconSvg } })
] : [],
createElement('span', { slot: 'title' }, menu.title || '未命名菜单')
])
}
// 创建 el-submenu
export function elSubmenu (createElement, menu) {
return createElement('el-submenu', { props: { index: menu.path } }, [
...menu.icon ? [
createElement('i', { slot: 'title', attrs: { class: `fa fa-${menu.icon}` } })
] : [],
...menu.icon === undefined & !menu.iconSvg ? [
createElement('i', { slot: 'title', attrs: { class: 'fa fa-folder-o' } })
] : [],
...menu.iconSvg ? [
createElement('d2-icon-svg', { slot: 'title', props: { name: menu.iconSvg } })
] : [],
createElement('span', { slot: 'title' }, menu.title || '未命名菜单'),
...menu.children.map((child, childIndex) => (child.children === undefined ? elMenuItem : elSubmenu).call(this, createElement, child))
])
}
import { throttle } from 'lodash'
import { mapState } from 'vuex'
import menuMixin from '../mixin/menu'
import { elMenuItem, elSubmenu } from '../libs/util.menu'
export default {
name: 'd2-layout-header-aside-menu-header',
mixins: [
menuMixin
],
render (createElement) {
return createElement('div', {
attrs: { flex: 'cross:center' },
class: { 'd2-theme-header-menu': true, 'is-scrollable': this.isScroll },
ref: 'page'
}, [
createElement('div', {
attrs: { class: 'd2-theme-header-menu__content', flex: '', 'flex-box': '1' },
ref: 'content'
}, [
createElement('div', {
attrs: { class: 'd2-theme-header-menu__scroll', 'flex-box': '0' },
style: { transform: `translateX(${this.currentTranslateX}px)` },
ref: 'scroll'
}, [
createElement('el-menu', {
props: { mode: 'horizontal', defaultActive: this.active },
on: { select: this.handleMenuSelect }
}, this.header.map(menu => (menu.children === undefined ? elMenuItem : elSubmenu).call(this, createElement, menu)))
])
]),
...this.isScroll ? [
createElement('div', {
attrs: { class: 'd2-theme-header-menu__prev', flex: 'main:center cross:center', 'flex-box': '0' },
on: { click: () => this.scroll('left') }
}, [
createElement('i', { attrs: { class: 'el-icon-arrow-left' } })
]),
createElement('div', {
attrs: { class: 'd2-theme-header-menu__next', flex: 'main:center cross:center', 'flex-box': '0' },
on: { click: () => this.scroll('right') }
}, [
createElement('i', { attrs: { class: 'el-icon-arrow-right' } })
])
] : []
])
},
computed: {
...mapState('d2admin/menu', [
'header'
])
},
data () {
return {
active: '',
isScroll: false,
scrollWidth: 0,
contentWidth: 0,
currentTranslateX: 0,
throttledCheckScroll: null
}
},
watch: {
'$route.matched': {
handler (val) {
this.active = val[val.length - 1].path
},
immediate: true
}
},
methods: {
scroll (direction) {
if (direction === 'left') {
// 向右滚动
this.currentTranslateX = 0
} else {
// 向左滚动
if (this.contentWidth * 2 - this.currentTranslateX <= this.scrollWidth) {
this.currentTranslateX -= this.contentWidth
} else {
this.currentTranslateX = this.contentWidth - this.scrollWidth
}
}
},
checkScroll () {
let contentWidth = this.$refs.content.clientWidth
let scrollWidth = this.$refs.scroll.clientWidth
if (this.isScroll) {
// 页面依旧允许滚动的情况,需要更新width
if (this.contentWidth - this.scrollWidth === this.currentTranslateX) {
// currentTranslateX 也需要相应变化【在右端到头的情况时】
this.currentTranslateX = contentWidth - scrollWidth
// 快速的滑动依旧存在判断和计算时对应的contentWidth变成正数,所以需要限制一下
if (this.currentTranslateX > 0) {
this.currentTranslateX = 0
}
}
// 更新元素数据
this.contentWidth = contentWidth
this.scrollWidth = scrollWidth
// 判断何时滚动消失: 当scroll > content
if (contentWidth > scrollWidth) {
this.isScroll = false
}
}
// 判断何时滚动出现: 当scroll < content
if (!this.isScroll && contentWidth < scrollWidth) {
this.isScroll = true
// 注意,当isScroll变为true,对应的元素盒子大小会发生变化
this.$nextTick(() => {
contentWidth = this.$refs.content.clientWidth
scrollWidth = this.$refs.scroll.clientWidth
this.contentWidth = contentWidth
this.scrollWidth = scrollWidth
this.currentTranslateX = 0
})
}
}
},
mounted () {
// 初始化判断
// 默认判断父元素和子元素的大小,以确定初始情况是否显示滚动
window.addEventListener('load', this.checkScroll)
// 全局窗口变化监听,判断父元素和子元素的大小,从而控制isScroll的开关
this.throttledCheckScroll = throttle(this.checkScroll, 300)
window.addEventListener('resize', this.throttledCheckScroll)
},
beforeDestroy () {
// 取消监听
window.removeEventListener('resize', this.throttledCheckScroll)
window.removeEventListener('load', this.checkScroll)
}
}
import { mapState } from 'vuex'
import menuMixin from '../mixin/menu'
import { elMenuItem, elSubmenu } from '../libs/util.menu'
import BScroll from 'better-scroll'
export default {
name: 'd2-layout-header-aside-menu-side',
mixins: [
menuMixin
],
render (createElement) {
return createElement('div', { attrs: { class: 'd2-layout-header-aside-menu-side' } }, [
createElement('el-menu', {
props: { collapse: this.asideCollapse, uniqueOpened: true, defaultActive: this.active },
ref: 'menu',
on: { select: this.handleMenuSelect }
}, this.aside.map(menu => (menu.children === undefined ? elMenuItem : elSubmenu).call(this, createElement, menu))),
...this.aside.length === 0 && !this.asideCollapse ? [
createElement('div', { attrs: { class: 'd2-layout-header-aside-menu-empty', flex: 'dir:top main:center cross:center' } }, [
createElement('d2-icon', { props: { name: 'inbox' } }),
createElement('span', {}, '没有侧栏菜单')
])
] : []
])
},
data () {
return {
active: '',
asideHeight: 300,
BS: null
}
},
computed: {
...mapState('d2admin/menu', [
'aside',
'asideCollapse'
])
},
watch: {
// 折叠和展开菜单的时候销毁 better scroll
asideCollapse (val) {
this.scrollDestroy()
setTimeout(() => {
this.scrollInit()
}, 500)
},
// 监听路由 控制侧边栏激活状态
'$route.fullPath': {
handler (value) {
this.active = value
},
immediate: true
}
},
mounted () {
this.scrollInit()
},
beforeDestroy () {
this.scrollDestroy()
},
methods: {
scrollInit () {
this.BS = new BScroll(this.$el, {
mouseWheel: true,
click: true
// 如果你愿意可以打开显示滚动条
// scrollbar: {
// fade: true,
// interactive: false
// }
})
},
scrollDestroy () {
// https://github.com/d2-projects/d2-admin/issues/75
try {
this.BS.destroy()
} catch (e) {
delete this.BS
this.BS = null
}
}
}
}
import util from '@/libs/util.js'
export default {
methods: {
handleMenuSelect (index, indexPath) {
if (/^d2-menu-empty-\d+$/.test(index) || index === undefined) {
this.$message.warning('临时菜单')
} else if (/^https:\/\/|http:\/\//.test(index)) {
util.open(index)
} else {
this.$router.push({
path: index
})
}
}
}
}
<template>
<div class="d2-panel-search-item" :class="hoverMode ? 'can-hover' : ''" flex>
<div class="d2-panel-search-item__icon" flex-box="0">
<div class="d2-panel-search-item__icon-box" flex="main:center cross:center">
<d2-icon v-if="item.icon" :name="item.icon"/>
<d2-icon-svg v-else-if="item.iconSvg" :name="item.iconSvg"/>
<d2-icon v-else name="file-o"/>
</div>
</div>
<div class="d2-panel-search-item__info" flex-box="1" flex="dir:top">
<div class="d2-panel-search-item__info-title" flex-box="1" flex="cross:center">
<span>{{item.title}}</span>
</div>
<div class="d2-panel-search-item__info-fullTitle" flex-box="0">
<span>{{item.fullTitle}}</span>
</div>
<div class="d2-panel-search-item__info-path" flex-box="0">
<span>{{item.path}}</span>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
item: {
default: () => ({})
},
hoverMode: {
default: false
}
}
}
</script>
<style lang="scss" scoped>
.d2-panel-search-item {
height: 64px;
margin: 0px -20px;
&.can-hover {
@extend %unable-select;
margin: 0px;
&:hover {
background-color: #F5F7FA;
.d2-panel-search-item__icon {
.d2-panel-search-item__icon-box {
i {
font-size: 24px;
color: $color-primary;
}
}
}
.d2-panel-search-item__info {
.d2-panel-search-item__info-title {
color: $color-text-main;
}
.d2-panel-search-item__info-fullTitle {
color: $color-text-normal;
}
.d2-panel-search-item__info-path {
color: $color-text-normal;
}
}
}
}
.d2-panel-search-item__icon {
width: 64px;
.d2-panel-search-item__icon-box {
height: 64px;
width: 64px;
border-right: 1px solid $color-border-3;
i {
font-size: 20px;
color: $color-text-sub;
}
svg {
height: 20px;
width: 20px;
}
}
}
.d2-panel-search-item__info {
margin-left: 10px;
.d2-panel-search-item__info-title {
font-size: 16px;
line-height: 16px;
font-weight: bold;
color: $color-text-normal;
}
.d2-panel-search-item__info-fullTitle {
font-size: 10px;
line-height: 14px;
color: $color-text-placehoder;
}
.d2-panel-search-item__info-path {
margin-bottom: 4px;
font-size: 10px;
line-height: 14px;
color: $color-text-placehoder;
}
}
}
</style>
<template>
<div
class="panel-search"
flex="dir:top">
<div
class="panel-search__input-group"
flex-box="0"
flex="dir:top main:center cross:center"
@click.self="handlePanelClick">
<d2-icon-svg
class="panel-search__logo"
name="d2-admin-text"/>
<el-autocomplete
class="panel-search__input"
ref="input"
v-model="searchText"
suffix-icon="el-icon-search"
placeholder="搜索页面"
:fetch-suggestions="querySearch"
:trigger-on-focus="false"
:clearable="true"
@keydown.esc.native="handleEsc"
@select="handleSelect">
<d2-panel-search-item
slot-scope="{ item }"
:item="item"/>
</el-autocomplete>
<div class="panel-search__tip">
您可以使用快捷键
<span class="panel-search__key">{{hotkey.open}}</span>
唤醒搜索面板,按
<span class="panel-search__key">{{hotkey.close}}</span>
关闭
</div>
</div>
<div
v-if="resultsList.length > 0"
class="panel-search__results-group"
flex-box="1">
<el-card>
<div class="panel-search__results-group-inner">
<d2-panel-search-item
v-for="(item, index) in resultsList"
:key="index"
:item="item"
:hover-mode="true"
@click.native="handleResultsGroupItemClick(item.path)"/>
</div>
</el-card>
</div>
</div>
</template>
<script>
import Fuse from 'fuse.js'
import { mapState } from 'vuex'
import mixin from '../mixin/menu'
export default {
mixins: [
mixin
],
components: {
'd2-panel-search-item': () => import('./components/panel-search-item/index.vue')
},
data () {
return {
searchText: '',
results: []
}
},
computed: {
...mapState('d2admin/search', [
'hotkey',
'pool'
]),
// 这份数据是展示在搜索面板下面的
resultsList () {
return (this.results.length === 0 && this.searchText === '') ? this.pool.map(e => ({
value: e.fullTitle,
...e
})) : this.results
}
},
methods: {
/**
* @description 过滤选项 这个方法在每次输入框的值发生变化时会触发
*/
querySearch (queryString, callback) {
var pool = this.pool
const results = this.query(queryString ? pool : [], queryString)
this.results = results
callback(results)
},
/**
* @description 指定的数据源中根据指定的查询字符串过滤数据
* @param {Object} pool 需要过滤的数据
* @param {String} queryString 查询字符串
*/
query (pool, queryString) {
return new Fuse(pool, {
shouldSort: true,
tokenize: true,
threshold: 0.6,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: [
'fullTitle',
'path'
]
})
.search(queryString)
.map(e => ({
value: e.fullTitle,
...e
}))
},
/**
* @description 聚焦输入框
*/
focus () {
this.input = ''
setTimeout(() => {
if (this.$refs.input) {
this.$refs.input.focus()
}
// 还原
this.searchText = ''
this.results = []
}, 500)
},
/**
* @description 接收用户在列表中选择项目的事件
*/
handleResultsGroupItemClick (path) {
// 如果用户选择的就是当前页面 就直接关闭搜索面板
if (path === this.$route.path) {
this.handleEsc()
return
}
// 用户选择的是其它页面
this.handleMenuSelect(path)
},
/**
* @description 接收用户在下拉菜单中选中事件
*/
handleSelect ({ path }) {
// 如果用户选择的就是当前页面 就直接关闭搜索面板
if (path === this.$route.path) {
this.handleEsc()
return
}
// 用户选择的是其它页面
this.$nextTick(() => {
this.handleMenuSelect(path)
})
},
/**
* @augments 关闭输入框的下拉菜单
*/
closeSuggestion () {
if (this.$refs.input.activated) {
this.$refs.input.suggestions = []
this.$refs.input.activated = false
}
},
/**
* @augments 接收用户点击空白区域的关闭
*/
handlePanelClick () {
this.handleEsc()
},
/**
* @augments 接收用户触发的关闭
*/
handleEsc () {
this.closeSuggestion()
this.$nextTick(() => {
this.$emit('close')
})
}
}
}
</script>
<style lang="scss" scoped>
.panel-search {
margin: 20px;
width: 100%;
.panel-search__input-group {
height: 240px;
.panel-search__logo {
width: 80px;
height: 80px;
margin-bottom: 20px;
}
.panel-search__input {
width: 500px;
}
.panel-search__tip {
@extend %unable-select;
margin-top: 20px;
margin-bottom: 40px;
font-size: 12px;
color: $color-text-sub;
.panel-search__key {
padding: 1px 5px;
margin: 0px 2px;
border-radius: 2px;
background-color: $color-text-normal;
color: $color-bg;
}
}
}
.panel-search__results-group {
overflow: auto;
margin-bottom: -20px;
.panel-search__results-group-inner {
margin: -20px;
}
}
}
</style>
<template>
<div class="d2-multiple-page-control-group" flex>
<div class="d2-multiple-page-control-content" flex-box="1">
<div class="d2-multiple-page-control-content-inner">
<d2-contextmenu
:visible.sync="contextmenuFlag"
:x="contentmenuX"
:y="contentmenuY">
<d2-contextmenu-list
:menulist="tagName === '/index' ? contextmenuListIndex : contextmenuList"
@rowClick="contextmenuClick"/>
</d2-contextmenu>
<el-tabs
class="d2-multiple-page-control d2-multiple-page-sort"
:value="current"
type="card"
:closable="true"
@tab-click="handleClick"
@edit="handleTabsEdit"
@contextmenu.native="handleContextmenu">
<el-tab-pane
v-for="page in opened"
:key="page.fullPath"
:label="page.meta.title || '未命名'"
:name="page.fullPath"/>
</el-tabs>
</div>
</div>
<div
class="d2-multiple-page-control-btn"
flex-box="0">
<el-dropdown
size="default"
split-button
@click="closeAll"
@command="command => handleControlItemClick(command)">
<d2-icon name="times-circle"/>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="left">
<d2-icon name="arrow-left" class="d2-mr-10"/>
关闭左侧
</el-dropdown-item>
<el-dropdown-item command="right">
<d2-icon name="arrow-right" class="d2-mr-10"/>
关闭右侧
</el-dropdown-item>
<el-dropdown-item command="other">
<d2-icon name="times" class="d2-mr-10"/>
关闭其它
</el-dropdown-item>
<el-dropdown-item command="all">
<d2-icon name="times-circle" class="d2-mr-10"/>
全部关闭
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
import Sortable from 'sortablejs'
export default {
components: {
D2Contextmenu: () => import('../contextmenu'),
D2ContextmenuList: () => import('../contextmenu/components/contentmenuList')
},
data () {
return {
contextmenuFlag: false,
contentmenuX: 0,
contentmenuY: 0,
contextmenuListIndex: [
{ icon: 'times-circle', title: '关闭全部', value: 'all' }
],
contextmenuList: [
{ icon: 'arrow-left', title: '关闭左侧', value: 'left' },
{ icon: 'arrow-right', title: '关闭右侧', value: 'right' },
{ icon: 'times', title: '关闭其它', value: 'other' },
{ icon: 'times-circle', title: '关闭全部', value: 'all' }
],
tagName: '/index'
}
},
computed: {
...mapState('d2admin/page', [
'opened',
'current'
])
},
methods: {
...mapActions('d2admin/page', [
'close',
'closeLeft',
'closeRight',
'closeOther',
'closeAll',
'openedSort'
]),
/**
* @description 右键菜单功能点击
*/
handleContextmenu (event) {
let target = event.target
// 解决 https://github.com/d2-projects/d2-admin/issues/54
let flag = false
if (target.className.indexOf('el-tabs__item') > -1) flag = true
else if (target.parentNode.className.indexOf('el-tabs__item') > -1) {
target = target.parentNode
flag = true
}
if (flag) {
event.preventDefault()
event.stopPropagation()
this.contentmenuX = event.clientX
this.contentmenuY = event.clientY
this.tagName = target.getAttribute('aria-controls').slice(5)
this.contextmenuFlag = true
}
},
/**
* @description 右键菜单的row-click事件
*/
contextmenuClick (command) {
this.handleControlItemClick(command, this.tagName)
},
/**
* @description 接收点击关闭控制上选项的事件
*/
handleControlItemClick (command, tagName = null) {
if (tagName) {
this.contextmenuFlag = false
}
const params = {
pageSelect: tagName
}
switch (command) {
case 'left':
this.closeLeft(params)
break
case 'right':
this.closeRight(params)
break
case 'other':
this.closeOther(params)
break
case 'all':
this.closeAll()
break
default:
this.$message.error('无效的操作')
break
}
},
/**
* @description 接收点击 tab 标签的事件
*/
handleClick (tab, event) {
// 找到点击的页面在 tag 列表里是哪个
const page = this.opened.find(page => page.fullPath === tab.name)
const { name, params, query } = page
if (page) {
this.$router.push({ name, params, query })
}
},
/**
* @description 点击 tab 上的删除按钮触发这里 首页的删除按钮已经隐藏 因此这里不用判断是 index
*/
handleTabsEdit (tagName, action) {
if (action === 'remove') {
this.close({
tagName
})
}
}
},
mounted () {
const el = document.querySelectorAll('.d2-multiple-page-sort .el-tabs__nav')[0]
Sortable.create(el, {
onEnd: (evt) => {
const { oldIndex, newIndex } = evt
this.openedSort({ oldIndex, newIndex })
}
})
}
}
</script>
import layout from './layout'
export default layout
<template>
<div
class="d2-layout-header-aside-group"
:style="styleLayoutMainGroup"
:class="{grayMode: grayActive}"
>
<!-- 半透明遮罩 -->
<div class="d2-layout-header-aside-mask"></div>
<!-- 主体内容 -->
<div class="d2-layout-header-aside-content" flex="dir:top">
<!-- 顶栏 -->
<div
class="d2-theme-header"
:style="{
opacity: this.searchActive ? 0.5 : 1
}"
flex-box="0"
flex
>
<img class="zlogos" :src="`/image/logo.png`" />
<!-- <img :src="`${$baseUrl}image/theme/${themeActiveSetting.name}/logo/all.png`" /> -->
<!-- <router-link
to="/index"
class="logo-group"
:style="{width: asideCollapse ? asideWidthCollapse : asideWidth}"
flex-box="0"
>
<img
v-if="asideCollapse"
:src="`${$baseUrl}image/theme/${themeActiveSetting.name}/logo/icon-only.png`"
/>
<img v-else :src="`${$baseUrl}image/theme/${themeActiveSetting.name}/logo/all.png`" />
<img class="zlogos" :src="`/image/logo.png`" />
<div>亿百分营销管理系统</div>
</router-link>-->
<!-- <div class="toggle-aside-btn" @click="handleToggleAside" flex-box="0">
<d2-icon name="bars" />
</div>-->
<d2-menu-header class="header-menus" flex-box="1" />
<!-- 顶栏右侧 -->
<div class="d2-header-right" flex-box="0">
<!-- 如果你只想在开发环境显示这个按钮请添加 v-if="$env === 'development'" -->
<!-- <d2-header-search @click="handleSearchClick" />
<d2-header-log />
<d2-header-fullscreen />
<d2-header-theme />
<d2-header-size />
<d2-header-locales />
<d2-header-color />-->
<d2-header-user />
</div>
</div>
<!-- 下面 主体 -->
<div class="d2-theme-container" flex-box="1" flex>
<!-- 主体 侧边栏 -->
<!-- <div
flex-box="0"
ref="aside"
class="d2-theme-container-aside"
:style="{
width: asideCollapse ? asideWidthCollapse : asideWidth,
opacity: this.searchActive ? 0.5 : 1
}">
<d2-menu-side/>
</div>-->
<!-- 主体 -->
<div class="d2-theme-container-main" flex-box="1" flex>
<!-- 搜索 -->
<!-- <transition name="fade-scale">
<div v-if="searchActive" class="d2-theme-container-main-layer" flex>
<d2-panel-search ref="panelSearch" @close="searchPanelClose" />
</div>
</transition>-->
<!-- 内容 -->
<transition name="fade-scale">
<div v-if="!searchActive" class="d2-theme-container-main-layer" flex="dir:top">
<!-- tab -->
<!-- <div class="d2-theme-container-main-header" flex-box="0">
<d2-tabs/>
</div>-->
<!-- 页面 -->
<div
class="d2-theme-container-main-body"
flex-box="1"
style="border:0px solid red;margin: 10px 0px 10px 0px;"
>
<transition :name="transitionActive ? 'fade-transverse' : ''">
<keep-alive :include="keepAlive">
<router-view />
</keep-alive>
</transition>
</div>
</div>
</transition>
</div>
</div>
</div>
</div>
</template>
<script>
import d2MenuSide from './components/menu-side'
import d2MenuHeader from './components/menu-header'
import d2Tabs from './components/tabs'
import d2HeaderFullscreen from './components/header-fullscreen'
import d2HeaderLocales from './components/header-locales'
import d2HeaderSearch from './components/header-search'
import d2HeaderSize from './components/header-size'
import d2HeaderTheme from './components/header-theme'
import d2HeaderUser from './components/header-user'
import d2HeaderLog from './components/header-log'
import d2HeaderColor from './components/header-color'
import { mapState, mapGetters, mapActions } from 'vuex'
import mixinSearch from './mixins/search'
export default {
name: 'd2-layout-header-aside',
mixins: [mixinSearch],
components: {
d2MenuSide,
d2MenuHeader,
d2Tabs,
d2HeaderFullscreen,
d2HeaderLocales,
d2HeaderSearch,
d2HeaderSize,
d2HeaderTheme,
d2HeaderUser,
d2HeaderLog,
d2HeaderColor
},
data () {
return {
// [侧边栏宽度] 正常状态
asideWidth: '200px',
// [侧边栏宽度] 折叠状态
asideWidthCollapse: '65px'
}
},
computed: {
...mapState('d2admin', {
keepAlive: state => state.page.keepAlive,
grayActive: state => state.gray.active,
transitionActive: state => state.transition.active,
asideCollapse: state => state.menu.asideCollapse
}),
...mapGetters('d2admin', {
themeActiveSetting: 'theme/activeSetting'
}),
/**
* @description 最外层容器的背景图片样式
*/
styleLayoutMainGroup () {
return {
...(this.themeActiveSetting.backgroundImage
? {
backgroundImage: `url('${this.$baseUrl}${this.themeActiveSetting.backgroundImage}')`
}
: {})
}
}
},
methods: {
...mapActions('d2admin/menu', ['asideCollapseToggle']),
/**
* 接收点击切换侧边栏的按钮
*/
handleToggleAside () {
this.asideCollapseToggle()
}
}
}
</script>
<style lang="scss">
// 注册主题
@import "~@/assets/style/theme/register.scss";
</style>
<style lang="scss" scoped>
.zlogos {
height: 60px;
width: 300px;
padding-left: 20px;
object-fit: cover;
}
.d2-theme-header{
background-color: #4E59C7;
// background-color: red;
}
.header-menus{
color: #E8E9FF !important;
// background-color: red;
}
</style>
import { mapState, mapMutations } from 'vuex'
import hotkeys from 'hotkeys-js'
export default {
components: {
'd2-panel-search': () => import('../components/panel-search')
},
mounted () {
// 绑定搜索功能快捷键 [ 打开 ]
hotkeys(this.searchHotkey.open, event => {
event.preventDefault()
this.searchPanelOpen()
})
// 绑定搜索功能快捷键 [ 关闭 ]
hotkeys(this.searchHotkey.close, event => {
event.preventDefault()
this.searchPanelClose()
})
},
beforeDestroy () {
hotkeys.unbind(this.searchHotkey.open)
hotkeys.unbind(this.searchHotkey.close)
},
computed: {
...mapState('d2admin', {
searchActive: state => state.search.active,
searchHotkey: state => state.search.hotkey
})
},
methods: {
...mapMutations({
searchToggle: 'd2admin/search/toggle',
searchSet: 'd2admin/search/set'
}),
/**
* 接收点击搜索按钮
*/
handleSearchClick () {
this.searchToggle()
if (this.searchActive) {
setTimeout(() => {
if (this.$refs.panelSearch) {
this.$refs.panelSearch.focus()
}
}, 500)
}
},
searchPanelOpen () {
if (!this.searchActive) {
this.searchSet(true)
setTimeout(() => {
if (this.$refs.panelSearch) {
this.$refs.panelSearch.focus()
}
}, 500)
}
},
// 关闭搜索面板
searchPanelClose () {
if (this.searchActive) {
this.searchSet(false)
}
}
}
}
import Cookies from 'js-cookie'
const cookies = {}
/**
* @description 存储 cookie 值
* @param {String} name cookie name
* @param {String} value cookie value
* @param {Object} setting cookie setting
*/
cookies.set = function (name = 'default', value = '', cookieSetting = {}) {
let currentCookieSetting = {
expires: 1
}
Object.assign(currentCookieSetting, cookieSetting)
Cookies.set(`d2admin-${process.env.VUE_APP_VERSION}-${name}`, value, currentCookieSetting)
}
/**
* @description 拿到 cookie 值
* @param {String} name cookie name
*/
cookies.get = function (name = 'default') {
return Cookies.get(`d2admin-${process.env.VUE_APP_VERSION}-${name}`)
}
/**
* @description 拿到 cookie 全部的值
*/
cookies.getAll = function () {
return Cookies.get()
}
/**
* @description 删除 cookie
* @param {String} name cookie name
*/
cookies.remove = function (name = 'default') {
return Cookies.remove(`d2admin-${process.env.VUE_APP_VERSION}-${name}`)
}
export default cookies
import low from 'lowdb'
import LocalStorage from 'lowdb/adapters/LocalStorage'
import util from '@/libs/util'
import { cloneDeep } from 'lodash'
const adapter = new LocalStorage(`d2admin-${process.env.VUE_APP_VERSION}`)
const db = low(adapter)
db
.defaults({
sys: {},
database: {}
})
.write()
export default db
/**
* @description 检查路径是否存在 不存在的话初始化
* @param {Object} payload dbName {String} 数据库名称
* @param {Object} payload path {String} 路径
* @param {Object} payload user {Boolean} 区分用户
* @param {Object} payload validator {Function} 数据校验钩子 返回 true 表示验证通过
* @param {Object} payload defaultValue {*} 初始化默认值
* @returns {String} 可以直接使用的路径
*/
export function pathInit ({
dbName = 'database',
path = '',
user = true,
validator = () => true,
defaultValue = ''
}) {
const uuid = util.cookies.get('uuid') || 'ghost-uuid'
const currentPath = `${dbName}.${user ? `user.${uuid}` : 'public'}${path ? `.${path}` : ''}`
const value = db.get(currentPath).value()
if (!(value !== undefined && validator(value))) {
db
.set(currentPath, defaultValue)
.write()
}
return currentPath
}
/**
* @description 将数据存储到指定位置 | 路径不存在会自动初始化
* @description 效果类似于取值 dbName.path = value
* @param {Object} payload dbName {String} 数据库名称
* @param {Object} payload path {String} 存储路径
* @param {Object} payload value {*} 需要存储的值
* @param {Object} payload user {Boolean} 是否区分用户
*/
export function dbSet ({
dbName = 'database',
path = '',
value = '',
user = false
}) {
db.set(pathInit({
dbName,
path,
user
}), value).write()
}
/**
* @description 获取数据
* @description 效果类似于取值 dbName.path || defaultValue
* @param {Object} payload dbName {String} 数据库名称
* @param {Object} payload path {String} 存储路径
* @param {Object} payload defaultValue {*} 取值失败的默认值
* @param {Object} payload user {Boolean} 是否区分用户
*/
export function dbGet ({
dbName = 'database',
path = '',
defaultValue = '',
user = false
}) {
return new Promise(resolve => {
resolve(cloneDeep(db.get(pathInit({
dbName,
path,
user,
defaultValue
})).value()))
})
}
/**
* @description 获取存储数据库对象
* @param {Object} payload user {Boolean} 是否区分用户
*/
export function database ({
dbName = 'database',
path = '',
user = false,
validator = () => true,
defaultValue = ''
} = {}) {
return new Promise(resolve => {
resolve(db.get(pathInit({
dbName, path, user, validator, defaultValue
})))
})
}
module.exports = file => require('@/views/' + file).default
module.exports = file => () => import('@/views/' + file)
import cookies from './util.cookies'
import db from './util.db'
import log from './util.log'
const util = {
cookies,
db,
log
}
/**
* @description 更新标题
* @param {String} title 标题
*/
util.title = function (titleText) {
const processTitle = process.env.VUE_APP_TITLE || 'D2Admin'
window.document.title = `${processTitle}${titleText ? ` | ${titleText}` : ''}`
}
/**
* @description 打开新页面
* @param {String} url 地址
*/
util.open = function (url) {
var a = document.createElement('a')
a.setAttribute('href', url)
a.setAttribute('target', '_blank')
a.setAttribute('id', 'd2admin-link-temp')
document.body.appendChild(a)
a.click()
document.body.removeChild(document.getElementById('d2admin-link-temp'))
}
export default util
const log = {}
/**
* @description 返回这个样式的颜色值
* @param {String} type 样式名称 [ primary | success | warning | danger | text ]
*/
function typeColor (type = 'default') {
let color = ''
switch (type) {
case 'default': color = '#35495E'; break
case 'primary': color = '#3488ff'; break
case 'success': color = '#43B883'; break
case 'warning': color = '#e6a23c'; break
case 'danger': color = '#f56c6c'; break
default:; break
}
return color
}
/**
* @description 打印一个 [ title | text ] 样式的信息
* @param {String} title title text
* @param {String} info info text
* @param {String} type style
*/
log.capsule = function (title, info, type = 'primary') {
console.log(
`%c ${title} %c ${info} %c`,
'background:#35495E; padding: 1px; border-radius: 3px 0 0 3px; color: #fff;',
`background:${typeColor(type)}; padding: 1px; border-radius: 0 3px 3px 0; color: #fff;`,
'background:transparent'
)
}
/**
* @description 打印彩色文字
*/
log.colorful = function (textArr) {
console.log(
`%c${textArr.map(t => t.text || '').join('%c')}`,
...textArr.map(t => `color: ${typeColor(t.type)};`)
)
}
/**
* @description 打印 default 样式的文字
*/
log.default = function (text) {
log.colorful([{ text }])
}
/**
* @description 打印 primary 样式的文字
*/
log.primary = function (text) {
log.colorful([{ text, type: 'primary' }])
}
/**
* @description 打印 success 样式的文字
*/
log.success = function (text) {
log.colorful([{ text, type: 'success' }])
}
/**
* @description 打印 warning 样式的文字
*/
log.warning = function (text) {
log.colorful([{ text, type: 'warning' }])
}
/**
* @description 打印 danger 样式的文字
*/
log.danger = function (text) {
log.colorful([{ text, type: 'danger' }])
}
export default log
{
"_element": "en",
"_name": "English",
"page": {
"demo": {
"playground": {
"locales": {
"text": "D2Admin is a fully open source and free enterprise back-end product front-end integration solution, using the latest front-end technology stack, has prepared most of the project preparations, and with a lot of sample code to help the management system agile development."
}
}
}
}
}
{
"_element": "ja",
"_name": "日本語",
"page": {
"demo": {
"playground": {
"locales": {
"text": "D2Adminは、最新のフロントエンドテクノロジースタックを使用した、完全にオープンソースの無料エンタープライズバックエンド製品フロントエンド統合ソリューションであり、プロジェクトのほとんどの準備を整えており、システムのアジャイル開発の管理に役立つ多くのサンプルコードを備えています。"
}
}
}
}
}
export default {
methods: {
onChangeLocale (command) {
this.$i18n.locale = command
let message = `当前语言:${this.$t('_name')} [ ${this.$i18n.locale} ]`
if (process.env.VUE_APP_BUILD_MODE === 'PREVIEW') {
message = [
`当前语言:${this.$t('_name')} [ ${this.$i18n.locale} ]`,
`仅提供切换功能,没有配置具体的语言数据 `,
`文档参考:<a class="el-link el-link--primary is-underline" target="_blank" href="https://d2.pub/zh/doc/d2-admin/locales">《国际化 | D2Admin》</a>`
].join('<br/>')
}
this.$notify({
title: '语言变更',
dangerouslyUseHTMLString: true,
message
})
}
}
}
{
"_element": "zh-CN",
"_name": "简体中文",
"page": {
"demo": {
"playground": {
"locales": {
"text": "D2Admin 是一个完全 开源免费 的企业中后台产品前端集成方案,使用最新的前端技术栈,已经做好大部分项目前期准备工作,并且带有大量示例代码,助力管理系统敏捷开发。"
}
}
}
}
}
{
"_element": "zh-TW",
"_name": "繁體中文",
"page": {
"demo": {
"playground": {
"locales": {
"text": "D2Admin 是一個完全 開源免費 的企業中後台產品前端集成方案,使用最新的前端技術棧,已經做好大部分項目前期準備工作,並且帶有大量示例代碼,助力管理系統敏捷開發。"
}
}
}
}
}
// Vue
import Vue from 'vue'
import App from './App.vue'
import i18n from './i18n'
import App from './App'
// 核心插件
import d2Admin from '@/plugin/d2admin'
// store
import store from '@/store/index'
// 菜单和路由设置
import router from './router'
import store from './store'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import menuHeader from '@/menu/header'
import menuAside from '@/menu/aside'
import { frameInRoutes } from '@/router/routes'
Vue.use(ElementUI);
Vue.config.productionTip = false
// 核心插件
Vue.use(d2Admin)
new Vue({
router,
store,
render: h => h(App)
i18n,
render: h => h(App),
created () {
// 处理路由 得到每一级的路由设置
this.$store.commit('d2admin/page/init', frameInRoutes)
// 设置顶栏菜单
this.$store.commit('d2admin/menu/headerSet', menuHeader)
// 设置侧边栏菜单
this.$store.commit('d2admin/menu/asideSet', menuAside)
// 初始化菜单搜索功能
this.$store.commit('d2admin/search/init', menuHeader)
},
mounted () {
// 展示系统信息
this.$store.commit('d2admin/releases/versionShow')
// 用户登录后从数据库加载一系列的设置
this.$store.dispatch('d2admin/account/load')
// 获取并记录用户 UA
this.$store.commit('d2admin/ua/get')
// 初始化全屏监听
this.$store.dispatch('d2admin/fullscreen/listen')
}
}).$mount('#app')
// 菜单 侧边栏
// export default [
// { path: '/index', title: '首页', icon: 'home' },
// {
// title: '页面',
// icon: 'folder-o',
// children: [
// { path: '/page1', title: '页面 1' },
// { path: '/page2', title: '页面 2' },
// { path: '/page3', title: '页面 3' },
// { path: '/page-demo', title: '新建示例' }
// ]
// }
// ]
// 菜单 顶栏
export default [
// { path: '/index', title: '首页', icon: 'home' },
// {
// title: '页面',
// icon: 'folder-o',
// children: [
// { path: '/page1', title: '页面 1' },
// { path: '/page2', title: '页面 2' },
// { path: '/page3', title: '页面 3' },
// { path: '/page-demo', title: '新建示例' }
// ]
// },
{
path: '/home/main',
title: '首页',
icon: ''
},
{
path: '/in/contact',
title: '进件管理',
icon: ''
},
{
path: '/active/mode',
title: '活动模版管理',
icon: ''
},
{
path: '/task/bar',
title: '任务管理',
icon: ''
},
{
path: '/goods/main',
title: '活动商品',
icon: ''
}
]
const userDB = [
{ username: 'admin', password: 'admin', uuid: 'admin-uuid', name: 'Admin' },
{ username: 'editor', password: 'editor', uuid: 'editor-uuid', name: 'Editor' },
{ username: 'user1', password: 'user1', uuid: 'user1-uuid', name: 'User1' }
]
export default [
{
path: '/api/login',
method: 'post',
handle ({ body }) {
const user = userDB.find(e => e.username === body.username && e.password === body.password)
if (user) {
return {
code: 0,
msg: '登录成功',
data: {
...user,
token: '8dfhassad0asdjwoeiruty'
}
}
} else {
return {
code: 401,
msg: '用户名或密码错误',
data: {}
}
}
}
}
]
import Mock from 'mockjs'
import qs from 'qs'
import withCredentials from './patch/withCredentials'
/* 补丁 */
withCredentials(Mock)
/* Mock 默认配置 */
Mock.setup({ timeout: '200-300' })
/* 扩展 [生成器] */
const Generator = (prop, template) => {
const obj = {}
obj[prop] = [template]
return Mock.mock(obj)
}
/* 扩展 [循环] */
const Repeat = (num, itemTemplate) => Generator(`data|${num}`, itemTemplate).data
const CustomExtends = {
Generator,
Repeat,
Mock,
Random: Mock.Random
}
const extend = (prop, value) => {
CustomExtends[prop] = value
}
/* 装配配置组 */
const wired = ({ url, type, body }) => ({
method: type,
params: qs.parse(url.split('?').length > 1 ? url.split('?')[1] : ''),
body: JSON.parse(body),
url: qs.parse(url.split('?')[0]),
...CustomExtends
})
const setup = (path, method, handle) => {
Mock.mock(
RegExp(path),
method,
typeof handle === 'function' ? o => handle(wired(o)) : handle
)
}
const load = (collection) => {
collection.map(({ path, method, handle }) => {
if (method === '*') {
method = [
'get',
'head',
'post',
'put',
'delete',
'connect',
'options',
'trace',
'patch'
]
}
if (typeof method === 'string' && method.indexOf('|') > -1) method = method.split('|')
if (method instanceof Array) {
method.map(item => setup(path, item, handle))
} else {
setup(path, method, handle)
}
})
}
export default { setup, load, extend }
export default function (Mock) {
// http://cnine.me/note/FrontEnd/mock-lose-cookies-dbg.html
Mock.XHR.prototype.__send = Mock.XHR.prototype.send
Mock.XHR.prototype.send = function () {
if (this.custom.xhr) {
this.custom.xhr.withCredentials = this.withCredentials || false
this.custom.xhr.responseType = this.responseType
}
this.__send.apply(this, arguments)
}
}
import d2Mock from './d2-mock'
const req = context => context.keys().map(context)
const options = req(require.context('./api/', true, /\.js$/))
.filter(e => e.default)
.map(e => e.default)
options.forEach(option => {
d2Mock.load(option)
})
<template>
<d2-container>
<template slot="header">header</template>
active/mode/index.vue
<template slot="footer">footer</template>
</d2-container>
</template>
<template>
<d2-container>
<template slot="header">header</template>
active/shop/index.vue
<template slot="footer">footer</template>
</d2-container>
</template>
<template>
<d2-container>
<template slot="header">header</template>
goods/main/index.vue
<template slot="footer">footer</template>
</d2-container>
</template>
<template>
<d2-container>
<template slot="header">header</template>
home/main/index.vue
<template slot="footer">footer</template>
</d2-container>
</template>
<template>
<d2-container>
<template slot="header">header</template>
in/bar/index.vue
<template slot="footer">footer</template>
</d2-container>
</template>
<template>
<d2-container>
<!-- <template slot="header">header</template> -->
in/contact/index.vue
<!-- <template slot="footer">footer</template> -->
</d2-container>
</template>
<template>
<d2-container>
<template slot="header">header</template>
in/shop/index.vue
<template slot="footer">footer</template>
</d2-container>
</template>
<template>
<d2-container>
<template slot="header">header</template>
Hello World
<template slot="footer">footer</template>
</d2-container>
</template>
<template>
<d2-container>
<template slot="header">header</template>
task/bar/index.vue
<template slot="footer">footer</template>
</d2-container>
</template>
<template>
<d2-container>
<template slot="header">header</template>
task/com/index.vue
<template slot="footer">footer</template>
</d2-container>
</template>
<template>
<d2-container>
<template slot="header">header</template>
task/count/index.vue
<template slot="footer">footer</template>
</d2-container>
</template>
import store from '@/store'
import axios from 'axios'
import { Message } from 'element-ui'
import util from '@/libs/util'
// 创建一个错误
function errorCreate (msg) {
const error = new Error(msg)
errorLog(error)
throw error
}
// 记录和显示错误
function errorLog (error) {
// 添加到日志
store.dispatch('d2admin/log/push', {
message: '数据请求异常',
type: 'danger',
meta: {
error
}
})
// 打印到控制台
if (process.env.NODE_ENV === 'development') {
util.log.danger('>>>>>> Error >>>>>>')
console.log(error)
}
// 显示提示
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
}
// 创建一个 axios 实例
const service = axios.create({
baseURL: process.env.VUE_APP_API,
timeout: 5000 // 请求超时时间
})
// 请求拦截器
service.interceptors.request.use(
config => {
// 在请求发送之前做一些处理
const token = util.cookies.get('token')
// 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
config.headers['X-Token'] = token
return config
},
error => {
// 发送失败
console.log(error)
return Promise.reject(error)
}
)
// 响应拦截器
service.interceptors.response.use(
response => {
// dataAxios 是 axios 返回数据中的 data
const dataAxios = response.data
// 这个状态码是和后端约定的
const { code } = dataAxios
// 根据 code 进行判断
if (code === undefined) {
// 如果没有 code 代表这不是项目后端开发的接口 比如可能是 D2Admin 请求最新版本
return dataAxios
} else {
// 有 code 代表这是一个后端接口 可以进行进一步的判断
switch (code) {
case 0:
// [ 示例 ] code === 0 代表没有错误
return dataAxios.data
case 'xxx':
// [ 示例 ] 其它和后台约定的 code
errorCreate(`[ code: xxx ] ${dataAxios.msg}: ${response.config.url}`)
break
default:
// 不是正确的 code
errorCreate(`${dataAxios.msg}: ${response.config.url}`)
break
}
}
},
error => {
if (error && error.response) {
switch (error.response.status) {
case 400: error.message = '请求错误'; break
case 401: error.message = '未授权,请登录'; break
case 403: error.message = '拒绝访问'; break
case 404: error.message = `请求地址出错: ${error.response.config.url}`; break
case 408: error.message = '请求超时'; break
case 500: error.message = '服务器内部错误'; break
case 501: error.message = '服务未实现'; break
case 502: error.message = '网关错误'; break
case 503: error.message = '服务不可用'; break
case 504: error.message = '网关超时'; break
case 505: error.message = 'HTTP版本不受支持'; break
default: break
}
}
errorLog(error)
return Promise.reject(error)
}
)
export default service
// Element
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
// flex 布局库
import 'flex.css'
// 组件
import '@/components'
// svg 图标
import '@/assets/svg-icons'
// 国际化
import i18n from '@/i18n.js'
// 功能插件
import pluginError from '@/plugin/error'
import pluginLog from '@/plugin/log'
import pluginOpen from '@/plugin/open'
export default {
async install (Vue, options) {
// 设置为 false 以阻止 vue 在启动时生成生产提示
// https://cn.vuejs.org/v2/api/#productionTip
Vue.config.productionTip = false
// 当前环境
Vue.prototype.$env = process.env.NODE_ENV
// 当前的 baseUrl
Vue.prototype.$baseUrl = process.env.BASE_URL
// 当前版本
Vue.prototype.$version = process.env.VUE_APP_VERSION
// 构建时间
Vue.prototype.$buildTime = process.env.VUE_APP_BUILD_TIME
// Element
Vue.use(ElementUI, {
i18n: (key, value) => i18n.t(key, value)
})
// 插件
Vue.use(pluginError)
Vue.use(pluginLog)
Vue.use(pluginOpen)
}
}
import store from '@/store'
import util from '@/libs/util'
export default {
install (Vue, options) {
Vue.config.errorHandler = function (error, instance, info) {
Vue.nextTick(() => {
// store 追加 log
store.dispatch('d2admin/log/push', {
message: `${info}: ${error.message}`,
type: 'danger',
meta: {
error,
instance
}
})
// 只在开发模式下打印 log
if (process.env.NODE_ENV === 'development') {
util.log.capsule('D2Admin', 'ErrorHandler', 'danger')
util.log.danger('>>>>>> 错误信息 >>>>>>')
console.log(info)
util.log.danger('>>>>>> Vue 实例 >>>>>>')
console.log(instance)
util.log.danger('>>>>>> Error >>>>>>')
console.log(error)
}
})
}
}
}
import store from '@/store'
import util from '@/libs/util'
export default {
install (Vue, options) {
// 快速打印 log
Vue.prototype.$log = {
...util.log,
push (data) {
if (typeof data === 'string') {
// 如果传递来的数据是字符串
// 赋值给 message 字段
// 为了方便使用
// eg: this.$log.push('foo text')
store.dispatch('d2admin/log/push', {
message: data
})
} else if (typeof data === 'object') {
// 如果传递来的数据是对象
store.dispatch('d2admin/log/push', data)
}
}
}
}
}
import util from '@/libs/util'
export default {
install (Vue, options) {
Vue.prototype.$open = util.open
}
}
import Vue from 'vue'
import VueRouter from 'vue-router'
// import Home from '../views/Home.vue'
Vue.use(VueRouter)
// 进度条
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import store from '@/store/index'
import util from '@/libs/util.js'
// 路由数据
import routes from './routes'
const routes = [
// {
// path: '/',
// name: 'home',
// component: Home
// },
// {
// path: '/about',
// name: 'about',
// // route level code-splitting
// // this generates a separate chunk (about.[hash].js) for this route
// // which is lazy-loaded when the route is visited.
// component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
// }
]
// fix vue-router NavigationDuplicated
const VueRouterPush = VueRouter.prototype.push
VueRouter.prototype.push = function push (location) {
return VueRouterPush.call(this, location).catch(err => err)
}
const VueRouterReplace = VueRouter.prototype.replace
VueRouter.prototype.replace = function replace (location) {
return VueRouterReplace.call(this, location).catch(err => err)
}
Vue.use(VueRouter)
// 导出路由 在 main.js 里使用
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
/**
* 路由拦截
* 权限验证
*/
router.beforeEach(async (to, from, next) => {
// 确认已经加载多标签页数据 https://github.com/d2-projects/d2-admin/issues/201
await store.dispatch('d2admin/page/isLoaded')
// 确认已经加载组件尺寸设置 https://github.com/d2-projects/d2-admin/issues/198
await store.dispatch('d2admin/size/isLoaded')
// 进度条
NProgress.start()
// 关闭搜索面板
store.commit('d2admin/search/set', false)
// 验证当前路由所有的匹配中是否需要有登录验证的
if (to.matched.some(r => r.meta.auth)) {
// 这里暂时将cookie里是否存有token作为验证是否登录的条件
// 请根据自身业务需要修改
const token = util.cookies.get('token')
if (token && token !== 'undefined') {
next()
} else {
// 没有登录的时候跳转到登录界面
// 携带上登陆成功之后需要跳转的页面完整路径
next({
name: 'login',
query: {
redirect: to.fullPath
}
})
// https://github.com/d2-projects/d2-admin/issues/138
NProgress.done()
}
} else {
// 不需要身份校验 直接通过
next()
}
})
router.afterEach(to => {
// 进度条
NProgress.done()
// 多页控制 打开新的页面
store.dispatch('d2admin/page/open', to)
// 更改标题
util.title(to.meta.title)
})
export default router
import layoutHeaderAside from '@/layout/header-aside'
// 由于懒加载页面太多的话会造成webpack热更新太慢,所以开发环境不使用懒加载,只有生产环境使用懒加载
const _import = require('@/libs/util.import.' + process.env.NODE_ENV)
/**
* 在主框架内显示
*/
const frameIn = [
{
path: '/',
// redirect: { name: 'index' },
redirect: { name: 'homeMain' },
component: layoutHeaderAside,
children: [
// 首页
{
path: 'index',
name: 'index',
meta: {
auth: true
},
component: _import('system/index')
},
// Z-首页-首页
{
path: '/home/main',
name: 'homeMain',
component: () => import('@/pages/home/main'),
meta: {
auth: true,
title: '首页'
}
},
// Z-进件管理-通讯录管理
{
path: '/in/contact',
name: 'inContact',
component: () => import('@/pages/in/contact'),
meta: {
auth: true,
title: '通讯录管理'
}
},
// Z-进件管理-通讯录管理
{
path: '/in/bar',
name: 'inBar',
component: () => import('@/pages/in/bar'),
meta: {
auth: true,
title: '柜组管理'
}
},
// Z-进件管理-通讯录管理
{
path: '/in/shop',
name: 'inShop',
component: () => import('@/pages/in/shop'),
meta: {
auth: true,
title: '门店管理'
}
},
// Z-活动模版管理-模版中心
{
path: '/active/mode',
name: 'activeMode',
component: () => import('@/pages/active/mode'),
meta: {
auth: true,
title: '模版中心'
}
},
// Z-活动模版管理-模版商城
{
path: '/active/shop',
name: 'activeMode',
component: () => import('@/pages/active/shop'),
meta: {
auth: true,
title: '模版商城'
}
},
// Z-任务管理-柜组任务
{
path: '/task/bar',
name: 'taskBar',
component: () => import('@/pages/task/bar'),
meta: {
auth: true,
title: '柜组任务'
}
},
// Z-任务管理-集团任务
{
path: '/task/com',
name: 'taskCom',
component: () => import('@/pages/task/com'),
meta: {
auth: true,
title: '集团任务'
}
},
// Z-任务管理-任务统计
{
path: '/task/count',
name: 'taskCount',
component: () => import('@/pages/task/count'),
meta: {
auth: true,
title: '任务统计'
}
},
// Z-活动商品-活动商品
{
path: '/goods/main',
name: 'goodsMain',
component: () => import('@/pages/goods/main'),
meta: {
auth: true,
title: '活动商品'
}
},
// 演示页面
{
path: 'page1',
name: 'page1',
meta: {
title: '页面 1',
auth: true
},
component: _import('demo/page1')
},
{
path: 'page2',
name: 'page2',
meta: {
title: '页面 2',
auth: true
},
component: _import('demo/page2')
},
{
path: 'page3',
name: 'page3',
meta: {
title: '页面 3',
auth: true
},
component: _import('demo/page3')
},
{
path: '/page-demo',
name: 'page-demo',
component: () => import('@/pages/page-demo'),
meta: {
auth: true,
title: '新建示例'
}
},
// 系统 前端日志
{
path: 'log',
name: 'log',
meta: {
title: '前端日志',
auth: true
},
component: _import('system/log')
},
// 刷新页面 必须保留
{
path: 'refresh',
name: 'refresh',
hidden: true,
component: _import('system/function/refresh')
},
// 页面重定向 必须保留
{
path: 'redirect/:route*',
name: 'redirect',
hidden: true,
component: _import('system/function/redirect')
}
]
}
]
/**
* 在主框架之外显示
*/
const frameOut = [
// 登录
{
path: '/login',
name: 'login',
component: _import('system/login')
}
]
/**
* 错误页面
*/
const errorPage = [
{
path: '*',
name: '404',
component: _import('system/error/404')
}
]
// 导出需要显示菜单的
export const frameInRoutes = frameIn
// 重新组织后导出
export default [
...frameIn,
...frameOut,
...errorPage
]
export default {
// 快捷键
// 支持快捷键 例如 ctrl+shift+s
hotkey: {
search: {
open: 's',
close: 'esc'
}
},
// 侧边栏默认折叠状态
menu: {
asideCollapse: false
},
// 在读取持久化数据失败时默认页面
page: {
opened: [
{
name: 'index',
fullPath: '/index',
meta: {
title: '首页',
auth: false
}
}
]
},
// 菜单搜索
search: {
enable: true
},
// 注册的主题
theme: {
list: [
{
title: 'd2admin 经典',
name: 'd2',
preview: 'image/theme/d2/preview@2x.png'
},
{
title: '紫罗兰',
name: 'violet',
preview: 'image/theme/violet/preview@2x.png'
},
{
title: '简约线条',
name: 'line',
backgroundImage: 'image/theme/line/bg.jpg',
preview: 'image/theme/line/preview@2x.png'
},
{
title: '流星',
name: 'star',
backgroundImage: 'image/theme/star/bg.jpg',
preview: 'image/theme/star/preview@2x.png'
},
{
title: 'Tomorrow Night Blue (vsCode)',
name: 'tomorrow-night-blue',
preview: 'image/theme/tomorrow-night-blue/preview@2x.png'
}
]
},
// 是否默认开启页面切换动画
transition: {
active: true
}
}
import Vue from 'vue'
import Vuex from 'vuex'
import d2admin from './modules/d2admin'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
d2admin
}
})
/**
* The file enables `@/store/index.js` to import all vuex modules
* in a one-shot manner. There should not be any reason to edit this file.
*/
const files = require.context('./modules', false, /\.js$/)
const modules = {}
files.keys().forEach(key => {
modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default
})
export default {
namespaced: true,
modules
}
import { Message, MessageBox } from 'element-ui'
import util from '@/libs/util.js'
import router from '@/router'
import { AccountLogin } from '@api/sys.login'
export default {
namespaced: true,
actions: {
/**
* @description 登录
* @param {Object} context
* @param {Object} payload username {String} 用户账号
* @param {Object} payload password {String} 密码
* @param {Object} payload route {Object} 登录成功后定向的路由对象 任何 vue-router 支持的格式
*/
login ({ dispatch }, {
username = '',
password = ''
} = {}) {
return new Promise((resolve, reject) => {
// 开始请求登录接口
AccountLogin({
username,
password
})
.then(async res => {
// 设置 cookie 一定要存 uuid 和 token 两个 cookie
// 整个系统依赖这两个数据进行校验和存储
// uuid 是用户身份唯一标识 用户注册的时候确定 并且不可改变 不可重复
// token 代表用户当前登录状态 建议在网络请求中携带 token
// 如有必要 token 需要定时更新,默认保存一天
util.cookies.set('uuid', res.uuid)
util.cookies.set('token', res.token)
// 设置 vuex 用户信息
await dispatch('d2admin/user/set', {
name: res.name
}, { root: true })
// 用户登录后从持久化数据加载一系列的设置
await dispatch('load')
// 结束
resolve()
})
.catch(err => {
console.log('err: ', err)
reject(err)
})
})
},
/**
* @description 注销用户并返回登录页面
* @param {Object} context
* @param {Object} payload confirm {Boolean} 是否需要确认
*/
logout ({ commit, dispatch }, { confirm = false } = {}) {
/**
* @description 注销
*/
async function logout () {
// 删除cookie
util.cookies.remove('token')
util.cookies.remove('uuid')
// 清空 vuex 用户信息
await dispatch('d2admin/user/set', {}, { root: true })
// 跳转路由
router.push({
name: 'login'
})
}
// 判断是否需要确认
if (confirm) {
commit('d2admin/gray/set', true, { root: true })
MessageBox.confirm('确定要注销当前用户吗', '注销用户', {
type: 'warning'
})
.then(() => {
commit('d2admin/gray/set', false, { root: true })
logout()
})
.catch(() => {
commit('d2admin/gray/set', false, { root: true })
Message({
message: '取消注销操作'
})
})
} else {
logout()
}
},
/**
* @description 用户登录后从持久化数据加载一系列的设置
* @param {Object} context
*/
load ({ dispatch }) {
return new Promise(async resolve => {
// DB -> store 加载用户名
await dispatch('d2admin/user/load', null, { root: true })
// DB -> store 加载主题
await dispatch('d2admin/theme/load', null, { root: true })
// DB -> store 加载页面过渡效果设置
await dispatch('d2admin/transition/load', null, { root: true })
// DB -> store 持久化数据加载上次退出时的多页列表
await dispatch('d2admin/page/openedLoad', null, { root: true })
// DB -> store 持久化数据加载侧边栏折叠状态
await dispatch('d2admin/menu/asideCollapseLoad', null, { root: true })
// DB -> store 持久化数据加载全局尺寸
await dispatch('d2admin/size/load', null, { root: true })
// DB -> store 持久化数据加载颜色设置
await dispatch('d2admin/color/load', null, { root: true })
// end
resolve()
})
}
}
}
import client from 'webpack-theme-color-replacer/client'
import forElementUI from 'webpack-theme-color-replacer/forElementUI'
export default {
namespaced: true,
state: {
// 颜色
value: process.env.VUE_APP_ELEMENT_COLOR
},
actions: {
/**
* @description 设置颜色
* @param {Object} context
* @param {String} color 尺寸
*/
set ({ state, dispatch, commit }, color) {
return new Promise(async resolve => {
// 记录上个值
const old = state.value
// store 赋值
state.value = color || process.env.VUE_APP_ELEMENT_COLOR
// 持久化
await dispatch('d2admin/db/set', {
dbName: 'sys',
path: 'color.value',
value: state.value,
user: true
}, { root: true })
// 应用
commit('apply', {
oldColor: old,
newColor: state.value
})
// end
resolve()
})
},
/**
* @description 从持久化数据读取颜色设置
* @param {Object} context
*/
load ({ state, dispatch, commit }) {
return new Promise(async resolve => {
// 记录上个值
const old = state.value
// store 赋值
state.value = await dispatch('d2admin/db/get', {
dbName: 'sys',
path: 'color.value',
defaultValue: process.env.VUE_APP_ELEMENT_COLOR,
user: true
}, { root: true })
// 应用
commit('apply', {
oldColor: old,
newColor: state.value
})
// end
resolve()
})
}
},
mutations: {
/**
* @description 将 vuex 中的主题颜色设置应用到系统中
* @param {Object} context
* @param {Object} payload oldColor {String} 旧的颜色
* @param {Object} payload newColor {String} 新颜色
*/
apply (state, { oldColor, newColor }) {
var options = {
oldColors: [...forElementUI.getElementUISeries(oldColor)],
newColors: [...forElementUI.getElementUISeries(newColor)]
}
client.changer.changeColor(options)
}
}
}
import router from '@/router'
import { cloneDeep } from 'lodash'
import { database as getDatabase, dbGet, dbSet } from '@/libs/util.db'
export default {
namespaced: true,
actions: {
/**
* @description 将数据存储到指定位置 | 路径不存在会自动初始化
* @description 效果类似于取值 dbName.path = value
* @param {Object} context
* @param {Object} payload dbName {String} 数据库名称
* @param {Object} payload path {String} 存储路径
* @param {Object} payload value {*} 需要存储的值
* @param {Object} payload user {Boolean} 是否区分用户
*/
set (context, {
dbName = 'database',
path = '',
value = '',
user = false
}) {
dbSet({ dbName, path, value, user })
},
/**
* @description 获取数据
* @description 效果类似于取值 dbName.path || defaultValue
* @param {Object} context
* @param {Object} payload dbName {String} 数据库名称
* @param {Object} payload path {String} 存储路径
* @param {Object} payload defaultValue {*} 取值失败的默认值
* @param {Object} payload user {Boolean} 是否区分用户
*/
get (context, {
dbName = 'database',
path = '',
defaultValue = '',
user = false
}) {
return dbGet({ dbName, path, defaultValue, user })
},
/**
* @description 获取存储数据库对象
* @param {Object} context
* @param {Object} payload user {Boolean} 是否区分用户
*/
database (context, {
user = false
} = {}) {
return getDatabase({
user,
defaultValue: {}
})
},
/**
* @description 清空存储数据库对象
* @param {Object} context
* @param {Object} payload user {Boolean} 是否区分用户
*/
databaseClear (context, {
user = false
} = {}) {
return getDatabase({
user,
validator: () => false,
defaultValue: {}
})
},
/**
* @description 获取存储数据库对象 [ 区分页面 ]
* @param {Object} context
* @param {Object} payload basis {String} 页面区分依据 [ name | path | fullPath ]
* @param {Object} payload user {Boolean} 是否区分用户
*/
databasePage (context, {
basis = 'fullPath',
user = false
} = {}) {
return getDatabase({
path: `$page.${router.app.$route[basis]}`,
user,
defaultValue: {}
})
},
/**
* @description 清空存储数据库对象 [ 区分页面 ]
* @param {Object} context
* @param {Object} payload basis {String} 页面区分依据 [ name | path | fullPath ]
* @param {Object} payload user {Boolean} 是否区分用户
*/
databasePageClear (context, {
basis = 'fullPath',
user = false
} = {}) {
return getDatabase({
path: `$page.${router.app.$route[basis]}`,
user,
validator: () => false,
defaultValue: {}
})
},
/**
* @description 快速将页面当前的数据 ( $data ) 持久化
* @param {Object} context
* @param {Object} payload instance {Object} vue 实例
* @param {Object} payload basis {String} 页面区分依据 [ name | path | fullPath ]
* @param {Object} payload user {Boolean} 是否区分用户
*/
pageSet (context, {
instance,
basis = 'fullPath',
user = false
}) {
return getDatabase({
path: `$page.${router.app.$route[basis]}.$data`,
user,
validator: () => false,
defaultValue: cloneDeep(instance.$data)
})
},
/**
* @description 快速获取页面快速持久化的数据
* @param {Object} context
* @param {Object} payload instance {Object} vue 实例
* @param {Object} payload basis {String} 页面区分依据 [ name | path | fullPath ]
* @param {Object} payload user {Boolean} 是否区分用户
*/
pageGet (context, {
instance,
basis = 'fullPath',
user = false
}) {
return dbGet({
path: `$page.${router.app.$route[basis]}.$data`,
user,
defaultValue: cloneDeep(instance.$data)
})
},
/**
* @description 清空页面快照
* @param {Object} context
* @param {Object} payload basis {String} 页面区分依据 [ name | path | fullPath ]
* @param {Object} payload user {Boolean} 是否区分用户
*/
pageClear (context, {
basis = 'fullPath',
user = false
}) {
return getDatabase({
path: `$page.${router.app.$route[basis]}.$data`,
user,
validator: () => false,
defaultValue: {}
})
}
}
}
import screenfull from 'screenfull'
export default {
namespaced: true,
state: {
// 全屏激活
active: false
},
actions: {
/**
* @description 初始化监听
* @param {Object} context
*/
listen ({ commit }) {
return new Promise(resolve => {
if (screenfull.enabled) {
screenfull.on('change', () => {
console.log('1')
if (!screenfull.isFullscreen) {
commit('set', false)
}
})
}
// end
resolve()
})
},
/**
* @description 切换全屏
* @param {Object} context
*/
toggle ({ commit }) {
return new Promise(resolve => {
if (screenfull.isFullscreen) {
screenfull.exit()
commit('set', false)
} else {
screenfull.request()
commit('set', true)
}
// end
resolve()
})
}
},
mutations: {
/**
* @description 设置 store 里的全屏状态
* @param {Object} state state
* @param {Boolean} active active
*/
set (state, active) {
state.active = active
}
}
}
export default {
namespaced: true,
state: {
// 灰度
active: false
},
mutations: {
/**
* @description 切换灰度状态
* @param {Object} state state
*/
toggle (state) {
state.active = !state.active
},
/**
* @description 设置灰度模式
* @param {Object} state state
* @param {Boolean} active active
*/
set (state, active) {
state.active = active
}
}
}
import dayjs from 'dayjs'
import { get } from 'lodash'
import util from '@/libs/util.js'
export default {
namespaced: true,
state: {
// 错误日志
// + 日志条目的属性
// - message 必须 日志信息
// - type 非必须 类型 success | warning | info(默认) | danger
// - time 必须 日志记录时间
// - meta 非必须 其它携带信息
log: []
},
getters: {
/**
* @description 返回现存 log (all) 的条数
* @param {*} state vuex state
*/
length (state) {
return state.log.length
},
/**
* @description 返回现存 log (error) 的条数
* @param {*} state vuex state
*/
lengthError (state) {
return state.log.filter(log => log.type === 'danger').length
}
},
actions: {
/**
* @description 添加一个日志
* @param {Object} context
* @param {String} param message {String} 信息
* @param {String} param type {String} 类型
* @param {Object} payload meta {Object} 附带的信息
*/
push ({ rootState, commit }, { message, type = 'info', meta }) {
commit('push', {
message,
type,
time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
meta: {
// 当前用户信息
user: rootState.d2admin.user.info,
// 当前用户的 uuid
uuid: util.cookies.get('uuid'),
// 当前的 token
token: util.cookies.get('token'),
// 当前地址
url: get(window, 'location.href', ''),
// 用户设置
...meta
}
})
}
},
mutations: {
/**
* @description 添加日志
* @param {Object} state state
* @param {Object} log data
*/
push (state, log) {
state.log.push(log)
},
/**
* @description 清空日志
* @param {Object} state state
*/
clean (state) {
// store 赋值
state.log = []
}
}
}
import { uniqueId } from 'lodash'
// 设置文件
import setting from '@/setting.js'
/**
* 给菜单数据补充上 path 字段
* https://github.com/d2-projects/d2-admin/issues/209
* @param {Array} menu 原始的菜单数据
*/
function supplementMenuPath (menu) {
return menu.map(e => ({
...e,
path: e.path || uniqueId('d2-menu-empty-'),
...e.children ? {
children: supplementMenuPath(e.children)
} : {}
}))
}
export default {
namespaced: true,
state: {
// 顶栏菜单
header: [],
// 侧栏菜单
aside: [],
// 侧边栏收缩
asideCollapse: setting.menu.asideCollapse
},
actions: {
/**
* 设置侧边栏展开或者收缩
* @param {Object} context
* @param {Boolean} collapse is collapse
*/
asideCollapseSet ({ state, dispatch }, collapse) {
return new Promise(async resolve => {
// store 赋值
state.asideCollapse = collapse
// 持久化
await dispatch('d2admin/db/set', {
dbName: 'sys',
path: 'menu.asideCollapse',
value: state.asideCollapse,
user: true
}, { root: true })
// end
resolve()
})
},
/**
* 切换侧边栏展开和收缩
* @param {Object} context
*/
asideCollapseToggle ({ state, dispatch }) {
return new Promise(async resolve => {
// store 赋值
state.asideCollapse = !state.asideCollapse
// 持久化
await dispatch('d2admin/db/set', {
dbName: 'sys',
path: 'menu.asideCollapse',
value: state.asideCollapse,
user: true
}, { root: true })
// end
resolve()
})
},
/**
* 从持久化数据读取侧边栏展开或者收缩
* @param {Object} context
*/
asideCollapseLoad ({ state, dispatch }) {
return new Promise(async resolve => {
// store 赋值
state.asideCollapse = await dispatch('d2admin/db/get', {
dbName: 'sys',
path: 'menu.asideCollapse',
defaultValue: setting.menu.asideCollapse,
user: true
}, { root: true })
// end
resolve()
})
}
},
mutations: {
/**
* @description 设置顶栏菜单
* @param {Object} state state
* @param {Array} menu menu setting
*/
headerSet (state, menu) {
// store 赋值
state.header = supplementMenuPath(menu)
},
/**
* @description 设置侧边栏菜单
* @param {Object} state state
* @param {Array} menu menu setting
*/
asideSet (state, menu) {
// store 赋值
state.aside = supplementMenuPath(menu)
}
}
}
import { get } from 'lodash'
import router from '@/router'
import setting from '@/setting.js'
// 判定是否需要缓存
const isKeepAlive = data => get(data, 'meta.cache', false)
export default {
namespaced: true,
state: {
// 可以在多页 tab 模式下显示的页面
pool: [],
// 当前显示的多页面列表
opened: setting.page.opened,
// 已经加载多标签页数据 https://github.com/d2-projects/d2-admin/issues/201
openedLoaded: false,
// 当前页面
current: '',
// 需要缓存的页面 name
keepAlive: []
},
actions: {
/**
* @description 确认已经加载多标签页数据 https://github.com/d2-projects/d2-admin/issues/201
* @param {Object} context
*/
isLoaded ({ state }) {
if (state.openedLoaded) return Promise.resolve()
return new Promise(resolve => {
const timer = setInterval(() => {
if (state.openedLoaded) {
resolve(clearInterval(timer))
}
}, 10)
})
},
/**
* @class opened
* @description 从持久化数据载入标签页列表
* @param {Object} context
*/
openedLoad ({ state, commit, dispatch }) {
return new Promise(async resolve => {
// store 赋值
const value = await dispatch('d2admin/db/get', {
dbName: 'sys',
path: 'page.opened',
defaultValue: setting.page.opened,
user: true
}, { root: true })
// 在处理函数中进行数据优化 过滤掉现在已经失效的页签或者已经改变了信息的页签
// 以 fullPath 字段为准
// 如果页面过多的话可能需要优化算法
// valid 有效列表 1, 1, 0, 1 => 有效, 有效, 失效, 有效
const valid = []
// 处理数据
state.opened = value.map(opened => {
// 忽略首页
if (opened.fullPath === '/index') {
valid.push(1)
return opened
}
// 尝试在所有的支持多标签页的页面里找到 name 匹配的页面
const find = state.pool.find(item => item.name === opened.name)
// 记录有效或无效信息
valid.push(find ? 1 : 0)
// 返回合并后的数据 新的覆盖旧的
// 新的数据中一般不会携带 params 和 query, 所以旧的参数会留存
return Object.assign({}, opened, find)
}).filter((opened, index) => valid[index] === 1)
// 标记已经加载多标签页数据 https://github.com/d2-projects/d2-admin/issues/201
state.openedLoaded = true
// 根据 opened 数据生成缓存设置
commit('keepAliveRefresh')
// end
resolve()
})
},
/**
* 将 opened 属性赋值并持久化 在这之前请先确保已经更新了 state.opened
* @param {Object} context
*/
opened2db ({ state, dispatch }) {
return new Promise(async resolve => {
// 设置数据
dispatch('d2admin/db/set', {
dbName: 'sys',
path: 'page.opened',
value: state.opened,
user: true
}, { root: true })
// end
resolve()
})
},
/**
* @class opened
* @description 更新页面列表上的某一项
* @param {Object} context
* @param {Object} payload { index, params, query, fullPath } 路由信息
*/
openedUpdate ({ state, commit, dispatch }, { index, params, query, fullPath }) {
return new Promise(async resolve => {
// 更新页面列表某一项
let page = state.opened[index]
page.params = params || page.params
page.query = query || page.query
page.fullPath = fullPath || page.fullPath
state.opened.splice(index, 1, page)
// 持久化
await dispatch('opened2db')
// end
resolve()
})
},
/**
* @class opened
* @description 重排页面列表上的某一项
* @param {Object} context
* @param {Object} payload { oldIndex, newIndex } 位置信息
*/
openedSort ({ state, commit, dispatch }, { oldIndex, newIndex }) {
return new Promise(async resolve => {
// 重排页面列表某一项
let page = state.opened[oldIndex]
state.opened.splice(oldIndex, 1)
state.opened.splice(newIndex, 0, page)
// 持久化
await dispatch('opened2db')
// end
resolve()
})
},
/**
* @class opened
* @description 新增一个 tag (打开一个页面)
* @param {Object} context
* @param {Object} payload new tag info
*/
add ({ state, commit, dispatch }, { tag, params, query, fullPath }) {
return new Promise(async resolve => {
// 设置新的 tag 在新打开一个以前没打开过的页面时使用
let newTag = tag
newTag.params = params || newTag.params
newTag.query = query || newTag.query
newTag.fullPath = fullPath || newTag.fullPath
// 添加进当前显示的页面数组
state.opened.push(newTag)
// 如果这个页面需要缓存 将其添加到缓存设置
if (isKeepAlive(newTag)) {
commit('keepAlivePush', tag.name)
}
// 持久化
await dispatch('opened2db')
// end
resolve()
})
},
/**
* @class current
* @description 打开一个新的页面
* @param {Object} context
* @param {Object} payload 从路由钩子的 to 对象上获取 { name, params, query, fullPath } 路由信息
*/
open ({ state, commit, dispatch }, { name, params, query, fullPath }) {
return new Promise(async resolve => {
// 已经打开的页面
let opened = state.opened
// 判断此页面是否已经打开 并且记录位置
let pageOpendIndex = 0
const pageOpend = opened.find((page, index) => {
const same = page.fullPath === fullPath
pageOpendIndex = same ? index : pageOpendIndex
return same
})
if (pageOpend) {
// 页面以前打开过
await dispatch('openedUpdate', {
index: pageOpendIndex,
params,
query,
fullPath
})
} else {
// 页面以前没有打开过
let page = state.pool.find(t => t.name === name)
// 如果这里没有找到 page 代表这个路由虽然在框架内 但是不参与标签页显示
if (page) {
await dispatch('add', {
tag: Object.assign({}, page),
params,
query,
fullPath
})
}
}
commit('currentSet', fullPath)
// end
resolve()
})
},
/**
* @class opened
* @description 关闭一个 tag (关闭一个页面)
* @param {Object} context
* @param {Object} payload { tagName: 要关闭的标签名字 }
*/
close ({ state, commit, dispatch }, { tagName }) {
return new Promise(async resolve => {
// 下个新的页面
let newPage = state.opened[0]
const isCurrent = state.current === tagName
// 如果关闭的页面就是当前显示的页面
if (isCurrent) {
// 去找一个新的页面
let len = state.opened.length
for (let i = 1; i < len; i++) {
if (state.opened[i].fullPath === tagName) {
if (i < len - 1) {
newPage = state.opened[i + 1]
} else {
newPage = state.opened[i - 1]
}
break
}
}
}
// 找到这个页面在已经打开的数据里是第几个
const index = state.opened.findIndex(page => page.fullPath === tagName)
if (index >= 0) {
// 如果这个页面是缓存的页面 将其在缓存设置中删除
commit('keepAliveRemove', state.opened[index].name)
// 更新数据 删除关闭的页面
state.opened.splice(index, 1)
}
// 持久化
await dispatch('opened2db')
// 最后需要判断是否需要跳到首页
if (isCurrent) {
const { name = '', params = {}, query = {} } = newPage
let routerObj = {
name,
params,
query
}
router.push(routerObj)
}
// end
resolve()
})
},
/**
* @class opened
* @description 关闭当前标签左边的标签
* @param {Object} context
* @param {Object} payload { pageSelect: 当前选中的tagName }
*/
closeLeft ({ state, commit, dispatch }, { pageSelect } = {}) {
return new Promise(async resolve => {
const pageAim = pageSelect || state.current
let currentIndex = 0
state.opened.forEach((page, index) => {
if (page.fullPath === pageAim) {
currentIndex = index
}
})
if (currentIndex > 0) {
// 删除打开的页面 并在缓存设置中删除
state.opened.splice(1, currentIndex - 1).forEach(({ name }) => commit('keepAliveRemove', name))
}
state.current = pageAim
if (router.app.$route.fullPath !== pageAim) {
router.push(pageAim)
}
// 持久化
await dispatch('opened2db')
// end
resolve()
})
},
/**
* @class opened
* @description 关闭当前标签右边的标签
* @param {Object} context
* @param {Object} payload { pageSelect: 当前选中的tagName }
*/
closeRight ({ state, commit, dispatch }, { pageSelect } = {}) {
return new Promise(async resolve => {
const pageAim = pageSelect || state.current
let currentIndex = 0
state.opened.forEach((page, index) => {
if (page.fullPath === pageAim) {
currentIndex = index
}
})
// 删除打开的页面 并在缓存设置中删除
state.opened.splice(currentIndex + 1).forEach(({ name }) => commit('keepAliveRemove', name))
// 设置当前的页面
state.current = pageAim
if (router.app.$route.fullPath !== pageAim) {
router.push(pageAim)
}
// 持久化
await dispatch('opened2db')
// end
resolve()
})
},
/**
* @class opened
* @description 关闭当前激活之外的 tag
* @param {Object} context
* @param {Object} payload { pageSelect: 当前选中的tagName }
*/
closeOther ({ state, commit, dispatch }, { pageSelect } = {}) {
return new Promise(async resolve => {
const pageAim = pageSelect || state.current
let currentIndex = 0
state.opened.forEach((page, index) => {
if (page.fullPath === pageAim) {
currentIndex = index
}
})
// 删除打开的页面数据 并更新缓存设置
if (currentIndex === 0) {
state.opened.splice(1).forEach(({ name }) => commit('keepAliveRemove', name))
} else {
state.opened.splice(currentIndex + 1).forEach(({ name }) => commit('keepAliveRemove', name))
state.opened.splice(1, currentIndex - 1).forEach(({ name }) => commit('keepAliveRemove', name))
}
// 设置新的页面
state.current = pageAim
if (router.app.$route.fullPath !== pageAim) {
router.push(pageAim)
}
// 持久化
await dispatch('opened2db')
// end
resolve()
})
},
/**
* @class opened
* @description 关闭所有 tag
* @param {Object} context
*/
closeAll ({ state, commit, dispatch }) {
return new Promise(async resolve => {
// 删除打开的页面 并在缓存设置中删除
state.opened.splice(1).forEach(({ name }) => commit('keepAliveRemove', name))
// 持久化
await dispatch('opened2db')
// 关闭所有的标签页后需要判断一次现在是不是在首页
if (router.app.$route.name !== 'index') {
router.push({
name: 'index'
})
}
// end
resolve()
})
}
},
mutations: {
/**
* @class keepAlive
* @description 从已经打开的页面记录中更新需要缓存的页面记录
* @param {Object} state state
*/
keepAliveRefresh (state) {
state.keepAlive = state.opened.filter(item => isKeepAlive(item)).map(e => e.name)
},
/**
* @description 删除一个页面的缓存设置
* @param {Object} state state
* @param {String} name name
*/
keepAliveRemove (state, name) {
const list = [ ...state.keepAlive ]
const index = list.findIndex(item => item === name)
if (index !== -1) {
list.splice(index, 1)
state.keepAlive = list
}
},
/**
* @description 增加一个页面的缓存设置
* @param {Object} state state
* @param {String} name name
*/
keepAlivePush (state, name) {
const keep = [ ...state.keepAlive ]
keep.push(name)
state.keepAlive = keep
},
/**
* @description 清空页面缓存设置
* @param {Object} state state
*/
keepAliveClean (state) {
state.keepAlive = []
},
/**
* @class current
* @description 设置当前激活的页面 fullPath
* @param {Object} state state
* @param {String} fullPath new fullPath
*/
currentSet (state, fullPath) {
state.current = fullPath
},
/**
* @class pool
* @description 保存 pool (候选池)
* @param {Object} state state
* @param {Array} routes routes
*/
init (state, routes) {
const pool = []
const push = function (routes) {
routes.forEach(route => {
if (route.children && route.children.length > 0) {
push(route.children)
} else {
if (!route.hidden) {
const { meta, name, path } = route
pool.push({ meta, name, path })
}
}
})
}
push(routes)
state.pool = pool
}
}
}
import util from '@/libs/util.js'
export default {
namespaced: true,
mutations: {
/**
* @description 显示版本信息
* @param {Object} state state
*/
versionShow () {
util.log.capsule('D2Admin', `v${process.env.VUE_APP_VERSION}`)
console.log('D2 Admin https://github.com/d2-projects/d2-admin')
console.log('D2 Crud https://github.com/d2-projects/d2-crud')
console.log('Document https://d2.pub/zh/doc/d2-admin')
console.log('请不要吝啬您的 star,谢谢 ~')
}
}
}
import setting from '@/setting.js'
export default {
namespaced: true,
state: {
// 搜索面板激活状态
active: false,
// 快捷键
hotkey: {
open: setting.hotkey.search.open,
close: setting.hotkey.search.close
},
// 所有可以搜索的页面
pool: []
},
mutations: {
/**
* @description 切换激活状态
* @param {Object} state state
*/
toggle (state) {
state.active = !state.active
},
/**
* @description 设置激活模式
* @param {Object} state state
* @param {Boolean} active active
*/
set (state, active) {
state.active = active
},
/**
* @description 初始化
* @param {Object} state state
* @param {Array} menu menu
*/
init (state, menu) {
const pool = []
const push = function (menu, titlePrefix = []) {
menu.forEach(m => {
if (m.children) {
push(m.children, [ ...titlePrefix, m.title ])
} else {
pool.push({
...m,
fullTitle: [ ...titlePrefix, m.title ].join(' / ')
})
}
})
}
push(menu)
state.pool = pool
}
}
}
import Vue from 'vue'
import router from '@/router'
export default {
namespaced: true,
state: {
// 尺寸
value: '' // medium small mini
},
actions: {
/**
* @description 将当前的设置应用到 element
* @param {Object} context
* @param {Boolean} refresh 是否在设置之后刷新页面
*/
apply ({ state, commit }, refresh) {
Vue.prototype.$ELEMENT.size = state.value
if (refresh) {
commit('d2admin/page/keepAliveClean', null, { root: true })
router.replace('/refresh')
}
},
/**
* @description 确认已经加载组件尺寸设置 https://github.com/d2-projects/d2-admin/issues/198
* @param {Object} context
*/
isLoaded ({ state }) {
if (state.value) return Promise.resolve()
return new Promise(resolve => {
const timer = setInterval(() => {
if (state.value) {
resolve(clearInterval(timer))
}
}, 10)
})
},
/**
* @description 设置尺寸
* @param {Object} context
* @param {String} size 尺寸
*/
set ({ state, dispatch }, size) {
return new Promise(async resolve => {
// store 赋值
state.value = size
// 应用
dispatch('apply', true)
// 持久化
await dispatch('d2admin/db/set', {
dbName: 'sys',
path: 'size.value',
value: state.value,
user: true
}, { root: true })
// end
resolve()
})
},
/**
* @description 从持久化数据读取尺寸设置
* @param {Object} context
*/
load ({ state, dispatch }) {
return new Promise(async resolve => {
// store 赋值
state.value = await dispatch('d2admin/db/get', {
dbName: 'sys',
path: 'size.value',
defaultValue: 'default',
user: true
}, { root: true })
// 应用
dispatch('apply')
// end
resolve()
})
}
}
}
// 设置文件
import setting from '@/setting.js'
export default {
namespaced: true,
state: {
// 主题
list: setting.theme.list,
// 现在激活的主题 这应该是一个名字 不是对象
activeName: setting.theme.list[0].name
},
getters: {
/**
* @description 返回当前的主题信息 不是一个名字 而是当前激活主题的所有数据
* @param {Object} state state
*/
activeSetting (state) {
return state.list.find(theme => theme.name === state.activeName)
}
},
actions: {
/**
* @description 激活一个主题
* @param {String} themeValue 需要激活的主题名称
*/
set ({ state, commit, dispatch }, themeName) {
return new Promise(async resolve => {
// 检查这个主题在主题列表里是否存在
state.activeName = state.list.find(e => e.name === themeName) ? themeName : state.list[0].name
// 将 vuex 中的主题应用到 dom
commit('dom')
// 持久化
await dispatch('d2admin/db/set', {
dbName: 'sys',
path: 'theme.activeName',
value: state.activeName,
user: true
}, { root: true })
// end
resolve()
})
},
/**
* @description 从持久化数据加载主题设置 * @param {Object} context
*/
load ({ state, commit, dispatch }) {
return new Promise(async resolve => {
// store 赋值
let activeName = await dispatch('d2admin/db/get', {
dbName: 'sys',
path: 'theme.activeName',
defaultValue: state.list[0].name,
user: true
}, { root: true })
// 检查这个主题在主题列表里是否存在
if (state.list.find(e => e.name === activeName)) {
state.activeName = activeName
} else {
state.activeName = state.list[0].name
// 持久化
await dispatch('d2admin/db/set', {
dbName: 'sys',
path: 'theme.activeName',
value: state.activeName,
user: true
}, { root: true })
}
// 将 vuex 中的主题应用到 dom
commit('dom')
// end
resolve()
})
}
},
mutations: {
/**
* @description 将 vuex 中的主题应用到 dom
* @param {Object} state state
*/
dom (state) {
document.body.className = `theme-${state.activeName}`
}
}
}
// 设置文件
import setting from '@/setting.js'
export default {
namespaced: true,
state: {
// 是否开启页面过度动画
active: setting.transition.active
},
actions: {
/**
* @description 设置开启状态
* @param {Object} context
* @param {Boolean} active 新的状态
*/
set ({ state, dispatch }, active) {
return new Promise(async resolve => {
// store 赋值
state.active = active
// 持久化
await dispatch('d2admin/db/set', {
dbName: 'sys',
path: 'transition.active',
value: state.active,
user: true
}, { root: true })
// end
resolve()
})
},
/**
* 从数据库读取页面过渡动画设置
* @param {Object} context
*/
load ({ state, dispatch }) {
return new Promise(async resolve => {
// store 赋值
state.active = await dispatch('d2admin/db/get', {
dbName: 'sys',
path: 'transition.active',
defaultValue: setting.transition.active,
user: true
}, { root: true })
// end
resolve()
})
}
}
}
import UaParser from 'ua-parser-js'
export default {
namespaced: true,
state: {
// 用户 UA
data: {}
},
mutations: {
/**
* @description 记录 UA
* @param {Object} state state
*/
get (state) {
state.data = new UaParser().getResult()
}
}
}
export default {
namespaced: true,
state: {
// 用户信息
info: {}
},
actions: {
/**
* @description 设置用户数据
* @param {Object} context
* @param {*} info info
*/
set ({ state, dispatch }, info) {
return new Promise(async resolve => {
// store 赋值
state.info = info
// 持久化
await dispatch('d2admin/db/set', {
dbName: 'sys',
path: 'user.info',
value: info,
user: true
}, { root: true })
// end
resolve()
})
},
/**
* @description 从数据库取用户数据
* @param {Object} context
*/
load ({ state, dispatch }) {
return new Promise(async resolve => {
// store 赋值
state.info = await dispatch('d2admin/db/get', {
dbName: 'sys',
path: 'user.info',
defaultValue: {},
user: true
}, { root: true })
// end
resolve()
})
}
}
}
<template>
<d2-container>
<template slot="header">Page 1 header</template>
Hello World
</d2-container>
</template>
<script>
export default {
name: 'page1'
}
</script>
<template>
<d2-container>
<template slot="header">Page 2 header</template>
Hello World
</d2-container>
</template>
<script>
export default {
name: 'page2'
}
</script>
<template>
<d2-container>
<template slot="header">Page 3 header</template>
Hello World
</d2-container>
</template>
<script>
export default {
name: 'page3'
}
</script>
<template>
<div class="page">
<p class="page_title">404 page not found</p>
<el-button class="d2-mt" @click="$router.replace({ path: '/' })">
返回首页
</el-button>
</div>
</template>
<style lang="scss" scoped>
.page {
background: #303133;
background-blend-mode: multiply,multiply;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
.page_title {
font-size: 20px;
color: #FFF;
}
}
</style>
export default {
beforeRouteEnter (to, from, next) {
next(instance => instance.$router.replace(JSON.parse(from.params.route)))
},
render: h => h()
}
export default {
beforeRouteEnter (to, from, next) {
next(instance => instance.$router.replace(from.fullPath))
},
render: h => h()
}
<template>
<div class="d2-badge">
<p v-for="(group, groupIndex) of badges" :key="groupIndex" align="center">
<a v-for="(badge, badgeIndex) of group" :key="badgeIndex" :href="badge.link" target="_blank">
<img :src="badge.img"/>
</a>
</p>
</div>
</template>
<script>
const linkD2Admin = 'https://github.com/d2-projects/d2-admin'
export default {
data () {
return {
badges: [
[
{ img: 'https://img.shields.io/github/stars/d2-projects/d2-admin.svg', link: `${linkD2Admin}/stargazers` },
{ img: 'https://img.shields.io/github/forks/d2-projects/d2-admin.svg', link: `${linkD2Admin}/network/members` },
{ img: 'https://img.shields.io/github/issues/d2-projects/d2-admin.svg', link: `${linkD2Admin}/issues` },
{ img: 'https://img.shields.io/github/issues-closed/d2-projects/d2-admin.svg', link: `${linkD2Admin}/issues?q=is%3Aissue+is%3Aclosed` },
{ img: 'https://img.shields.io/github/issues-pr/d2-projects/d2-admin.svg', link: `${linkD2Admin}/pulls` },
{ img: 'https://img.shields.io/github/issues-pr-closed/d2-projects/d2-admin.svg', link: `${linkD2Admin}/pulls?q=is%3Apr+is%3Aclosed` },
{ img: 'https://img.shields.io/github/last-commit/d2-projects/d2-admin.svg', link: linkD2Admin }
],
[
{ img: 'https://github.com/d2-projects/d2-admin-start-kit/workflows/Deploy%20https%3A%2F%2Fd2.pub/badge.svg', link: `${linkD2Admin}/actions?query=workflow%3A%22Deploy+https%3A%2F%2Fd2.pub%22` },
{ img: 'https://github.com/d2-projects/d2-admin-start-kit/workflows/Deploy%20https%3A%2F%2Fcdn.d2.pub/badge.svg', link: `${linkD2Admin}/actions?query=workflow%3A%22Deploy+https%3A%2F%2Fcdn.d2.pub%22` },
{ img: 'https://github.com/d2-projects/d2-admin-start-kit/workflows/Deploy%20Github/badge.svg', link: `${linkD2Admin}/actions?query=workflow%3A%22Deploy+Github%22` },
{ img: 'https://api.netlify.com/api/v1/badges/08ff8c93-f0a8-497a-a081-440b31fb3aa4/deploy-status', link: 'https://app.netlify.com/sites/d2-admin-start-kit/deploys' }
],
[
{ img: 'https://visitor-count-badge.herokuapp.com/today.svg?repo_id=d2-projects.d2-admin', link: linkD2Admin },
{ img: 'https://visitor-count-badge.herokuapp.com/total.svg?repo_id=d2-projects.d2-admin', link: linkD2Admin },
{ img: 'https://img.shields.io/github/release/d2-projects/d2-admin.svg', link: `${linkD2Admin}/releases` }
]
]
}
}
}
</script>
<style lang="scss" scoped>
.d2-badge {
margin-bottom: 20px;
p {
margin: 0px;
margin-bottom: 2px;
&:last-child {
margin-bottom: 0px;
}
img {
display: inline-block;
margin: 0px 2px;
}
}
}
</style>
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" xmlns:xlink="http://www.w3.org/1999/xlink" width="804" height="804" viewBox="0 0 804 804">
<desc></desc>
<rect width="804" height="804" fill="#ffffff" cx="0" cy="0" />
<defs>
<rect id="p" width="12" height="12" />
</defs>
<g fill="#000000">
<use x="12" y="12" xlink:href="#p" />
<use x="24" y="12" xlink:href="#p" />
<use x="36" y="12" xlink:href="#p" />
<use x="48" y="12" xlink:href="#p" />
<use x="60" y="12" xlink:href="#p" />
<use x="72" y="12" xlink:href="#p" />
<use x="84" y="12" xlink:href="#p" />
<use x="108" y="12" xlink:href="#p" />
<use x="156" y="12" xlink:href="#p" />
<use x="168" y="12" xlink:href="#p" />
<use x="216" y="12" xlink:href="#p" />
<use x="252" y="12" xlink:href="#p" />
<use x="276" y="12" xlink:href="#p" />
<use x="288" y="12" xlink:href="#p" />
<use x="312" y="12" xlink:href="#p" />
<use x="324" y="12" xlink:href="#p" />
<use x="348" y="12" xlink:href="#p" />
<use x="360" y="12" xlink:href="#p" />
<use x="444" y="12" xlink:href="#p" />
<use x="468" y="12" xlink:href="#p" />
<use x="480" y="12" xlink:href="#p" />
<use x="492" y="12" xlink:href="#p" />
<use x="504" y="12" xlink:href="#p" />
<use x="540" y="12" xlink:href="#p" />
<use x="552" y="12" xlink:href="#p" />
<use x="612" y="12" xlink:href="#p" />
<use x="648" y="12" xlink:href="#p" />
<use x="672" y="12" xlink:href="#p" />
<use x="708" y="12" xlink:href="#p" />
<use x="720" y="12" xlink:href="#p" />
<use x="732" y="12" xlink:href="#p" />
<use x="744" y="12" xlink:href="#p" />
<use x="756" y="12" xlink:href="#p" />
<use x="768" y="12" xlink:href="#p" />
<use x="780" y="12" xlink:href="#p" />
<use x="12" y="24" xlink:href="#p" />
<use x="84" y="24" xlink:href="#p" />
<use x="144" y="24" xlink:href="#p" />
<use x="156" y="24" xlink:href="#p" />
<use x="168" y="24" xlink:href="#p" />
<use x="204" y="24" xlink:href="#p" />
<use x="216" y="24" xlink:href="#p" />
<use x="240" y="24" xlink:href="#p" />
<use x="264" y="24" xlink:href="#p" />
<use x="300" y="24" xlink:href="#p" />
<use x="312" y="24" xlink:href="#p" />
<use x="336" y="24" xlink:href="#p" />
<use x="360" y="24" xlink:href="#p" />
<use x="372" y="24" xlink:href="#p" />
<use x="396" y="24" xlink:href="#p" />
<use x="504" y="24" xlink:href="#p" />
<use x="516" y="24" xlink:href="#p" />
<use x="540" y="24" xlink:href="#p" />
<use x="588" y="24" xlink:href="#p" />
<use x="600" y="24" xlink:href="#p" />
<use x="612" y="24" xlink:href="#p" />
<use x="684" y="24" xlink:href="#p" />
<use x="708" y="24" xlink:href="#p" />
<use x="780" y="24" xlink:href="#p" />
<use x="12" y="36" xlink:href="#p" />
<use x="36" y="36" xlink:href="#p" />
<use x="48" y="36" xlink:href="#p" />
<use x="60" y="36" xlink:href="#p" />
<use x="84" y="36" xlink:href="#p" />
<use x="108" y="36" xlink:href="#p" />
<use x="132" y="36" xlink:href="#p" />
<use x="156" y="36" xlink:href="#p" />
<use x="300" y="36" xlink:href="#p" />
<use x="336" y="36" xlink:href="#p" />
<use x="348" y="36" xlink:href="#p" />
<use x="360" y="36" xlink:href="#p" />
<use x="372" y="36" xlink:href="#p" />
<use x="384" y="36" xlink:href="#p" />
<use x="456" y="36" xlink:href="#p" />
<use x="468" y="36" xlink:href="#p" />
<use x="492" y="36" xlink:href="#p" />
<use x="504" y="36" xlink:href="#p" />
<use x="528" y="36" xlink:href="#p" />
<use x="576" y="36" xlink:href="#p" />
<use x="588" y="36" xlink:href="#p" />
<use x="600" y="36" xlink:href="#p" />
<use x="660" y="36" xlink:href="#p" />
<use x="684" y="36" xlink:href="#p" />
<use x="708" y="36" xlink:href="#p" />
<use x="732" y="36" xlink:href="#p" />
<use x="744" y="36" xlink:href="#p" />
<use x="756" y="36" xlink:href="#p" />
<use x="780" y="36" xlink:href="#p" />
<use x="12" y="48" xlink:href="#p" />
<use x="36" y="48" xlink:href="#p" />
<use x="48" y="48" xlink:href="#p" />
<use x="60" y="48" xlink:href="#p" />
<use x="84" y="48" xlink:href="#p" />
<use x="132" y="48" xlink:href="#p" />
<use x="156" y="48" xlink:href="#p" />
<use x="168" y="48" xlink:href="#p" />
<use x="180" y="48" xlink:href="#p" />
<use x="192" y="48" xlink:href="#p" />
<use x="228" y="48" xlink:href="#p" />
<use x="240" y="48" xlink:href="#p" />
<use x="252" y="48" xlink:href="#p" />
<use x="276" y="48" xlink:href="#p" />
<use x="300" y="48" xlink:href="#p" />
<use x="432" y="48" xlink:href="#p" />
<use x="444" y="48" xlink:href="#p" />
<use x="492" y="48" xlink:href="#p" />
<use x="504" y="48" xlink:href="#p" />
<use x="516" y="48" xlink:href="#p" />
<use x="564" y="48" xlink:href="#p" />
<use x="612" y="48" xlink:href="#p" />
<use x="624" y="48" xlink:href="#p" />
<use x="636" y="48" xlink:href="#p" />
<use x="648" y="48" xlink:href="#p" />
<use x="660" y="48" xlink:href="#p" />
<use x="672" y="48" xlink:href="#p" />
<use x="708" y="48" xlink:href="#p" />
<use x="732" y="48" xlink:href="#p" />
<use x="744" y="48" xlink:href="#p" />
<use x="756" y="48" xlink:href="#p" />
<use x="780" y="48" xlink:href="#p" />
<use x="12" y="60" xlink:href="#p" />
<use x="36" y="60" xlink:href="#p" />
<use x="48" y="60" xlink:href="#p" />
<use x="60" y="60" xlink:href="#p" />
<use x="84" y="60" xlink:href="#p" />
<use x="108" y="60" xlink:href="#p" />
<use x="120" y="60" xlink:href="#p" />
<use x="180" y="60" xlink:href="#p" />
<use x="216" y="60" xlink:href="#p" />
<use x="228" y="60" xlink:href="#p" />
<use x="240" y="60" xlink:href="#p" />
<use x="264" y="60" xlink:href="#p" />
<use x="276" y="60" xlink:href="#p" />
<use x="300" y="60" xlink:href="#p" />
<use x="312" y="60" xlink:href="#p" />
<use x="324" y="60" xlink:href="#p" />
<use x="336" y="60" xlink:href="#p" />
<use x="372" y="60" xlink:href="#p" />
<use x="384" y="60" xlink:href="#p" />
<use x="396" y="60" xlink:href="#p" />
<use x="408" y="60" xlink:href="#p" />
<use x="420" y="60" xlink:href="#p" />
<use x="432" y="60" xlink:href="#p" />
<use x="444" y="60" xlink:href="#p" />
<use x="480" y="60" xlink:href="#p" />
<use x="516" y="60" xlink:href="#p" />
<use x="564" y="60" xlink:href="#p" />
<use x="576" y="60" xlink:href="#p" />
<use x="624" y="60" xlink:href="#p" />
<use x="636" y="60" xlink:href="#p" />
<use x="648" y="60" xlink:href="#p" />
<use x="684" y="60" xlink:href="#p" />
<use x="708" y="60" xlink:href="#p" />
<use x="732" y="60" xlink:href="#p" />
<use x="744" y="60" xlink:href="#p" />
<use x="756" y="60" xlink:href="#p" />
<use x="780" y="60" xlink:href="#p" />
<use x="12" y="72" xlink:href="#p" />
<use x="84" y="72" xlink:href="#p" />
<use x="120" y="72" xlink:href="#p" />
<use x="132" y="72" xlink:href="#p" />
<use x="144" y="72" xlink:href="#p" />
<use x="168" y="72" xlink:href="#p" />
<use x="180" y="72" xlink:href="#p" />
<use x="204" y="72" xlink:href="#p" />
<use x="216" y="72" xlink:href="#p" />
<use x="228" y="72" xlink:href="#p" />
<use x="240" y="72" xlink:href="#p" />
<use x="288" y="72" xlink:href="#p" />
<use x="312" y="72" xlink:href="#p" />
<use x="324" y="72" xlink:href="#p" />
<use x="348" y="72" xlink:href="#p" />
<use x="372" y="72" xlink:href="#p" />
<use x="420" y="72" xlink:href="#p" />
<use x="432" y="72" xlink:href="#p" />
<use x="468" y="72" xlink:href="#p" />
<use x="480" y="72" xlink:href="#p" />
<use x="492" y="72" xlink:href="#p" />
<use x="504" y="72" xlink:href="#p" />
<use x="516" y="72" xlink:href="#p" />
<use x="528" y="72" xlink:href="#p" />
<use x="552" y="72" xlink:href="#p" />
<use x="564" y="72" xlink:href="#p" />
<use x="588" y="72" xlink:href="#p" />
<use x="600" y="72" xlink:href="#p" />
<use x="624" y="72" xlink:href="#p" />
<use x="648" y="72" xlink:href="#p" />
<use x="660" y="72" xlink:href="#p" />
<use x="708" y="72" xlink:href="#p" />
<use x="780" y="72" xlink:href="#p" />
<use x="12" y="84" xlink:href="#p" />
<use x="24" y="84" xlink:href="#p" />
<use x="36" y="84" xlink:href="#p" />
<use x="48" y="84" xlink:href="#p" />
<use x="60" y="84" xlink:href="#p" />
<use x="72" y="84" xlink:href="#p" />
<use x="84" y="84" xlink:href="#p" />
<use x="108" y="84" xlink:href="#p" />
<use x="132" y="84" xlink:href="#p" />
<use x="156" y="84" xlink:href="#p" />
<use x="180" y="84" xlink:href="#p" />
<use x="204" y="84" xlink:href="#p" />
<use x="228" y="84" xlink:href="#p" />
<use x="252" y="84" xlink:href="#p" />
<use x="276" y="84" xlink:href="#p" />
<use x="300" y="84" xlink:href="#p" />
<use x="324" y="84" xlink:href="#p" />
<use x="348" y="84" xlink:href="#p" />
<use x="372" y="84" xlink:href="#p" />
<use x="396" y="84" xlink:href="#p" />
<use x="420" y="84" xlink:href="#p" />
<use x="444" y="84" xlink:href="#p" />
<use x="468" y="84" xlink:href="#p" />
<use x="492" y="84" xlink:href="#p" />
<use x="516" y="84" xlink:href="#p" />
<use x="540" y="84" xlink:href="#p" />
<use x="564" y="84" xlink:href="#p" />
<use x="588" y="84" xlink:href="#p" />
<use x="612" y="84" xlink:href="#p" />
<use x="636" y="84" xlink:href="#p" />
<use x="660" y="84" xlink:href="#p" />
<use x="684" y="84" xlink:href="#p" />
<use x="708" y="84" xlink:href="#p" />
<use x="720" y="84" xlink:href="#p" />
<use x="732" y="84" xlink:href="#p" />
<use x="744" y="84" xlink:href="#p" />
<use x="756" y="84" xlink:href="#p" />
<use x="768" y="84" xlink:href="#p" />
<use x="780" y="84" xlink:href="#p" />
<use x="108" y="96" xlink:href="#p" />
<use x="120" y="96" xlink:href="#p" />
<use x="132" y="96" xlink:href="#p" />
<use x="144" y="96" xlink:href="#p" />
<use x="156" y="96" xlink:href="#p" />
<use x="180" y="96" xlink:href="#p" />
<use x="192" y="96" xlink:href="#p" />
<use x="216" y="96" xlink:href="#p" />
<use x="228" y="96" xlink:href="#p" />
<use x="300" y="96" xlink:href="#p" />
<use x="336" y="96" xlink:href="#p" />
<use x="372" y="96" xlink:href="#p" />
<use x="420" y="96" xlink:href="#p" />
<use x="432" y="96" xlink:href="#p" />
<use x="456" y="96" xlink:href="#p" />
<use x="468" y="96" xlink:href="#p" />
<use x="492" y="96" xlink:href="#p" />
<use x="576" y="96" xlink:href="#p" />
<use x="588" y="96" xlink:href="#p" />
<use x="600" y="96" xlink:href="#p" />
<use x="660" y="96" xlink:href="#p" />
<use x="672" y="96" xlink:href="#p" />
<use x="72" y="108" xlink:href="#p" />
<use x="84" y="108" xlink:href="#p" />
<use x="120" y="108" xlink:href="#p" />
<use x="132" y="108" xlink:href="#p" />
<use x="144" y="108" xlink:href="#p" />
<use x="180" y="108" xlink:href="#p" />
<use x="204" y="108" xlink:href="#p" />
<use x="276" y="108" xlink:href="#p" />
<use x="324" y="108" xlink:href="#p" />
<use x="372" y="108" xlink:href="#p" />
<use x="384" y="108" xlink:href="#p" />
<use x="396" y="108" xlink:href="#p" />
<use x="408" y="108" xlink:href="#p" />
<use x="420" y="108" xlink:href="#p" />
<use x="444" y="108" xlink:href="#p" />
<use x="456" y="108" xlink:href="#p" />
<use x="468" y="108" xlink:href="#p" />
<use x="492" y="108" xlink:href="#p" />
<use x="504" y="108" xlink:href="#p" />
<use x="516" y="108" xlink:href="#p" />
<use x="528" y="108" xlink:href="#p" />
<use x="540" y="108" xlink:href="#p" />
<use x="564" y="108" xlink:href="#p" />
<use x="576" y="108" xlink:href="#p" />
<use x="588" y="108" xlink:href="#p" />
<use x="624" y="108" xlink:href="#p" />
<use x="648" y="108" xlink:href="#p" />
<use x="660" y="108" xlink:href="#p" />
<use x="672" y="108" xlink:href="#p" />
<use x="684" y="108" xlink:href="#p" />
<use x="708" y="108" xlink:href="#p" />
<use x="732" y="108" xlink:href="#p" />
<use x="756" y="108" xlink:href="#p" />
<use x="780" y="108" xlink:href="#p" />
<use x="12" y="120" xlink:href="#p" />
<use x="36" y="120" xlink:href="#p" />
<use x="48" y="120" xlink:href="#p" />
<use x="168" y="120" xlink:href="#p" />
<use x="204" y="120" xlink:href="#p" />
<use x="228" y="120" xlink:href="#p" />
<use x="240" y="120" xlink:href="#p" />
<use x="276" y="120" xlink:href="#p" />
<use x="300" y="120" xlink:href="#p" />
<use x="396" y="120" xlink:href="#p" />
<use x="420" y="120" xlink:href="#p" />
<use x="456" y="120" xlink:href="#p" />
<use x="468" y="120" xlink:href="#p" />
<use x="504" y="120" xlink:href="#p" />
<use x="516" y="120" xlink:href="#p" />
<use x="552" y="120" xlink:href="#p" />
<use x="564" y="120" xlink:href="#p" />
<use x="600" y="120" xlink:href="#p" />
<use x="636" y="120" xlink:href="#p" />
<use x="648" y="120" xlink:href="#p" />
<use x="660" y="120" xlink:href="#p" />
<use x="696" y="120" xlink:href="#p" />
<use x="732" y="120" xlink:href="#p" />
<use x="744" y="120" xlink:href="#p" />
<use x="756" y="120" xlink:href="#p" />
<use x="24" y="132" xlink:href="#p" />
<use x="36" y="132" xlink:href="#p" />
<use x="48" y="132" xlink:href="#p" />
<use x="72" y="132" xlink:href="#p" />
<use x="84" y="132" xlink:href="#p" />
<use x="96" y="132" xlink:href="#p" />
<use x="108" y="132" xlink:href="#p" />
<use x="132" y="132" xlink:href="#p" />
<use x="204" y="132" xlink:href="#p" />
<use x="228" y="132" xlink:href="#p" />
<use x="240" y="132" xlink:href="#p" />
<use x="312" y="132" xlink:href="#p" />
<use x="348" y="132" xlink:href="#p" />
<use x="372" y="132" xlink:href="#p" />
<use x="384" y="132" xlink:href="#p" />
<use x="408" y="132" xlink:href="#p" />
<use x="480" y="132" xlink:href="#p" />
<use x="516" y="132" xlink:href="#p" />
<use x="528" y="132" xlink:href="#p" />
<use x="540" y="132" xlink:href="#p" />
<use x="564" y="132" xlink:href="#p" />
<use x="600" y="132" xlink:href="#p" />
<use x="612" y="132" xlink:href="#p" />
<use x="624" y="132" xlink:href="#p" />
<use x="648" y="132" xlink:href="#p" />
<use x="660" y="132" xlink:href="#p" />
<use x="684" y="132" xlink:href="#p" />
<use x="720" y="132" xlink:href="#p" />
<use x="732" y="132" xlink:href="#p" />
<use x="24" y="144" xlink:href="#p" />
<use x="132" y="144" xlink:href="#p" />
<use x="144" y="144" xlink:href="#p" />
<use x="168" y="144" xlink:href="#p" />
<use x="180" y="144" xlink:href="#p" />
<use x="216" y="144" xlink:href="#p" />
<use x="228" y="144" xlink:href="#p" />
<use x="252" y="144" xlink:href="#p" />
<use x="264" y="144" xlink:href="#p" />
<use x="276" y="144" xlink:href="#p" />
<use x="288" y="144" xlink:href="#p" />
<use x="300" y="144" xlink:href="#p" />
<use x="336" y="144" xlink:href="#p" />
<use x="408" y="144" xlink:href="#p" />
<use x="420" y="144" xlink:href="#p" />
<use x="432" y="144" xlink:href="#p" />
<use x="444" y="144" xlink:href="#p" />
<use x="456" y="144" xlink:href="#p" />
<use x="492" y="144" xlink:href="#p" />
<use x="504" y="144" xlink:href="#p" />
<use x="516" y="144" xlink:href="#p" />
<use x="552" y="144" xlink:href="#p" />
<use x="588" y="144" xlink:href="#p" />
<use x="600" y="144" xlink:href="#p" />
<use x="624" y="144" xlink:href="#p" />
<use x="636" y="144" xlink:href="#p" />
<use x="660" y="144" xlink:href="#p" />
<use x="672" y="144" xlink:href="#p" />
<use x="732" y="144" xlink:href="#p" />
<use x="744" y="144" xlink:href="#p" />
<use x="768" y="144" xlink:href="#p" />
<use x="12" y="156" xlink:href="#p" />
<use x="24" y="156" xlink:href="#p" />
<use x="36" y="156" xlink:href="#p" />
<use x="60" y="156" xlink:href="#p" />
<use x="72" y="156" xlink:href="#p" />
<use x="84" y="156" xlink:href="#p" />
<use x="108" y="156" xlink:href="#p" />
<use x="156" y="156" xlink:href="#p" />
<use x="192" y="156" xlink:href="#p" />
<use x="216" y="156" xlink:href="#p" />
<use x="288" y="156" xlink:href="#p" />
<use x="300" y="156" xlink:href="#p" />
<use x="312" y="156" xlink:href="#p" />
<use x="336" y="156" xlink:href="#p" />
<use x="384" y="156" xlink:href="#p" />
<use x="396" y="156" xlink:href="#p" />
<use x="432" y="156" xlink:href="#p" />
<use x="456" y="156" xlink:href="#p" />
<use x="480" y="156" xlink:href="#p" />
<use x="492" y="156" xlink:href="#p" />
<use x="516" y="156" xlink:href="#p" />
<use x="528" y="156" xlink:href="#p" />
<use x="540" y="156" xlink:href="#p" />
<use x="552" y="156" xlink:href="#p" />
<use x="588" y="156" xlink:href="#p" />
<use x="612" y="156" xlink:href="#p" />
<use x="624" y="156" xlink:href="#p" />
<use x="636" y="156" xlink:href="#p" />
<use x="648" y="156" xlink:href="#p" />
<use x="660" y="156" xlink:href="#p" />
<use x="732" y="156" xlink:href="#p" />
<use x="756" y="156" xlink:href="#p" />
<use x="768" y="156" xlink:href="#p" />
<use x="780" y="156" xlink:href="#p" />
<use x="48" y="168" xlink:href="#p" />
<use x="72" y="168" xlink:href="#p" />
<use x="96" y="168" xlink:href="#p" />
<use x="108" y="168" xlink:href="#p" />
<use x="132" y="168" xlink:href="#p" />
<use x="180" y="168" xlink:href="#p" />
<use x="192" y="168" xlink:href="#p" />
<use x="204" y="168" xlink:href="#p" />
<use x="216" y="168" xlink:href="#p" />
<use x="276" y="168" xlink:href="#p" />
<use x="288" y="168" xlink:href="#p" />
<use x="300" y="168" xlink:href="#p" />
<use x="324" y="168" xlink:href="#p" />
<use x="336" y="168" xlink:href="#p" />
<use x="348" y="168" xlink:href="#p" />
<use x="360" y="168" xlink:href="#p" />
<use x="372" y="168" xlink:href="#p" />
<use x="396" y="168" xlink:href="#p" />
<use x="420" y="168" xlink:href="#p" />
<use x="456" y="168" xlink:href="#p" />
<use x="468" y="168" xlink:href="#p" />
<use x="480" y="168" xlink:href="#p" />
<use x="492" y="168" xlink:href="#p" />
<use x="504" y="168" xlink:href="#p" />
<use x="540" y="168" xlink:href="#p" />
<use x="552" y="168" xlink:href="#p" />
<use x="612" y="168" xlink:href="#p" />
<use x="636" y="168" xlink:href="#p" />
<use x="648" y="168" xlink:href="#p" />
<use x="660" y="168" xlink:href="#p" />
<use x="672" y="168" xlink:href="#p" />
<use x="684" y="168" xlink:href="#p" />
<use x="732" y="168" xlink:href="#p" />
<use x="744" y="168" xlink:href="#p" />
<use x="756" y="168" xlink:href="#p" />
<use x="780" y="168" xlink:href="#p" />
<use x="12" y="180" xlink:href="#p" />
<use x="36" y="180" xlink:href="#p" />
<use x="72" y="180" xlink:href="#p" />
<use x="84" y="180" xlink:href="#p" />
<use x="96" y="180" xlink:href="#p" />
<use x="108" y="180" xlink:href="#p" />
<use x="132" y="180" xlink:href="#p" />
<use x="144" y="180" xlink:href="#p" />
<use x="168" y="180" xlink:href="#p" />
<use x="180" y="180" xlink:href="#p" />
<use x="192" y="180" xlink:href="#p" />
<use x="204" y="180" xlink:href="#p" />
<use x="216" y="180" xlink:href="#p" />
<use x="252" y="180" xlink:href="#p" />
<use x="276" y="180" xlink:href="#p" />
<use x="288" y="180" xlink:href="#p" />
<use x="312" y="180" xlink:href="#p" />
<use x="324" y="180" xlink:href="#p" />
<use x="372" y="180" xlink:href="#p" />
<use x="384" y="180" xlink:href="#p" />
<use x="396" y="180" xlink:href="#p" />
<use x="420" y="180" xlink:href="#p" />
<use x="432" y="180" xlink:href="#p" />
<use x="444" y="180" xlink:href="#p" />
<use x="468" y="180" xlink:href="#p" />
<use x="492" y="180" xlink:href="#p" />
<use x="504" y="180" xlink:href="#p" />
<use x="552" y="180" xlink:href="#p" />
<use x="576" y="180" xlink:href="#p" />
<use x="588" y="180" xlink:href="#p" />
<use x="624" y="180" xlink:href="#p" />
<use x="648" y="180" xlink:href="#p" />
<use x="696" y="180" xlink:href="#p" />
<use x="708" y="180" xlink:href="#p" />
<use x="744" y="180" xlink:href="#p" />
<use x="768" y="180" xlink:href="#p" />
<use x="36" y="192" xlink:href="#p" />
<use x="60" y="192" xlink:href="#p" />
<use x="96" y="192" xlink:href="#p" />
<use x="132" y="192" xlink:href="#p" />
<use x="180" y="192" xlink:href="#p" />
<use x="192" y="192" xlink:href="#p" />
<use x="204" y="192" xlink:href="#p" />
<use x="216" y="192" xlink:href="#p" />
<use x="228" y="192" xlink:href="#p" />
<use x="300" y="192" xlink:href="#p" />
<use x="324" y="192" xlink:href="#p" />
<use x="384" y="192" xlink:href="#p" />
<use x="396" y="192" xlink:href="#p" />
<use x="408" y="192" xlink:href="#p" />
<use x="420" y="192" xlink:href="#p" />
<use x="432" y="192" xlink:href="#p" />
<use x="444" y="192" xlink:href="#p" />
<use x="468" y="192" xlink:href="#p" />
<use x="480" y="192" xlink:href="#p" />
<use x="492" y="192" xlink:href="#p" />
<use x="504" y="192" xlink:href="#p" />
<use x="516" y="192" xlink:href="#p" />
<use x="528" y="192" xlink:href="#p" />
<use x="540" y="192" xlink:href="#p" />
<use x="564" y="192" xlink:href="#p" />
<use x="576" y="192" xlink:href="#p" />
<use x="600" y="192" xlink:href="#p" />
<use x="624" y="192" xlink:href="#p" />
<use x="648" y="192" xlink:href="#p" />
<use x="672" y="192" xlink:href="#p" />
<use x="684" y="192" xlink:href="#p" />
<use x="708" y="192" xlink:href="#p" />
<use x="732" y="192" xlink:href="#p" />
<use x="744" y="192" xlink:href="#p" />
<use x="756" y="192" xlink:href="#p" />
<use x="768" y="192" xlink:href="#p" />
<use x="780" y="192" xlink:href="#p" />
<use x="12" y="204" xlink:href="#p" />
<use x="84" y="204" xlink:href="#p" />
<use x="108" y="204" xlink:href="#p" />
<use x="120" y="204" xlink:href="#p" />
<use x="144" y="204" xlink:href="#p" />
<use x="168" y="204" xlink:href="#p" />
<use x="180" y="204" xlink:href="#p" />
<use x="240" y="204" xlink:href="#p" />
<use x="264" y="204" xlink:href="#p" />
<use x="336" y="204" xlink:href="#p" />
<use x="348" y="204" xlink:href="#p" />
<use x="360" y="204" xlink:href="#p" />
<use x="372" y="204" xlink:href="#p" />
<use x="408" y="204" xlink:href="#p" />
<use x="420" y="204" xlink:href="#p" />
<use x="444" y="204" xlink:href="#p" />
<use x="456" y="204" xlink:href="#p" />
<use x="468" y="204" xlink:href="#p" />
<use x="516" y="204" xlink:href="#p" />
<use x="528" y="204" xlink:href="#p" />
<use x="588" y="204" xlink:href="#p" />
<use x="600" y="204" xlink:href="#p" />
<use x="612" y="204" xlink:href="#p" />
<use x="624" y="204" xlink:href="#p" />
<use x="648" y="204" xlink:href="#p" />
<use x="672" y="204" xlink:href="#p" />
<use x="684" y="204" xlink:href="#p" />
<use x="708" y="204" xlink:href="#p" />
<use x="720" y="204" xlink:href="#p" />
<use x="732" y="204" xlink:href="#p" />
<use x="756" y="204" xlink:href="#p" />
<use x="768" y="204" xlink:href="#p" />
<use x="36" y="216" xlink:href="#p" />
<use x="48" y="216" xlink:href="#p" />
<use x="72" y="216" xlink:href="#p" />
<use x="96" y="216" xlink:href="#p" />
<use x="108" y="216" xlink:href="#p" />
<use x="120" y="216" xlink:href="#p" />
<use x="144" y="216" xlink:href="#p" />
<use x="168" y="216" xlink:href="#p" />
<use x="180" y="216" xlink:href="#p" />
<use x="192" y="216" xlink:href="#p" />
<use x="204" y="216" xlink:href="#p" />
<use x="216" y="216" xlink:href="#p" />
<use x="252" y="216" xlink:href="#p" />
<use x="312" y="216" xlink:href="#p" />
<use x="324" y="216" xlink:href="#p" />
<use x="372" y="216" xlink:href="#p" />
<use x="396" y="216" xlink:href="#p" />
<use x="456" y="216" xlink:href="#p" />
<use x="468" y="216" xlink:href="#p" />
<use x="492" y="216" xlink:href="#p" />
<use x="516" y="216" xlink:href="#p" />
<use x="540" y="216" xlink:href="#p" />
<use x="576" y="216" xlink:href="#p" />
<use x="648" y="216" xlink:href="#p" />
<use x="660" y="216" xlink:href="#p" />
<use x="672" y="216" xlink:href="#p" />
<use x="720" y="216" xlink:href="#p" />
<use x="732" y="216" xlink:href="#p" />
<use x="744" y="216" xlink:href="#p" />
<use x="36" y="228" xlink:href="#p" />
<use x="60" y="228" xlink:href="#p" />
<use x="84" y="228" xlink:href="#p" />
<use x="96" y="228" xlink:href="#p" />
<use x="108" y="228" xlink:href="#p" />
<use x="132" y="228" xlink:href="#p" />
<use x="168" y="228" xlink:href="#p" />
<use x="192" y="228" xlink:href="#p" />
<use x="204" y="228" xlink:href="#p" />
<use x="216" y="228" xlink:href="#p" />
<use x="240" y="228" xlink:href="#p" />
<use x="252" y="228" xlink:href="#p" />
<use x="276" y="228" xlink:href="#p" />
<use x="288" y="228" xlink:href="#p" />
<use x="300" y="228" xlink:href="#p" />
<use x="312" y="228" xlink:href="#p" />
<use x="324" y="228" xlink:href="#p" />
<use x="348" y="228" xlink:href="#p" />
<use x="372" y="228" xlink:href="#p" />
<use x="444" y="228" xlink:href="#p" />
<use x="492" y="228" xlink:href="#p" />
<use x="528" y="228" xlink:href="#p" />
<use x="540" y="228" xlink:href="#p" />
<use x="564" y="228" xlink:href="#p" />
<use x="576" y="228" xlink:href="#p" />
<use x="588" y="228" xlink:href="#p" />
<use x="600" y="228" xlink:href="#p" />
<use x="624" y="228" xlink:href="#p" />
<use x="636" y="228" xlink:href="#p" />
<use x="648" y="228" xlink:href="#p" />
<use x="684" y="228" xlink:href="#p" />
<use x="696" y="228" xlink:href="#p" />
<use x="720" y="228" xlink:href="#p" />
<use x="732" y="228" xlink:href="#p" />
<use x="756" y="228" xlink:href="#p" />
<use x="780" y="228" xlink:href="#p" />
<use x="24" y="240" xlink:href="#p" />
<use x="108" y="240" xlink:href="#p" />
<use x="180" y="240" xlink:href="#p" />
<use x="216" y="240" xlink:href="#p" />
<use x="252" y="240" xlink:href="#p" />
<use x="288" y="240" xlink:href="#p" />
<use x="312" y="240" xlink:href="#p" />
<use x="348" y="240" xlink:href="#p" />
<use x="372" y="240" xlink:href="#p" />
<use x="384" y="240" xlink:href="#p" />
<use x="396" y="240" xlink:href="#p" />
<use x="420" y="240" xlink:href="#p" />
<use x="432" y="240" xlink:href="#p" />
<use x="504" y="240" xlink:href="#p" />
<use x="516" y="240" xlink:href="#p" />
<use x="528" y="240" xlink:href="#p" />
<use x="552" y="240" xlink:href="#p" />
<use x="564" y="240" xlink:href="#p" />
<use x="612" y="240" xlink:href="#p" />
<use x="636" y="240" xlink:href="#p" />
<use x="648" y="240" xlink:href="#p" />
<use x="672" y="240" xlink:href="#p" />
<use x="696" y="240" xlink:href="#p" />
<use x="744" y="240" xlink:href="#p" />
<use x="12" y="252" xlink:href="#p" />
<use x="36" y="252" xlink:href="#p" />
<use x="48" y="252" xlink:href="#p" />
<use x="84" y="252" xlink:href="#p" />
<use x="120" y="252" xlink:href="#p" />
<use x="168" y="252" xlink:href="#p" />
<use x="180" y="252" xlink:href="#p" />
<use x="228" y="252" xlink:href="#p" />
<use x="240" y="252" xlink:href="#p" />
<use x="264" y="252" xlink:href="#p" />
<use x="276" y="252" xlink:href="#p" />
<use x="336" y="252" xlink:href="#p" />
<use x="420" y="252" xlink:href="#p" />
<use x="432" y="252" xlink:href="#p" />
<use x="492" y="252" xlink:href="#p" />
<use x="516" y="252" xlink:href="#p" />
<use x="528" y="252" xlink:href="#p" />
<use x="576" y="252" xlink:href="#p" />
<use x="588" y="252" xlink:href="#p" />
<use x="600" y="252" xlink:href="#p" />
<use x="648" y="252" xlink:href="#p" />
<use x="672" y="252" xlink:href="#p" />
<use x="684" y="252" xlink:href="#p" />
<use x="696" y="252" xlink:href="#p" />
<use x="708" y="252" xlink:href="#p" />
<use x="720" y="252" xlink:href="#p" />
<use x="732" y="252" xlink:href="#p" />
<use x="744" y="252" xlink:href="#p" />
<use x="756" y="252" xlink:href="#p" />
<use x="768" y="252" xlink:href="#p" />
<use x="12" y="264" xlink:href="#p" />
<use x="24" y="264" xlink:href="#p" />
<use x="36" y="264" xlink:href="#p" />
<use x="96" y="264" xlink:href="#p" />
<use x="120" y="264" xlink:href="#p" />
<use x="132" y="264" xlink:href="#p" />
<use x="144" y="264" xlink:href="#p" />
<use x="180" y="264" xlink:href="#p" />
<use x="192" y="264" xlink:href="#p" />
<use x="216" y="264" xlink:href="#p" />
<use x="252" y="264" xlink:href="#p" />
<use x="324" y="264" xlink:href="#p" />
<use x="360" y="264" xlink:href="#p" />
<use x="396" y="264" xlink:href="#p" />
<use x="408" y="264" xlink:href="#p" />
<use x="420" y="264" xlink:href="#p" />
<use x="468" y="264" xlink:href="#p" />
<use x="480" y="264" xlink:href="#p" />
<use x="516" y="264" xlink:href="#p" />
<use x="564" y="264" xlink:href="#p" />
<use x="612" y="264" xlink:href="#p" />
<use x="624" y="264" xlink:href="#p" />
<use x="636" y="264" xlink:href="#p" />
<use x="648" y="264" xlink:href="#p" />
<use x="660" y="264" xlink:href="#p" />
<use x="672" y="264" xlink:href="#p" />
<use x="684" y="264" xlink:href="#p" />
<use x="696" y="264" xlink:href="#p" />
<use x="708" y="264" xlink:href="#p" />
<use x="720" y="264" xlink:href="#p" />
<use x="732" y="264" xlink:href="#p" />
<use x="756" y="264" xlink:href="#p" />
<use x="48" y="276" xlink:href="#p" />
<use x="72" y="276" xlink:href="#p" />
<use x="84" y="276" xlink:href="#p" />
<use x="96" y="276" xlink:href="#p" />
<use x="108" y="276" xlink:href="#p" />
<use x="120" y="276" xlink:href="#p" />
<use x="132" y="276" xlink:href="#p" />
<use x="168" y="276" xlink:href="#p" />
<use x="192" y="276" xlink:href="#p" />
<use x="204" y="276" xlink:href="#p" />
<use x="216" y="276" xlink:href="#p" />
<use x="228" y="276" xlink:href="#p" />
<use x="240" y="276" xlink:href="#p" />
<use x="252" y="276" xlink:href="#p" />
<use x="288" y="276" xlink:href="#p" />
<use x="300" y="276" xlink:href="#p" />
<use x="324" y="276" xlink:href="#p" />
<use x="348" y="276" xlink:href="#p" />
<use x="396" y="276" xlink:href="#p" />
<use x="420" y="276" xlink:href="#p" />
<use x="444" y="276" xlink:href="#p" />
<use x="468" y="276" xlink:href="#p" />
<use x="516" y="276" xlink:href="#p" />
<use x="528" y="276" xlink:href="#p" />
<use x="552" y="276" xlink:href="#p" />
<use x="564" y="276" xlink:href="#p" />
<use x="588" y="276" xlink:href="#p" />
<use x="612" y="276" xlink:href="#p" />
<use x="636" y="276" xlink:href="#p" />
<use x="672" y="276" xlink:href="#p" />
<use x="696" y="276" xlink:href="#p" />
<use x="708" y="276" xlink:href="#p" />
<use x="720" y="276" xlink:href="#p" />
<use x="744" y="276" xlink:href="#p" />
<use x="756" y="276" xlink:href="#p" />
<use x="780" y="276" xlink:href="#p" />
<use x="24" y="288" xlink:href="#p" />
<use x="48" y="288" xlink:href="#p" />
<use x="60" y="288" xlink:href="#p" />
<use x="120" y="288" xlink:href="#p" />
<use x="132" y="288" xlink:href="#p" />
<use x="144" y="288" xlink:href="#p" />
<use x="156" y="288" xlink:href="#p" />
<use x="180" y="288" xlink:href="#p" />
<use x="192" y="288" xlink:href="#p" />
<use x="216" y="288" xlink:href="#p" />
<use x="228" y="288" xlink:href="#p" />
<use x="264" y="288" xlink:href="#p" />
<use x="300" y="288" xlink:href="#p" />
<use x="312" y="288" xlink:href="#p" />
<use x="384" y="288" xlink:href="#p" />
<use x="396" y="288" xlink:href="#p" />
<use x="408" y="288" xlink:href="#p" />
<use x="420" y="288" xlink:href="#p" />
<use x="444" y="288" xlink:href="#p" />
<use x="456" y="288" xlink:href="#p" />
<use x="468" y="288" xlink:href="#p" />
<use x="480" y="288" xlink:href="#p" />
<use x="492" y="288" xlink:href="#p" />
<use x="528" y="288" xlink:href="#p" />
<use x="564" y="288" xlink:href="#p" />
<use x="612" y="288" xlink:href="#p" />
<use x="636" y="288" xlink:href="#p" />
<use x="648" y="288" xlink:href="#p" />
<use x="672" y="288" xlink:href="#p" />
<use x="720" y="288" xlink:href="#p" />
<use x="756" y="288" xlink:href="#p" />
<use x="12" y="300" xlink:href="#p" />
<use x="24" y="300" xlink:href="#p" />
<use x="60" y="300" xlink:href="#p" />
<use x="84" y="300" xlink:href="#p" />
<use x="108" y="300" xlink:href="#p" />
<use x="120" y="300" xlink:href="#p" />
<use x="132" y="300" xlink:href="#p" />
<use x="144" y="300" xlink:href="#p" />
<use x="168" y="300" xlink:href="#p" />
<use x="180" y="300" xlink:href="#p" />
<use x="216" y="300" xlink:href="#p" />
<use x="240" y="300" xlink:href="#p" />
<use x="276" y="300" xlink:href="#p" />
<use x="312" y="300" xlink:href="#p" />
<use x="324" y="300" xlink:href="#p" />
<use x="348" y="300" xlink:href="#p" />
<use x="360" y="300" xlink:href="#p" />
<use x="396" y="300" xlink:href="#p" />
<use x="408" y="300" xlink:href="#p" />
<use x="480" y="300" xlink:href="#p" />
<use x="492" y="300" xlink:href="#p" />
<use x="516" y="300" xlink:href="#p" />
<use x="528" y="300" xlink:href="#p" />
<use x="540" y="300" xlink:href="#p" />
<use x="564" y="300" xlink:href="#p" />
<use x="588" y="300" xlink:href="#p" />
<use x="636" y="300" xlink:href="#p" />
<use x="648" y="300" xlink:href="#p" />
<use x="660" y="300" xlink:href="#p" />
<use x="672" y="300" xlink:href="#p" />
<use x="684" y="300" xlink:href="#p" />
<use x="708" y="300" xlink:href="#p" />
<use x="732" y="300" xlink:href="#p" />
<use x="744" y="300" xlink:href="#p" />
<use x="756" y="300" xlink:href="#p" />
<use x="768" y="300" xlink:href="#p" />
<use x="780" y="300" xlink:href="#p" />
<use x="12" y="312" xlink:href="#p" />
<use x="48" y="312" xlink:href="#p" />
<use x="96" y="312" xlink:href="#p" />
<use x="108" y="312" xlink:href="#p" />
<use x="156" y="312" xlink:href="#p" />
<use x="168" y="312" xlink:href="#p" />
<use x="180" y="312" xlink:href="#p" />
<use x="192" y="312" xlink:href="#p" />
<use x="240" y="312" xlink:href="#p" />
<use x="252" y="312" xlink:href="#p" />
<use x="264" y="312" xlink:href="#p" />
<use x="288" y="312" xlink:href="#p" />
<use x="336" y="312" xlink:href="#p" />
<use x="348" y="312" xlink:href="#p" />
<use x="372" y="312" xlink:href="#p" />
<use x="384" y="312" xlink:href="#p" />
<use x="396" y="312" xlink:href="#p" />
<use x="408" y="312" xlink:href="#p" />
<use x="432" y="312" xlink:href="#p" />
<use x="468" y="312" xlink:href="#p" />
<use x="480" y="312" xlink:href="#p" />
<use x="504" y="312" xlink:href="#p" />
<use x="516" y="312" xlink:href="#p" />
<use x="528" y="312" xlink:href="#p" />
<use x="552" y="312" xlink:href="#p" />
<use x="576" y="312" xlink:href="#p" />
<use x="588" y="312" xlink:href="#p" />
<use x="624" y="312" xlink:href="#p" />
<use x="636" y="312" xlink:href="#p" />
<use x="648" y="312" xlink:href="#p" />
<use x="660" y="312" xlink:href="#p" />
<use x="672" y="312" xlink:href="#p" />
<use x="696" y="312" xlink:href="#p" />
<use x="708" y="312" xlink:href="#p" />
<use x="720" y="312" xlink:href="#p" />
<use x="744" y="312" xlink:href="#p" />
<use x="780" y="312" xlink:href="#p" />
<use x="12" y="324" xlink:href="#p" />
<use x="36" y="324" xlink:href="#p" />
<use x="60" y="324" xlink:href="#p" />
<use x="72" y="324" xlink:href="#p" />
<use x="84" y="324" xlink:href="#p" />
<use x="96" y="324" xlink:href="#p" />
<use x="144" y="324" xlink:href="#p" />
<use x="156" y="324" xlink:href="#p" />
<use x="168" y="324" xlink:href="#p" />
<use x="204" y="324" xlink:href="#p" />
<use x="240" y="324" xlink:href="#p" />
<use x="252" y="324" xlink:href="#p" />
<use x="264" y="324" xlink:href="#p" />
<use x="276" y="324" xlink:href="#p" />
<use x="288" y="324" xlink:href="#p" />
<use x="336" y="324" xlink:href="#p" />
<use x="348" y="324" xlink:href="#p" />
<use x="360" y="324" xlink:href="#p" />
<use x="372" y="324" xlink:href="#p" />
<use x="456" y="324" xlink:href="#p" />
<use x="480" y="324" xlink:href="#p" />
<use x="492" y="324" xlink:href="#p" />
<use x="504" y="324" xlink:href="#p" />
<use x="552" y="324" xlink:href="#p" />
<use x="564" y="324" xlink:href="#p" />
<use x="588" y="324" xlink:href="#p" />
<use x="612" y="324" xlink:href="#p" />
<use x="672" y="324" xlink:href="#p" />
<use x="696" y="324" xlink:href="#p" />
<use x="720" y="324" xlink:href="#p" />
<use x="756" y="324" xlink:href="#p" />
<use x="768" y="324" xlink:href="#p" />
<use x="12" y="336" xlink:href="#p" />
<use x="72" y="336" xlink:href="#p" />
<use x="96" y="336" xlink:href="#p" />
<use x="108" y="336" xlink:href="#p" />
<use x="120" y="336" xlink:href="#p" />
<use x="144" y="336" xlink:href="#p" />
<use x="156" y="336" xlink:href="#p" />
<use x="180" y="336" xlink:href="#p" />
<use x="204" y="336" xlink:href="#p" />
<use x="216" y="336" xlink:href="#p" />
<use x="228" y="336" xlink:href="#p" />
<use x="252" y="336" xlink:href="#p" />
<use x="264" y="336" xlink:href="#p" />
<use x="288" y="336" xlink:href="#p" />
<use x="336" y="336" xlink:href="#p" />
<use x="348" y="336" xlink:href="#p" />
<use x="396" y="336" xlink:href="#p" />
<use x="408" y="336" xlink:href="#p" />
<use x="420" y="336" xlink:href="#p" />
<use x="456" y="336" xlink:href="#p" />
<use x="480" y="336" xlink:href="#p" />
<use x="516" y="336" xlink:href="#p" />
<use x="528" y="336" xlink:href="#p" />
<use x="540" y="336" xlink:href="#p" />
<use x="552" y="336" xlink:href="#p" />
<use x="564" y="336" xlink:href="#p" />
<use x="588" y="336" xlink:href="#p" />
<use x="612" y="336" xlink:href="#p" />
<use x="660" y="336" xlink:href="#p" />
<use x="684" y="336" xlink:href="#p" />
<use x="696" y="336" xlink:href="#p" />
<use x="708" y="336" xlink:href="#p" />
<use x="744" y="336" xlink:href="#p" />
<use x="768" y="336" xlink:href="#p" />
<use x="12" y="348" xlink:href="#p" />
<use x="36" y="348" xlink:href="#p" />
<use x="48" y="348" xlink:href="#p" />
<use x="60" y="348" xlink:href="#p" />
<use x="84" y="348" xlink:href="#p" />
<use x="96" y="348" xlink:href="#p" />
<use x="108" y="348" xlink:href="#p" />
<use x="144" y="348" xlink:href="#p" />
<use x="180" y="348" xlink:href="#p" />
<use x="192" y="348" xlink:href="#p" />
<use x="216" y="348" xlink:href="#p" />
<use x="228" y="348" xlink:href="#p" />
<use x="264" y="348" xlink:href="#p" />
<use x="276" y="348" xlink:href="#p" />
<use x="312" y="348" xlink:href="#p" />
<use x="384" y="348" xlink:href="#p" />
<use x="396" y="348" xlink:href="#p" />
<use x="408" y="348" xlink:href="#p" />
<use x="420" y="348" xlink:href="#p" />
<use x="432" y="348" xlink:href="#p" />
<use x="444" y="348" xlink:href="#p" />
<use x="456" y="348" xlink:href="#p" />
<use x="480" y="348" xlink:href="#p" />
<use x="576" y="348" xlink:href="#p" />
<use x="600" y="348" xlink:href="#p" />
<use x="624" y="348" xlink:href="#p" />
<use x="648" y="348" xlink:href="#p" />
<use x="696" y="348" xlink:href="#p" />
<use x="720" y="348" xlink:href="#p" />
<use x="732" y="348" xlink:href="#p" />
<use x="744" y="348" xlink:href="#p" />
<use x="756" y="348" xlink:href="#p" />
<use x="768" y="348" xlink:href="#p" />
<use x="12" y="360" xlink:href="#p" />
<use x="36" y="360" xlink:href="#p" />
<use x="96" y="360" xlink:href="#p" />
<use x="108" y="360" xlink:href="#p" />
<use x="120" y="360" xlink:href="#p" />
<use x="132" y="360" xlink:href="#p" />
<use x="168" y="360" xlink:href="#p" />
<use x="180" y="360" xlink:href="#p" />
<use x="192" y="360" xlink:href="#p" />
<use x="216" y="360" xlink:href="#p" />
<use x="228" y="360" xlink:href="#p" />
<use x="240" y="360" xlink:href="#p" />
<use x="252" y="360" xlink:href="#p" />
<use x="276" y="360" xlink:href="#p" />
<use x="288" y="360" xlink:href="#p" />
<use x="300" y="360" xlink:href="#p" />
<use x="312" y="360" xlink:href="#p" />
<use x="324" y="360" xlink:href="#p" />
<use x="336" y="360" xlink:href="#p" />
<use x="348" y="360" xlink:href="#p" />
<use x="372" y="360" xlink:href="#p" />
<use x="384" y="360" xlink:href="#p" />
<use x="432" y="360" xlink:href="#p" />
<use x="444" y="360" xlink:href="#p" />
<use x="468" y="360" xlink:href="#p" />
<use x="504" y="360" xlink:href="#p" />
<use x="540" y="360" xlink:href="#p" />
<use x="552" y="360" xlink:href="#p" />
<use x="600" y="360" xlink:href="#p" />
<use x="636" y="360" xlink:href="#p" />
<use x="648" y="360" xlink:href="#p" />
<use x="660" y="360" xlink:href="#p" />
<use x="672" y="360" xlink:href="#p" />
<use x="696" y="360" xlink:href="#p" />
<use x="720" y="360" xlink:href="#p" />
<use x="768" y="360" xlink:href="#p" />
<use x="12" y="372" xlink:href="#p" />
<use x="36" y="372" xlink:href="#p" />
<use x="60" y="372" xlink:href="#p" />
<use x="72" y="372" xlink:href="#p" />
<use x="84" y="372" xlink:href="#p" />
<use x="96" y="372" xlink:href="#p" />
<use x="108" y="372" xlink:href="#p" />
<use x="156" y="372" xlink:href="#p" />
<use x="180" y="372" xlink:href="#p" />
<use x="192" y="372" xlink:href="#p" />
<use x="216" y="372" xlink:href="#p" />
<use x="240" y="372" xlink:href="#p" />
<use x="288" y="372" xlink:href="#p" />
<use x="300" y="372" xlink:href="#p" />
<use x="312" y="372" xlink:href="#p" />
<use x="324" y="372" xlink:href="#p" />
<use x="372" y="372" xlink:href="#p" />
<use x="384" y="372" xlink:href="#p" />
<use x="396" y="372" xlink:href="#p" />
<use x="408" y="372" xlink:href="#p" />
<use x="420" y="372" xlink:href="#p" />
<use x="444" y="372" xlink:href="#p" />
<use x="468" y="372" xlink:href="#p" />
<use x="504" y="372" xlink:href="#p" />
<use x="540" y="372" xlink:href="#p" />
<use x="564" y="372" xlink:href="#p" />
<use x="612" y="372" xlink:href="#p" />
<use x="624" y="372" xlink:href="#p" />
<use x="648" y="372" xlink:href="#p" />
<use x="660" y="372" xlink:href="#p" />
<use x="672" y="372" xlink:href="#p" />
<use x="684" y="372" xlink:href="#p" />
<use x="696" y="372" xlink:href="#p" />
<use x="708" y="372" xlink:href="#p" />
<use x="720" y="372" xlink:href="#p" />
<use x="732" y="372" xlink:href="#p" />
<use x="780" y="372" xlink:href="#p" />
<use x="24" y="384" xlink:href="#p" />
<use x="36" y="384" xlink:href="#p" />
<use x="60" y="384" xlink:href="#p" />
<use x="108" y="384" xlink:href="#p" />
<use x="120" y="384" xlink:href="#p" />
<use x="180" y="384" xlink:href="#p" />
<use x="192" y="384" xlink:href="#p" />
<use x="204" y="384" xlink:href="#p" />
<use x="216" y="384" xlink:href="#p" />
<use x="228" y="384" xlink:href="#p" />
<use x="240" y="384" xlink:href="#p" />
<use x="276" y="384" xlink:href="#p" />
<use x="312" y="384" xlink:href="#p" />
<use x="324" y="384" xlink:href="#p" />
<use x="360" y="384" xlink:href="#p" />
<use x="372" y="384" xlink:href="#p" />
<use x="420" y="384" xlink:href="#p" />
<use x="432" y="384" xlink:href="#p" />
<use x="444" y="384" xlink:href="#p" />
<use x="456" y="384" xlink:href="#p" />
<use x="480" y="384" xlink:href="#p" />
<use x="492" y="384" xlink:href="#p" />
<use x="504" y="384" xlink:href="#p" />
<use x="528" y="384" xlink:href="#p" />
<use x="540" y="384" xlink:href="#p" />
<use x="552" y="384" xlink:href="#p" />
<use x="576" y="384" xlink:href="#p" />
<use x="588" y="384" xlink:href="#p" />
<use x="600" y="384" xlink:href="#p" />
<use x="684" y="384" xlink:href="#p" />
<use x="732" y="384" xlink:href="#p" />
<use x="756" y="384" xlink:href="#p" />
<use x="36" y="396" xlink:href="#p" />
<use x="48" y="396" xlink:href="#p" />
<use x="60" y="396" xlink:href="#p" />
<use x="84" y="396" xlink:href="#p" />
<use x="108" y="396" xlink:href="#p" />
<use x="120" y="396" xlink:href="#p" />
<use x="144" y="396" xlink:href="#p" />
<use x="168" y="396" xlink:href="#p" />
<use x="180" y="396" xlink:href="#p" />
<use x="192" y="396" xlink:href="#p" />
<use x="216" y="396" xlink:href="#p" />
<use x="228" y="396" xlink:href="#p" />
<use x="240" y="396" xlink:href="#p" />
<use x="264" y="396" xlink:href="#p" />
<use x="276" y="396" xlink:href="#p" />
<use x="300" y="396" xlink:href="#p" />
<use x="312" y="396" xlink:href="#p" />
<use x="336" y="396" xlink:href="#p" />
<use x="372" y="396" xlink:href="#p" />
<use x="396" y="396" xlink:href="#p" />
<use x="420" y="396" xlink:href="#p" />
<use x="432" y="396" xlink:href="#p" />
<use x="456" y="396" xlink:href="#p" />
<use x="468" y="396" xlink:href="#p" />
<use x="480" y="396" xlink:href="#p" />
<use x="516" y="396" xlink:href="#p" />
<use x="528" y="396" xlink:href="#p" />
<use x="552" y="396" xlink:href="#p" />
<use x="564" y="396" xlink:href="#p" />
<use x="576" y="396" xlink:href="#p" />
<use x="600" y="396" xlink:href="#p" />
<use x="624" y="396" xlink:href="#p" />
<use x="648" y="396" xlink:href="#p" />
<use x="660" y="396" xlink:href="#p" />
<use x="684" y="396" xlink:href="#p" />
<use x="708" y="396" xlink:href="#p" />
<use x="732" y="396" xlink:href="#p" />
<use x="12" y="408" xlink:href="#p" />
<use x="24" y="408" xlink:href="#p" />
<use x="36" y="408" xlink:href="#p" />
<use x="48" y="408" xlink:href="#p" />
<use x="60" y="408" xlink:href="#p" />
<use x="108" y="408" xlink:href="#p" />
<use x="120" y="408" xlink:href="#p" />
<use x="132" y="408" xlink:href="#p" />
<use x="144" y="408" xlink:href="#p" />
<use x="204" y="408" xlink:href="#p" />
<use x="216" y="408" xlink:href="#p" />
<use x="228" y="408" xlink:href="#p" />
<use x="240" y="408" xlink:href="#p" />
<use x="252" y="408" xlink:href="#p" />
<use x="300" y="408" xlink:href="#p" />
<use x="324" y="408" xlink:href="#p" />
<use x="360" y="408" xlink:href="#p" />
<use x="372" y="408" xlink:href="#p" />
<use x="420" y="408" xlink:href="#p" />
<use x="480" y="408" xlink:href="#p" />
<use x="492" y="408" xlink:href="#p" />
<use x="528" y="408" xlink:href="#p" />
<use x="552" y="408" xlink:href="#p" />
<use x="564" y="408" xlink:href="#p" />
<use x="588" y="408" xlink:href="#p" />
<use x="612" y="408" xlink:href="#p" />
<use x="636" y="408" xlink:href="#p" />
<use x="660" y="408" xlink:href="#p" />
<use x="684" y="408" xlink:href="#p" />
<use x="732" y="408" xlink:href="#p" />
<use x="744" y="408" xlink:href="#p" />
<use x="756" y="408" xlink:href="#p" />
<use x="768" y="408" xlink:href="#p" />
<use x="12" y="420" xlink:href="#p" />
<use x="24" y="420" xlink:href="#p" />
<use x="60" y="420" xlink:href="#p" />
<use x="72" y="420" xlink:href="#p" />
<use x="84" y="420" xlink:href="#p" />
<use x="96" y="420" xlink:href="#p" />
<use x="108" y="420" xlink:href="#p" />
<use x="120" y="420" xlink:href="#p" />
<use x="144" y="420" xlink:href="#p" />
<use x="156" y="420" xlink:href="#p" />
<use x="168" y="420" xlink:href="#p" />
<use x="180" y="420" xlink:href="#p" />
<use x="192" y="420" xlink:href="#p" />
<use x="204" y="420" xlink:href="#p" />
<use x="228" y="420" xlink:href="#p" />
<use x="240" y="420" xlink:href="#p" />
<use x="324" y="420" xlink:href="#p" />
<use x="336" y="420" xlink:href="#p" />
<use x="348" y="420" xlink:href="#p" />
<use x="372" y="420" xlink:href="#p" />
<use x="384" y="420" xlink:href="#p" />
<use x="396" y="420" xlink:href="#p" />
<use x="408" y="420" xlink:href="#p" />
<use x="420" y="420" xlink:href="#p" />
<use x="444" y="420" xlink:href="#p" />
<use x="480" y="420" xlink:href="#p" />
<use x="492" y="420" xlink:href="#p" />
<use x="504" y="420" xlink:href="#p" />
<use x="516" y="420" xlink:href="#p" />
<use x="552" y="420" xlink:href="#p" />
<use x="576" y="420" xlink:href="#p" />
<use x="588" y="420" xlink:href="#p" />
<use x="600" y="420" xlink:href="#p" />
<use x="612" y="420" xlink:href="#p" />
<use x="624" y="420" xlink:href="#p" />
<use x="648" y="420" xlink:href="#p" />
<use x="672" y="420" xlink:href="#p" />
<use x="684" y="420" xlink:href="#p" />
<use x="696" y="420" xlink:href="#p" />
<use x="708" y="420" xlink:href="#p" />
<use x="720" y="420" xlink:href="#p" />
<use x="732" y="420" xlink:href="#p" />
<use x="768" y="420" xlink:href="#p" />
<use x="48" y="432" xlink:href="#p" />
<use x="60" y="432" xlink:href="#p" />
<use x="120" y="432" xlink:href="#p" />
<use x="132" y="432" xlink:href="#p" />
<use x="144" y="432" xlink:href="#p" />
<use x="168" y="432" xlink:href="#p" />
<use x="180" y="432" xlink:href="#p" />
<use x="192" y="432" xlink:href="#p" />
<use x="204" y="432" xlink:href="#p" />
<use x="216" y="432" xlink:href="#p" />
<use x="228" y="432" xlink:href="#p" />
<use x="252" y="432" xlink:href="#p" />
<use x="300" y="432" xlink:href="#p" />
<use x="348" y="432" xlink:href="#p" />
<use x="372" y="432" xlink:href="#p" />
<use x="396" y="432" xlink:href="#p" />
<use x="408" y="432" xlink:href="#p" />
<use x="432" y="432" xlink:href="#p" />
<use x="444" y="432" xlink:href="#p" />
<use x="468" y="432" xlink:href="#p" />
<use x="480" y="432" xlink:href="#p" />
<use x="492" y="432" xlink:href="#p" />
<use x="552" y="432" xlink:href="#p" />
<use x="564" y="432" xlink:href="#p" />
<use x="600" y="432" xlink:href="#p" />
<use x="612" y="432" xlink:href="#p" />
<use x="648" y="432" xlink:href="#p" />
<use x="660" y="432" xlink:href="#p" />
<use x="672" y="432" xlink:href="#p" />
<use x="696" y="432" xlink:href="#p" />
<use x="708" y="432" xlink:href="#p" />
<use x="732" y="432" xlink:href="#p" />
<use x="780" y="432" xlink:href="#p" />
<use x="48" y="444" xlink:href="#p" />
<use x="60" y="444" xlink:href="#p" />
<use x="72" y="444" xlink:href="#p" />
<use x="84" y="444" xlink:href="#p" />
<use x="108" y="444" xlink:href="#p" />
<use x="156" y="444" xlink:href="#p" />
<use x="192" y="444" xlink:href="#p" />
<use x="204" y="444" xlink:href="#p" />
<use x="216" y="444" xlink:href="#p" />
<use x="240" y="444" xlink:href="#p" />
<use x="252" y="444" xlink:href="#p" />
<use x="288" y="444" xlink:href="#p" />
<use x="336" y="444" xlink:href="#p" />
<use x="348" y="444" xlink:href="#p" />
<use x="396" y="444" xlink:href="#p" />
<use x="432" y="444" xlink:href="#p" />
<use x="444" y="444" xlink:href="#p" />
<use x="456" y="444" xlink:href="#p" />
<use x="468" y="444" xlink:href="#p" />
<use x="492" y="444" xlink:href="#p" />
<use x="504" y="444" xlink:href="#p" />
<use x="516" y="444" xlink:href="#p" />
<use x="540" y="444" xlink:href="#p" />
<use x="600" y="444" xlink:href="#p" />
<use x="612" y="444" xlink:href="#p" />
<use x="624" y="444" xlink:href="#p" />
<use x="636" y="444" xlink:href="#p" />
<use x="648" y="444" xlink:href="#p" />
<use x="660" y="444" xlink:href="#p" />
<use x="672" y="444" xlink:href="#p" />
<use x="684" y="444" xlink:href="#p" />
<use x="744" y="444" xlink:href="#p" />
<use x="780" y="444" xlink:href="#p" />
<use x="48" y="456" xlink:href="#p" />
<use x="96" y="456" xlink:href="#p" />
<use x="108" y="456" xlink:href="#p" />
<use x="180" y="456" xlink:href="#p" />
<use x="192" y="456" xlink:href="#p" />
<use x="216" y="456" xlink:href="#p" />
<use x="228" y="456" xlink:href="#p" />
<use x="264" y="456" xlink:href="#p" />
<use x="276" y="456" xlink:href="#p" />
<use x="348" y="456" xlink:href="#p" />
<use x="360" y="456" xlink:href="#p" />
<use x="408" y="456" xlink:href="#p" />
<use x="468" y="456" xlink:href="#p" />
<use x="480" y="456" xlink:href="#p" />
<use x="492" y="456" xlink:href="#p" />
<use x="504" y="456" xlink:href="#p" />
<use x="588" y="456" xlink:href="#p" />
<use x="600" y="456" xlink:href="#p" />
<use x="612" y="456" xlink:href="#p" />
<use x="624" y="456" xlink:href="#p" />
<use x="636" y="456" xlink:href="#p" />
<use x="660" y="456" xlink:href="#p" />
<use x="672" y="456" xlink:href="#p" />
<use x="696" y="456" xlink:href="#p" />
<use x="708" y="456" xlink:href="#p" />
<use x="720" y="456" xlink:href="#p" />
<use x="732" y="456" xlink:href="#p" />
<use x="744" y="456" xlink:href="#p" />
<use x="756" y="456" xlink:href="#p" />
<use x="12" y="468" xlink:href="#p" />
<use x="48" y="468" xlink:href="#p" />
<use x="60" y="468" xlink:href="#p" />
<use x="72" y="468" xlink:href="#p" />
<use x="84" y="468" xlink:href="#p" />
<use x="96" y="468" xlink:href="#p" />
<use x="120" y="468" xlink:href="#p" />
<use x="132" y="468" xlink:href="#p" />
<use x="180" y="468" xlink:href="#p" />
<use x="216" y="468" xlink:href="#p" />
<use x="240" y="468" xlink:href="#p" />
<use x="252" y="468" xlink:href="#p" />
<use x="276" y="468" xlink:href="#p" />
<use x="288" y="468" xlink:href="#p" />
<use x="300" y="468" xlink:href="#p" />
<use x="324" y="468" xlink:href="#p" />
<use x="336" y="468" xlink:href="#p" />
<use x="348" y="468" xlink:href="#p" />
<use x="372" y="468" xlink:href="#p" />
<use x="408" y="468" xlink:href="#p" />
<use x="444" y="468" xlink:href="#p" />
<use x="480" y="468" xlink:href="#p" />
<use x="492" y="468" xlink:href="#p" />
<use x="516" y="468" xlink:href="#p" />
<use x="528" y="468" xlink:href="#p" />
<use x="552" y="468" xlink:href="#p" />
<use x="564" y="468" xlink:href="#p" />
<use x="576" y="468" xlink:href="#p" />
<use x="588" y="468" xlink:href="#p" />
<use x="732" y="468" xlink:href="#p" />
<use x="744" y="468" xlink:href="#p" />
<use x="768" y="468" xlink:href="#p" />
<use x="36" y="480" xlink:href="#p" />
<use x="48" y="480" xlink:href="#p" />
<use x="72" y="480" xlink:href="#p" />
<use x="96" y="480" xlink:href="#p" />
<use x="108" y="480" xlink:href="#p" />
<use x="120" y="480" xlink:href="#p" />
<use x="132" y="480" xlink:href="#p" />
<use x="168" y="480" xlink:href="#p" />
<use x="228" y="480" xlink:href="#p" />
<use x="240" y="480" xlink:href="#p" />
<use x="264" y="480" xlink:href="#p" />
<use x="276" y="480" xlink:href="#p" />
<use x="288" y="480" xlink:href="#p" />
<use x="312" y="480" xlink:href="#p" />
<use x="336" y="480" xlink:href="#p" />
<use x="348" y="480" xlink:href="#p" />
<use x="372" y="480" xlink:href="#p" />
<use x="384" y="480" xlink:href="#p" />
<use x="396" y="480" xlink:href="#p" />
<use x="432" y="480" xlink:href="#p" />
<use x="444" y="480" xlink:href="#p" />
<use x="468" y="480" xlink:href="#p" />
<use x="504" y="480" xlink:href="#p" />
<use x="528" y="480" xlink:href="#p" />
<use x="600" y="480" xlink:href="#p" />
<use x="612" y="480" xlink:href="#p" />
<use x="636" y="480" xlink:href="#p" />
<use x="648" y="480" xlink:href="#p" />
<use x="660" y="480" xlink:href="#p" />
<use x="672" y="480" xlink:href="#p" />
<use x="684" y="480" xlink:href="#p" />
<use x="780" y="480" xlink:href="#p" />
<use x="12" y="492" xlink:href="#p" />
<use x="24" y="492" xlink:href="#p" />
<use x="60" y="492" xlink:href="#p" />
<use x="84" y="492" xlink:href="#p" />
<use x="96" y="492" xlink:href="#p" />
<use x="132" y="492" xlink:href="#p" />
<use x="144" y="492" xlink:href="#p" />
<use x="180" y="492" xlink:href="#p" />
<use x="204" y="492" xlink:href="#p" />
<use x="240" y="492" xlink:href="#p" />
<use x="252" y="492" xlink:href="#p" />
<use x="300" y="492" xlink:href="#p" />
<use x="372" y="492" xlink:href="#p" />
<use x="384" y="492" xlink:href="#p" />
<use x="396" y="492" xlink:href="#p" />
<use x="408" y="492" xlink:href="#p" />
<use x="420" y="492" xlink:href="#p" />
<use x="432" y="492" xlink:href="#p" />
<use x="444" y="492" xlink:href="#p" />
<use x="480" y="492" xlink:href="#p" />
<use x="528" y="492" xlink:href="#p" />
<use x="552" y="492" xlink:href="#p" />
<use x="564" y="492" xlink:href="#p" />
<use x="588" y="492" xlink:href="#p" />
<use x="600" y="492" xlink:href="#p" />
<use x="612" y="492" xlink:href="#p" />
<use x="636" y="492" xlink:href="#p" />
<use x="684" y="492" xlink:href="#p" />
<use x="696" y="492" xlink:href="#p" />
<use x="720" y="492" xlink:href="#p" />
<use x="732" y="492" xlink:href="#p" />
<use x="768" y="492" xlink:href="#p" />
<use x="12" y="504" xlink:href="#p" />
<use x="36" y="504" xlink:href="#p" />
<use x="48" y="504" xlink:href="#p" />
<use x="96" y="504" xlink:href="#p" />
<use x="156" y="504" xlink:href="#p" />
<use x="216" y="504" xlink:href="#p" />
<use x="228" y="504" xlink:href="#p" />
<use x="276" y="504" xlink:href="#p" />
<use x="288" y="504" xlink:href="#p" />
<use x="324" y="504" xlink:href="#p" />
<use x="372" y="504" xlink:href="#p" />
<use x="420" y="504" xlink:href="#p" />
<use x="444" y="504" xlink:href="#p" />
<use x="456" y="504" xlink:href="#p" />
<use x="480" y="504" xlink:href="#p" />
<use x="492" y="504" xlink:href="#p" />
<use x="516" y="504" xlink:href="#p" />
<use x="540" y="504" xlink:href="#p" />
<use x="552" y="504" xlink:href="#p" />
<use x="576" y="504" xlink:href="#p" />
<use x="600" y="504" xlink:href="#p" />
<use x="636" y="504" xlink:href="#p" />
<use x="648" y="504" xlink:href="#p" />
<use x="660" y="504" xlink:href="#p" />
<use x="684" y="504" xlink:href="#p" />
<use x="696" y="504" xlink:href="#p" />
<use x="720" y="504" xlink:href="#p" />
<use x="732" y="504" xlink:href="#p" />
<use x="756" y="504" xlink:href="#p" />
<use x="768" y="504" xlink:href="#p" />
<use x="780" y="504" xlink:href="#p" />
<use x="24" y="516" xlink:href="#p" />
<use x="60" y="516" xlink:href="#p" />
<use x="84" y="516" xlink:href="#p" />
<use x="96" y="516" xlink:href="#p" />
<use x="108" y="516" xlink:href="#p" />
<use x="144" y="516" xlink:href="#p" />
<use x="180" y="516" xlink:href="#p" />
<use x="192" y="516" xlink:href="#p" />
<use x="228" y="516" xlink:href="#p" />
<use x="264" y="516" xlink:href="#p" />
<use x="348" y="516" xlink:href="#p" />
<use x="360" y="516" xlink:href="#p" />
<use x="372" y="516" xlink:href="#p" />
<use x="384" y="516" xlink:href="#p" />
<use x="444" y="516" xlink:href="#p" />
<use x="468" y="516" xlink:href="#p" />
<use x="492" y="516" xlink:href="#p" />
<use x="504" y="516" xlink:href="#p" />
<use x="540" y="516" xlink:href="#p" />
<use x="564" y="516" xlink:href="#p" />
<use x="576" y="516" xlink:href="#p" />
<use x="588" y="516" xlink:href="#p" />
<use x="600" y="516" xlink:href="#p" />
<use x="612" y="516" xlink:href="#p" />
<use x="636" y="516" xlink:href="#p" />
<use x="660" y="516" xlink:href="#p" />
<use x="708" y="516" xlink:href="#p" />
<use x="720" y="516" xlink:href="#p" />
<use x="732" y="516" xlink:href="#p" />
<use x="780" y="516" xlink:href="#p" />
<use x="24" y="528" xlink:href="#p" />
<use x="36" y="528" xlink:href="#p" />
<use x="48" y="528" xlink:href="#p" />
<use x="60" y="528" xlink:href="#p" />
<use x="72" y="528" xlink:href="#p" />
<use x="108" y="528" xlink:href="#p" />
<use x="132" y="528" xlink:href="#p" />
<use x="168" y="528" xlink:href="#p" />
<use x="192" y="528" xlink:href="#p" />
<use x="204" y="528" xlink:href="#p" />
<use x="252" y="528" xlink:href="#p" />
<use x="276" y="528" xlink:href="#p" />
<use x="300" y="528" xlink:href="#p" />
<use x="312" y="528" xlink:href="#p" />
<use x="336" y="528" xlink:href="#p" />
<use x="372" y="528" xlink:href="#p" />
<use x="396" y="528" xlink:href="#p" />
<use x="408" y="528" xlink:href="#p" />
<use x="432" y="528" xlink:href="#p" />
<use x="456" y="528" xlink:href="#p" />
<use x="468" y="528" xlink:href="#p" />
<use x="480" y="528" xlink:href="#p" />
<use x="492" y="528" xlink:href="#p" />
<use x="504" y="528" xlink:href="#p" />
<use x="516" y="528" xlink:href="#p" />
<use x="552" y="528" xlink:href="#p" />
<use x="588" y="528" xlink:href="#p" />
<use x="600" y="528" xlink:href="#p" />
<use x="636" y="528" xlink:href="#p" />
<use x="648" y="528" xlink:href="#p" />
<use x="660" y="528" xlink:href="#p" />
<use x="672" y="528" xlink:href="#p" />
<use x="684" y="528" xlink:href="#p" />
<use x="696" y="528" xlink:href="#p" />
<use x="708" y="528" xlink:href="#p" />
<use x="720" y="528" xlink:href="#p" />
<use x="744" y="528" xlink:href="#p" />
<use x="768" y="528" xlink:href="#p" />
<use x="60" y="540" xlink:href="#p" />
<use x="72" y="540" xlink:href="#p" />
<use x="84" y="540" xlink:href="#p" />
<use x="96" y="540" xlink:href="#p" />
<use x="120" y="540" xlink:href="#p" />
<use x="156" y="540" xlink:href="#p" />
<use x="228" y="540" xlink:href="#p" />
<use x="240" y="540" xlink:href="#p" />
<use x="252" y="540" xlink:href="#p" />
<use x="264" y="540" xlink:href="#p" />
<use x="276" y="540" xlink:href="#p" />
<use x="288" y="540" xlink:href="#p" />
<use x="348" y="540" xlink:href="#p" />
<use x="360" y="540" xlink:href="#p" />
<use x="384" y="540" xlink:href="#p" />
<use x="396" y="540" xlink:href="#p" />
<use x="420" y="540" xlink:href="#p" />
<use x="432" y="540" xlink:href="#p" />
<use x="456" y="540" xlink:href="#p" />
<use x="480" y="540" xlink:href="#p" />
<use x="492" y="540" xlink:href="#p" />
<use x="504" y="540" xlink:href="#p" />
<use x="516" y="540" xlink:href="#p" />
<use x="528" y="540" xlink:href="#p" />
<use x="552" y="540" xlink:href="#p" />
<use x="564" y="540" xlink:href="#p" />
<use x="576" y="540" xlink:href="#p" />
<use x="588" y="540" xlink:href="#p" />
<use x="612" y="540" xlink:href="#p" />
<use x="624" y="540" xlink:href="#p" />
<use x="636" y="540" xlink:href="#p" />
<use x="660" y="540" xlink:href="#p" />
<use x="708" y="540" xlink:href="#p" />
<use x="720" y="540" xlink:href="#p" />
<use x="732" y="540" xlink:href="#p" />
<use x="756" y="540" xlink:href="#p" />
<use x="768" y="540" xlink:href="#p" />
<use x="60" y="552" xlink:href="#p" />
<use x="96" y="552" xlink:href="#p" />
<use x="120" y="552" xlink:href="#p" />
<use x="156" y="552" xlink:href="#p" />
<use x="180" y="552" xlink:href="#p" />
<use x="204" y="552" xlink:href="#p" />
<use x="216" y="552" xlink:href="#p" />
<use x="228" y="552" xlink:href="#p" />
<use x="252" y="552" xlink:href="#p" />
<use x="264" y="552" xlink:href="#p" />
<use x="276" y="552" xlink:href="#p" />
<use x="288" y="552" xlink:href="#p" />
<use x="300" y="552" xlink:href="#p" />
<use x="312" y="552" xlink:href="#p" />
<use x="360" y="552" xlink:href="#p" />
<use x="396" y="552" xlink:href="#p" />
<use x="408" y="552" xlink:href="#p" />
<use x="420" y="552" xlink:href="#p" />
<use x="432" y="552" xlink:href="#p" />
<use x="480" y="552" xlink:href="#p" />
<use x="492" y="552" xlink:href="#p" />
<use x="504" y="552" xlink:href="#p" />
<use x="552" y="552" xlink:href="#p" />
<use x="564" y="552" xlink:href="#p" />
<use x="612" y="552" xlink:href="#p" />
<use x="708" y="552" xlink:href="#p" />
<use x="720" y="552" xlink:href="#p" />
<use x="732" y="552" xlink:href="#p" />
<use x="744" y="552" xlink:href="#p" />
<use x="48" y="564" xlink:href="#p" />
<use x="60" y="564" xlink:href="#p" />
<use x="84" y="564" xlink:href="#p" />
<use x="108" y="564" xlink:href="#p" />
<use x="168" y="564" xlink:href="#p" />
<use x="192" y="564" xlink:href="#p" />
<use x="204" y="564" xlink:href="#p" />
<use x="228" y="564" xlink:href="#p" />
<use x="240" y="564" xlink:href="#p" />
<use x="264" y="564" xlink:href="#p" />
<use x="300" y="564" xlink:href="#p" />
<use x="312" y="564" xlink:href="#p" />
<use x="324" y="564" xlink:href="#p" />
<use x="348" y="564" xlink:href="#p" />
<use x="372" y="564" xlink:href="#p" />
<use x="384" y="564" xlink:href="#p" />
<use x="444" y="564" xlink:href="#p" />
<use x="456" y="564" xlink:href="#p" />
<use x="480" y="564" xlink:href="#p" />
<use x="492" y="564" xlink:href="#p" />
<use x="516" y="564" xlink:href="#p" />
<use x="528" y="564" xlink:href="#p" />
<use x="540" y="564" xlink:href="#p" />
<use x="552" y="564" xlink:href="#p" />
<use x="576" y="564" xlink:href="#p" />
<use x="588" y="564" xlink:href="#p" />
<use x="600" y="564" xlink:href="#p" />
<use x="648" y="564" xlink:href="#p" />
<use x="660" y="564" xlink:href="#p" />
<use x="684" y="564" xlink:href="#p" />
<use x="696" y="564" xlink:href="#p" />
<use x="720" y="564" xlink:href="#p" />
<use x="756" y="564" xlink:href="#p" />
<use x="12" y="576" xlink:href="#p" />
<use x="72" y="576" xlink:href="#p" />
<use x="96" y="576" xlink:href="#p" />
<use x="108" y="576" xlink:href="#p" />
<use x="120" y="576" xlink:href="#p" />
<use x="168" y="576" xlink:href="#p" />
<use x="252" y="576" xlink:href="#p" />
<use x="336" y="576" xlink:href="#p" />
<use x="396" y="576" xlink:href="#p" />
<use x="444" y="576" xlink:href="#p" />
<use x="456" y="576" xlink:href="#p" />
<use x="468" y="576" xlink:href="#p" />
<use x="480" y="576" xlink:href="#p" />
<use x="516" y="576" xlink:href="#p" />
<use x="540" y="576" xlink:href="#p" />
<use x="552" y="576" xlink:href="#p" />
<use x="600" y="576" xlink:href="#p" />
<use x="624" y="576" xlink:href="#p" />
<use x="648" y="576" xlink:href="#p" />
<use x="660" y="576" xlink:href="#p" />
<use x="672" y="576" xlink:href="#p" />
<use x="684" y="576" xlink:href="#p" />
<use x="696" y="576" xlink:href="#p" />
<use x="708" y="576" xlink:href="#p" />
<use x="732" y="576" xlink:href="#p" />
<use x="744" y="576" xlink:href="#p" />
<use x="768" y="576" xlink:href="#p" />
<use x="780" y="576" xlink:href="#p" />
<use x="36" y="588" xlink:href="#p" />
<use x="48" y="588" xlink:href="#p" />
<use x="60" y="588" xlink:href="#p" />
<use x="84" y="588" xlink:href="#p" />
<use x="96" y="588" xlink:href="#p" />
<use x="108" y="588" xlink:href="#p" />
<use x="120" y="588" xlink:href="#p" />
<use x="168" y="588" xlink:href="#p" />
<use x="180" y="588" xlink:href="#p" />
<use x="192" y="588" xlink:href="#p" />
<use x="216" y="588" xlink:href="#p" />
<use x="228" y="588" xlink:href="#p" />
<use x="240" y="588" xlink:href="#p" />
<use x="288" y="588" xlink:href="#p" />
<use x="300" y="588" xlink:href="#p" />
<use x="312" y="588" xlink:href="#p" />
<use x="324" y="588" xlink:href="#p" />
<use x="336" y="588" xlink:href="#p" />
<use x="348" y="588" xlink:href="#p" />
<use x="360" y="588" xlink:href="#p" />
<use x="372" y="588" xlink:href="#p" />
<use x="384" y="588" xlink:href="#p" />
<use x="432" y="588" xlink:href="#p" />
<use x="456" y="588" xlink:href="#p" />
<use x="468" y="588" xlink:href="#p" />
<use x="480" y="588" xlink:href="#p" />
<use x="492" y="588" xlink:href="#p" />
<use x="504" y="588" xlink:href="#p" />
<use x="516" y="588" xlink:href="#p" />
<use x="540" y="588" xlink:href="#p" />
<use x="564" y="588" xlink:href="#p" />
<use x="576" y="588" xlink:href="#p" />
<use x="600" y="588" xlink:href="#p" />
<use x="612" y="588" xlink:href="#p" />
<use x="672" y="588" xlink:href="#p" />
<use x="684" y="588" xlink:href="#p" />
<use x="708" y="588" xlink:href="#p" />
<use x="732" y="588" xlink:href="#p" />
<use x="744" y="588" xlink:href="#p" />
<use x="24" y="600" xlink:href="#p" />
<use x="36" y="600" xlink:href="#p" />
<use x="60" y="600" xlink:href="#p" />
<use x="72" y="600" xlink:href="#p" />
<use x="120" y="600" xlink:href="#p" />
<use x="156" y="600" xlink:href="#p" />
<use x="168" y="600" xlink:href="#p" />
<use x="180" y="600" xlink:href="#p" />
<use x="204" y="600" xlink:href="#p" />
<use x="216" y="600" xlink:href="#p" />
<use x="264" y="600" xlink:href="#p" />
<use x="276" y="600" xlink:href="#p" />
<use x="288" y="600" xlink:href="#p" />
<use x="300" y="600" xlink:href="#p" />
<use x="324" y="600" xlink:href="#p" />
<use x="336" y="600" xlink:href="#p" />
<use x="360" y="600" xlink:href="#p" />
<use x="396" y="600" xlink:href="#p" />
<use x="408" y="600" xlink:href="#p" />
<use x="480" y="600" xlink:href="#p" />
<use x="492" y="600" xlink:href="#p" />
<use x="516" y="600" xlink:href="#p" />
<use x="540" y="600" xlink:href="#p" />
<use x="576" y="600" xlink:href="#p" />
<use x="600" y="600" xlink:href="#p" />
<use x="612" y="600" xlink:href="#p" />
<use x="636" y="600" xlink:href="#p" />
<use x="660" y="600" xlink:href="#p" />
<use x="672" y="600" xlink:href="#p" />
<use x="696" y="600" xlink:href="#p" />
<use x="720" y="600" xlink:href="#p" />
<use x="732" y="600" xlink:href="#p" />
<use x="744" y="600" xlink:href="#p" />
<use x="756" y="600" xlink:href="#p" />
<use x="768" y="600" xlink:href="#p" />
<use x="780" y="600" xlink:href="#p" />
<use x="12" y="612" xlink:href="#p" />
<use x="24" y="612" xlink:href="#p" />
<use x="36" y="612" xlink:href="#p" />
<use x="48" y="612" xlink:href="#p" />
<use x="60" y="612" xlink:href="#p" />
<use x="84" y="612" xlink:href="#p" />
<use x="120" y="612" xlink:href="#p" />
<use x="144" y="612" xlink:href="#p" />
<use x="156" y="612" xlink:href="#p" />
<use x="216" y="612" xlink:href="#p" />
<use x="228" y="612" xlink:href="#p" />
<use x="264" y="612" xlink:href="#p" />
<use x="276" y="612" xlink:href="#p" />
<use x="288" y="612" xlink:href="#p" />
<use x="300" y="612" xlink:href="#p" />
<use x="324" y="612" xlink:href="#p" />
<use x="336" y="612" xlink:href="#p" />
<use x="348" y="612" xlink:href="#p" />
<use x="360" y="612" xlink:href="#p" />
<use x="372" y="612" xlink:href="#p" />
<use x="384" y="612" xlink:href="#p" />
<use x="420" y="612" xlink:href="#p" />
<use x="468" y="612" xlink:href="#p" />
<use x="516" y="612" xlink:href="#p" />
<use x="528" y="612" xlink:href="#p" />
<use x="600" y="612" xlink:href="#p" />
<use x="612" y="612" xlink:href="#p" />
<use x="648" y="612" xlink:href="#p" />
<use x="684" y="612" xlink:href="#p" />
<use x="744" y="612" xlink:href="#p" />
<use x="768" y="612" xlink:href="#p" />
<use x="48" y="624" xlink:href="#p" />
<use x="72" y="624" xlink:href="#p" />
<use x="132" y="624" xlink:href="#p" />
<use x="192" y="624" xlink:href="#p" />
<use x="204" y="624" xlink:href="#p" />
<use x="240" y="624" xlink:href="#p" />
<use x="264" y="624" xlink:href="#p" />
<use x="288" y="624" xlink:href="#p" />
<use x="312" y="624" xlink:href="#p" />
<use x="324" y="624" xlink:href="#p" />
<use x="348" y="624" xlink:href="#p" />
<use x="360" y="624" xlink:href="#p" />
<use x="372" y="624" xlink:href="#p" />
<use x="384" y="624" xlink:href="#p" />
<use x="408" y="624" xlink:href="#p" />
<use x="444" y="624" xlink:href="#p" />
<use x="456" y="624" xlink:href="#p" />
<use x="480" y="624" xlink:href="#p" />
<use x="552" y="624" xlink:href="#p" />
<use x="564" y="624" xlink:href="#p" />
<use x="576" y="624" xlink:href="#p" />
<use x="612" y="624" xlink:href="#p" />
<use x="660" y="624" xlink:href="#p" />
<use x="684" y="624" xlink:href="#p" />
<use x="696" y="624" xlink:href="#p" />
<use x="708" y="624" xlink:href="#p" />
<use x="732" y="624" xlink:href="#p" />
<use x="756" y="624" xlink:href="#p" />
<use x="780" y="624" xlink:href="#p" />
<use x="36" y="636" xlink:href="#p" />
<use x="48" y="636" xlink:href="#p" />
<use x="72" y="636" xlink:href="#p" />
<use x="84" y="636" xlink:href="#p" />
<use x="96" y="636" xlink:href="#p" />
<use x="108" y="636" xlink:href="#p" />
<use x="132" y="636" xlink:href="#p" />
<use x="168" y="636" xlink:href="#p" />
<use x="180" y="636" xlink:href="#p" />
<use x="192" y="636" xlink:href="#p" />
<use x="228" y="636" xlink:href="#p" />
<use x="276" y="636" xlink:href="#p" />
<use x="288" y="636" xlink:href="#p" />
<use x="300" y="636" xlink:href="#p" />
<use x="324" y="636" xlink:href="#p" />
<use x="348" y="636" xlink:href="#p" />
<use x="360" y="636" xlink:href="#p" />
<use x="372" y="636" xlink:href="#p" />
<use x="408" y="636" xlink:href="#p" />
<use x="420" y="636" xlink:href="#p" />
<use x="444" y="636" xlink:href="#p" />
<use x="456" y="636" xlink:href="#p" />
<use x="468" y="636" xlink:href="#p" />
<use x="492" y="636" xlink:href="#p" />
<use x="516" y="636" xlink:href="#p" />
<use x="528" y="636" xlink:href="#p" />
<use x="552" y="636" xlink:href="#p" />
<use x="564" y="636" xlink:href="#p" />
<use x="576" y="636" xlink:href="#p" />
<use x="588" y="636" xlink:href="#p" />
<use x="600" y="636" xlink:href="#p" />
<use x="612" y="636" xlink:href="#p" />
<use x="624" y="636" xlink:href="#p" />
<use x="660" y="636" xlink:href="#p" />
<use x="672" y="636" xlink:href="#p" />
<use x="684" y="636" xlink:href="#p" />
<use x="696" y="636" xlink:href="#p" />
<use x="708" y="636" xlink:href="#p" />
<use x="720" y="636" xlink:href="#p" />
<use x="732" y="636" xlink:href="#p" />
<use x="756" y="636" xlink:href="#p" />
<use x="768" y="636" xlink:href="#p" />
<use x="36" y="648" xlink:href="#p" />
<use x="96" y="648" xlink:href="#p" />
<use x="120" y="648" xlink:href="#p" />
<use x="204" y="648" xlink:href="#p" />
<use x="228" y="648" xlink:href="#p" />
<use x="252" y="648" xlink:href="#p" />
<use x="276" y="648" xlink:href="#p" />
<use x="288" y="648" xlink:href="#p" />
<use x="324" y="648" xlink:href="#p" />
<use x="336" y="648" xlink:href="#p" />
<use x="348" y="648" xlink:href="#p" />
<use x="360" y="648" xlink:href="#p" />
<use x="384" y="648" xlink:href="#p" />
<use x="408" y="648" xlink:href="#p" />
<use x="468" y="648" xlink:href="#p" />
<use x="492" y="648" xlink:href="#p" />
<use x="516" y="648" xlink:href="#p" />
<use x="552" y="648" xlink:href="#p" />
<use x="588" y="648" xlink:href="#p" />
<use x="624" y="648" xlink:href="#p" />
<use x="660" y="648" xlink:href="#p" />
<use x="672" y="648" xlink:href="#p" />
<use x="696" y="648" xlink:href="#p" />
<use x="708" y="648" xlink:href="#p" />
<use x="720" y="648" xlink:href="#p" />
<use x="732" y="648" xlink:href="#p" />
<use x="756" y="648" xlink:href="#p" />
<use x="768" y="648" xlink:href="#p" />
<use x="780" y="648" xlink:href="#p" />
<use x="36" y="660" xlink:href="#p" />
<use x="48" y="660" xlink:href="#p" />
<use x="72" y="660" xlink:href="#p" />
<use x="84" y="660" xlink:href="#p" />
<use x="96" y="660" xlink:href="#p" />
<use x="108" y="660" xlink:href="#p" />
<use x="144" y="660" xlink:href="#p" />
<use x="168" y="660" xlink:href="#p" />
<use x="180" y="660" xlink:href="#p" />
<use x="192" y="660" xlink:href="#p" />
<use x="204" y="660" xlink:href="#p" />
<use x="228" y="660" xlink:href="#p" />
<use x="240" y="660" xlink:href="#p" />
<use x="252" y="660" xlink:href="#p" />
<use x="264" y="660" xlink:href="#p" />
<use x="300" y="660" xlink:href="#p" />
<use x="312" y="660" xlink:href="#p" />
<use x="324" y="660" xlink:href="#p" />
<use x="360" y="660" xlink:href="#p" />
<use x="372" y="660" xlink:href="#p" />
<use x="408" y="660" xlink:href="#p" />
<use x="420" y="660" xlink:href="#p" />
<use x="444" y="660" xlink:href="#p" />
<use x="480" y="660" xlink:href="#p" />
<use x="516" y="660" xlink:href="#p" />
<use x="588" y="660" xlink:href="#p" />
<use x="600" y="660" xlink:href="#p" />
<use x="612" y="660" xlink:href="#p" />
<use x="648" y="660" xlink:href="#p" />
<use x="660" y="660" xlink:href="#p" />
<use x="672" y="660" xlink:href="#p" />
<use x="684" y="660" xlink:href="#p" />
<use x="708" y="660" xlink:href="#p" />
<use x="720" y="660" xlink:href="#p" />
<use x="744" y="660" xlink:href="#p" />
<use x="780" y="660" xlink:href="#p" />
<use x="12" y="672" xlink:href="#p" />
<use x="48" y="672" xlink:href="#p" />
<use x="108" y="672" xlink:href="#p" />
<use x="120" y="672" xlink:href="#p" />
<use x="132" y="672" xlink:href="#p" />
<use x="144" y="672" xlink:href="#p" />
<use x="156" y="672" xlink:href="#p" />
<use x="204" y="672" xlink:href="#p" />
<use x="216" y="672" xlink:href="#p" />
<use x="228" y="672" xlink:href="#p" />
<use x="240" y="672" xlink:href="#p" />
<use x="288" y="672" xlink:href="#p" />
<use x="336" y="672" xlink:href="#p" />
<use x="348" y="672" xlink:href="#p" />
<use x="360" y="672" xlink:href="#p" />
<use x="372" y="672" xlink:href="#p" />
<use x="408" y="672" xlink:href="#p" />
<use x="444" y="672" xlink:href="#p" />
<use x="456" y="672" xlink:href="#p" />
<use x="480" y="672" xlink:href="#p" />
<use x="504" y="672" xlink:href="#p" />
<use x="516" y="672" xlink:href="#p" />
<use x="528" y="672" xlink:href="#p" />
<use x="552" y="672" xlink:href="#p" />
<use x="612" y="672" xlink:href="#p" />
<use x="636" y="672" xlink:href="#p" />
<use x="660" y="672" xlink:href="#p" />
<use x="672" y="672" xlink:href="#p" />
<use x="684" y="672" xlink:href="#p" />
<use x="708" y="672" xlink:href="#p" />
<use x="732" y="672" xlink:href="#p" />
<use x="768" y="672" xlink:href="#p" />
<use x="780" y="672" xlink:href="#p" />
<use x="24" y="684" xlink:href="#p" />
<use x="36" y="684" xlink:href="#p" />
<use x="60" y="684" xlink:href="#p" />
<use x="84" y="684" xlink:href="#p" />
<use x="132" y="684" xlink:href="#p" />
<use x="156" y="684" xlink:href="#p" />
<use x="180" y="684" xlink:href="#p" />
<use x="192" y="684" xlink:href="#p" />
<use x="204" y="684" xlink:href="#p" />
<use x="228" y="684" xlink:href="#p" />
<use x="252" y="684" xlink:href="#p" />
<use x="276" y="684" xlink:href="#p" />
<use x="288" y="684" xlink:href="#p" />
<use x="300" y="684" xlink:href="#p" />
<use x="348" y="684" xlink:href="#p" />
<use x="360" y="684" xlink:href="#p" />
<use x="372" y="684" xlink:href="#p" />
<use x="384" y="684" xlink:href="#p" />
<use x="396" y="684" xlink:href="#p" />
<use x="408" y="684" xlink:href="#p" />
<use x="420" y="684" xlink:href="#p" />
<use x="432" y="684" xlink:href="#p" />
<use x="456" y="684" xlink:href="#p" />
<use x="504" y="684" xlink:href="#p" />
<use x="528" y="684" xlink:href="#p" />
<use x="576" y="684" xlink:href="#p" />
<use x="588" y="684" xlink:href="#p" />
<use x="648" y="684" xlink:href="#p" />
<use x="684" y="684" xlink:href="#p" />
<use x="696" y="684" xlink:href="#p" />
<use x="708" y="684" xlink:href="#p" />
<use x="720" y="684" xlink:href="#p" />
<use x="732" y="684" xlink:href="#p" />
<use x="756" y="684" xlink:href="#p" />
<use x="780" y="684" xlink:href="#p" />
<use x="108" y="696" xlink:href="#p" />
<use x="144" y="696" xlink:href="#p" />
<use x="156" y="696" xlink:href="#p" />
<use x="168" y="696" xlink:href="#p" />
<use x="180" y="696" xlink:href="#p" />
<use x="192" y="696" xlink:href="#p" />
<use x="204" y="696" xlink:href="#p" />
<use x="216" y="696" xlink:href="#p" />
<use x="228" y="696" xlink:href="#p" />
<use x="252" y="696" xlink:href="#p" />
<use x="276" y="696" xlink:href="#p" />
<use x="312" y="696" xlink:href="#p" />
<use x="336" y="696" xlink:href="#p" />
<use x="348" y="696" xlink:href="#p" />
<use x="372" y="696" xlink:href="#p" />
<use x="420" y="696" xlink:href="#p" />
<use x="444" y="696" xlink:href="#p" />
<use x="456" y="696" xlink:href="#p" />
<use x="504" y="696" xlink:href="#p" />
<use x="516" y="696" xlink:href="#p" />
<use x="576" y="696" xlink:href="#p" />
<use x="612" y="696" xlink:href="#p" />
<use x="660" y="696" xlink:href="#p" />
<use x="684" y="696" xlink:href="#p" />
<use x="732" y="696" xlink:href="#p" />
<use x="744" y="696" xlink:href="#p" />
<use x="756" y="696" xlink:href="#p" />
<use x="768" y="696" xlink:href="#p" />
<use x="12" y="708" xlink:href="#p" />
<use x="24" y="708" xlink:href="#p" />
<use x="36" y="708" xlink:href="#p" />
<use x="48" y="708" xlink:href="#p" />
<use x="60" y="708" xlink:href="#p" />
<use x="72" y="708" xlink:href="#p" />
<use x="84" y="708" xlink:href="#p" />
<use x="156" y="708" xlink:href="#p" />
<use x="204" y="708" xlink:href="#p" />
<use x="216" y="708" xlink:href="#p" />
<use x="228" y="708" xlink:href="#p" />
<use x="240" y="708" xlink:href="#p" />
<use x="264" y="708" xlink:href="#p" />
<use x="288" y="708" xlink:href="#p" />
<use x="300" y="708" xlink:href="#p" />
<use x="324" y="708" xlink:href="#p" />
<use x="348" y="708" xlink:href="#p" />
<use x="360" y="708" xlink:href="#p" />
<use x="372" y="708" xlink:href="#p" />
<use x="396" y="708" xlink:href="#p" />
<use x="420" y="708" xlink:href="#p" />
<use x="456" y="708" xlink:href="#p" />
<use x="468" y="708" xlink:href="#p" />
<use x="492" y="708" xlink:href="#p" />
<use x="504" y="708" xlink:href="#p" />
<use x="552" y="708" xlink:href="#p" />
<use x="588" y="708" xlink:href="#p" />
<use x="624" y="708" xlink:href="#p" />
<use x="636" y="708" xlink:href="#p" />
<use x="648" y="708" xlink:href="#p" />
<use x="684" y="708" xlink:href="#p" />
<use x="708" y="708" xlink:href="#p" />
<use x="732" y="708" xlink:href="#p" />
<use x="744" y="708" xlink:href="#p" />
<use x="12" y="720" xlink:href="#p" />
<use x="84" y="720" xlink:href="#p" />
<use x="108" y="720" xlink:href="#p" />
<use x="120" y="720" xlink:href="#p" />
<use x="132" y="720" xlink:href="#p" />
<use x="168" y="720" xlink:href="#p" />
<use x="180" y="720" xlink:href="#p" />
<use x="192" y="720" xlink:href="#p" />
<use x="204" y="720" xlink:href="#p" />
<use x="228" y="720" xlink:href="#p" />
<use x="252" y="720" xlink:href="#p" />
<use x="312" y="720" xlink:href="#p" />
<use x="372" y="720" xlink:href="#p" />
<use x="420" y="720" xlink:href="#p" />
<use x="432" y="720" xlink:href="#p" />
<use x="444" y="720" xlink:href="#p" />
<use x="480" y="720" xlink:href="#p" />
<use x="492" y="720" xlink:href="#p" />
<use x="504" y="720" xlink:href="#p" />
<use x="516" y="720" xlink:href="#p" />
<use x="540" y="720" xlink:href="#p" />
<use x="552" y="720" xlink:href="#p" />
<use x="564" y="720" xlink:href="#p" />
<use x="576" y="720" xlink:href="#p" />
<use x="600" y="720" xlink:href="#p" />
<use x="612" y="720" xlink:href="#p" />
<use x="624" y="720" xlink:href="#p" />
<use x="660" y="720" xlink:href="#p" />
<use x="672" y="720" xlink:href="#p" />
<use x="684" y="720" xlink:href="#p" />
<use x="732" y="720" xlink:href="#p" />
<use x="768" y="720" xlink:href="#p" />
<use x="12" y="732" xlink:href="#p" />
<use x="36" y="732" xlink:href="#p" />
<use x="48" y="732" xlink:href="#p" />
<use x="60" y="732" xlink:href="#p" />
<use x="84" y="732" xlink:href="#p" />
<use x="144" y="732" xlink:href="#p" />
<use x="156" y="732" xlink:href="#p" />
<use x="192" y="732" xlink:href="#p" />
<use x="204" y="732" xlink:href="#p" />
<use x="216" y="732" xlink:href="#p" />
<use x="228" y="732" xlink:href="#p" />
<use x="240" y="732" xlink:href="#p" />
<use x="300" y="732" xlink:href="#p" />
<use x="312" y="732" xlink:href="#p" />
<use x="324" y="732" xlink:href="#p" />
<use x="336" y="732" xlink:href="#p" />
<use x="360" y="732" xlink:href="#p" />
<use x="372" y="732" xlink:href="#p" />
<use x="384" y="732" xlink:href="#p" />
<use x="396" y="732" xlink:href="#p" />
<use x="408" y="732" xlink:href="#p" />
<use x="420" y="732" xlink:href="#p" />
<use x="444" y="732" xlink:href="#p" />
<use x="456" y="732" xlink:href="#p" />
<use x="492" y="732" xlink:href="#p" />
<use x="504" y="732" xlink:href="#p" />
<use x="516" y="732" xlink:href="#p" />
<use x="528" y="732" xlink:href="#p" />
<use x="540" y="732" xlink:href="#p" />
<use x="552" y="732" xlink:href="#p" />
<use x="588" y="732" xlink:href="#p" />
<use x="636" y="732" xlink:href="#p" />
<use x="672" y="732" xlink:href="#p" />
<use x="684" y="732" xlink:href="#p" />
<use x="696" y="732" xlink:href="#p" />
<use x="708" y="732" xlink:href="#p" />
<use x="720" y="732" xlink:href="#p" />
<use x="732" y="732" xlink:href="#p" />
<use x="768" y="732" xlink:href="#p" />
<use x="780" y="732" xlink:href="#p" />
<use x="12" y="744" xlink:href="#p" />
<use x="36" y="744" xlink:href="#p" />
<use x="48" y="744" xlink:href="#p" />
<use x="60" y="744" xlink:href="#p" />
<use x="84" y="744" xlink:href="#p" />
<use x="120" y="744" xlink:href="#p" />
<use x="156" y="744" xlink:href="#p" />
<use x="168" y="744" xlink:href="#p" />
<use x="180" y="744" xlink:href="#p" />
<use x="216" y="744" xlink:href="#p" />
<use x="228" y="744" xlink:href="#p" />
<use x="276" y="744" xlink:href="#p" />
<use x="324" y="744" xlink:href="#p" />
<use x="336" y="744" xlink:href="#p" />
<use x="396" y="744" xlink:href="#p" />
<use x="408" y="744" xlink:href="#p" />
<use x="432" y="744" xlink:href="#p" />
<use x="444" y="744" xlink:href="#p" />
<use x="468" y="744" xlink:href="#p" />
<use x="480" y="744" xlink:href="#p" />
<use x="516" y="744" xlink:href="#p" />
<use x="540" y="744" xlink:href="#p" />
<use x="552" y="744" xlink:href="#p" />
<use x="564" y="744" xlink:href="#p" />
<use x="576" y="744" xlink:href="#p" />
<use x="588" y="744" xlink:href="#p" />
<use x="600" y="744" xlink:href="#p" />
<use x="624" y="744" xlink:href="#p" />
<use x="636" y="744" xlink:href="#p" />
<use x="648" y="744" xlink:href="#p" />
<use x="660" y="744" xlink:href="#p" />
<use x="684" y="744" xlink:href="#p" />
<use x="696" y="744" xlink:href="#p" />
<use x="720" y="744" xlink:href="#p" />
<use x="744" y="744" xlink:href="#p" />
<use x="12" y="756" xlink:href="#p" />
<use x="36" y="756" xlink:href="#p" />
<use x="48" y="756" xlink:href="#p" />
<use x="60" y="756" xlink:href="#p" />
<use x="84" y="756" xlink:href="#p" />
<use x="120" y="756" xlink:href="#p" />
<use x="180" y="756" xlink:href="#p" />
<use x="204" y="756" xlink:href="#p" />
<use x="216" y="756" xlink:href="#p" />
<use x="228" y="756" xlink:href="#p" />
<use x="240" y="756" xlink:href="#p" />
<use x="264" y="756" xlink:href="#p" />
<use x="288" y="756" xlink:href="#p" />
<use x="312" y="756" xlink:href="#p" />
<use x="324" y="756" xlink:href="#p" />
<use x="336" y="756" xlink:href="#p" />
<use x="348" y="756" xlink:href="#p" />
<use x="408" y="756" xlink:href="#p" />
<use x="432" y="756" xlink:href="#p" />
<use x="444" y="756" xlink:href="#p" />
<use x="468" y="756" xlink:href="#p" />
<use x="528" y="756" xlink:href="#p" />
<use x="540" y="756" xlink:href="#p" />
<use x="552" y="756" xlink:href="#p" />
<use x="576" y="756" xlink:href="#p" />
<use x="600" y="756" xlink:href="#p" />
<use x="612" y="756" xlink:href="#p" />
<use x="696" y="756" xlink:href="#p" />
<use x="708" y="756" xlink:href="#p" />
<use x="720" y="756" xlink:href="#p" />
<use x="732" y="756" xlink:href="#p" />
<use x="768" y="756" xlink:href="#p" />
<use x="12" y="768" xlink:href="#p" />
<use x="84" y="768" xlink:href="#p" />
<use x="132" y="768" xlink:href="#p" />
<use x="144" y="768" xlink:href="#p" />
<use x="168" y="768" xlink:href="#p" />
<use x="180" y="768" xlink:href="#p" />
<use x="192" y="768" xlink:href="#p" />
<use x="216" y="768" xlink:href="#p" />
<use x="228" y="768" xlink:href="#p" />
<use x="252" y="768" xlink:href="#p" />
<use x="276" y="768" xlink:href="#p" />
<use x="288" y="768" xlink:href="#p" />
<use x="336" y="768" xlink:href="#p" />
<use x="384" y="768" xlink:href="#p" />
<use x="408" y="768" xlink:href="#p" />
<use x="432" y="768" xlink:href="#p" />
<use x="444" y="768" xlink:href="#p" />
<use x="456" y="768" xlink:href="#p" />
<use x="468" y="768" xlink:href="#p" />
<use x="480" y="768" xlink:href="#p" />
<use x="492" y="768" xlink:href="#p" />
<use x="504" y="768" xlink:href="#p" />
<use x="528" y="768" xlink:href="#p" />
<use x="552" y="768" xlink:href="#p" />
<use x="600" y="768" xlink:href="#p" />
<use x="624" y="768" xlink:href="#p" />
<use x="684" y="768" xlink:href="#p" />
<use x="696" y="768" xlink:href="#p" />
<use x="720" y="768" xlink:href="#p" />
<use x="744" y="768" xlink:href="#p" />
<use x="756" y="768" xlink:href="#p" />
<use x="780" y="768" xlink:href="#p" />
<use x="12" y="780" xlink:href="#p" />
<use x="24" y="780" xlink:href="#p" />
<use x="36" y="780" xlink:href="#p" />
<use x="48" y="780" xlink:href="#p" />
<use x="60" y="780" xlink:href="#p" />
<use x="72" y="780" xlink:href="#p" />
<use x="84" y="780" xlink:href="#p" />
<use x="120" y="780" xlink:href="#p" />
<use x="132" y="780" xlink:href="#p" />
<use x="144" y="780" xlink:href="#p" />
<use x="156" y="780" xlink:href="#p" />
<use x="168" y="780" xlink:href="#p" />
<use x="180" y="780" xlink:href="#p" />
<use x="228" y="780" xlink:href="#p" />
<use x="252" y="780" xlink:href="#p" />
<use x="276" y="780" xlink:href="#p" />
<use x="288" y="780" xlink:href="#p" />
<use x="312" y="780" xlink:href="#p" />
<use x="360" y="780" xlink:href="#p" />
<use x="384" y="780" xlink:href="#p" />
<use x="408" y="780" xlink:href="#p" />
<use x="420" y="780" xlink:href="#p" />
<use x="432" y="780" xlink:href="#p" />
<use x="456" y="780" xlink:href="#p" />
<use x="504" y="780" xlink:href="#p" />
<use x="528" y="780" xlink:href="#p" />
<use x="552" y="780" xlink:href="#p" />
<use x="564" y="780" xlink:href="#p" />
<use x="576" y="780" xlink:href="#p" />
<use x="588" y="780" xlink:href="#p" />
<use x="600" y="780" xlink:href="#p" />
<use x="624" y="780" xlink:href="#p" />
<use x="648" y="780" xlink:href="#p" />
<use x="672" y="780" xlink:href="#p" />
<use x="720" y="780" xlink:href="#p" />
<use x="732" y="780" xlink:href="#p" />
<use x="756" y="780" xlink:href="#p" />
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" xmlns:xlink="http://www.w3.org/1999/xlink" width="468" height="468" viewBox="0 0 468 468">
<desc></desc>
<rect width="468" height="468" fill="#ffffff" cx="0" cy="0" />
<defs>
<rect id="p" width="12" height="12" />
</defs>
<g fill="#000000">
<use x="12" y="12" xlink:href="#p" />
<use x="24" y="12" xlink:href="#p" />
<use x="36" y="12" xlink:href="#p" />
<use x="48" y="12" xlink:href="#p" />
<use x="60" y="12" xlink:href="#p" />
<use x="72" y="12" xlink:href="#p" />
<use x="84" y="12" xlink:href="#p" />
<use x="108" y="12" xlink:href="#p" />
<use x="144" y="12" xlink:href="#p" />
<use x="156" y="12" xlink:href="#p" />
<use x="180" y="12" xlink:href="#p" />
<use x="204" y="12" xlink:href="#p" />
<use x="240" y="12" xlink:href="#p" />
<use x="264" y="12" xlink:href="#p" />
<use x="276" y="12" xlink:href="#p" />
<use x="288" y="12" xlink:href="#p" />
<use x="300" y="12" xlink:href="#p" />
<use x="348" y="12" xlink:href="#p" />
<use x="372" y="12" xlink:href="#p" />
<use x="384" y="12" xlink:href="#p" />
<use x="396" y="12" xlink:href="#p" />
<use x="408" y="12" xlink:href="#p" />
<use x="420" y="12" xlink:href="#p" />
<use x="432" y="12" xlink:href="#p" />
<use x="444" y="12" xlink:href="#p" />
<use x="12" y="24" xlink:href="#p" />
<use x="84" y="24" xlink:href="#p" />
<use x="108" y="24" xlink:href="#p" />
<use x="132" y="24" xlink:href="#p" />
<use x="144" y="24" xlink:href="#p" />
<use x="168" y="24" xlink:href="#p" />
<use x="192" y="24" xlink:href="#p" />
<use x="216" y="24" xlink:href="#p" />
<use x="228" y="24" xlink:href="#p" />
<use x="240" y="24" xlink:href="#p" />
<use x="264" y="24" xlink:href="#p" />
<use x="276" y="24" xlink:href="#p" />
<use x="336" y="24" xlink:href="#p" />
<use x="348" y="24" xlink:href="#p" />
<use x="372" y="24" xlink:href="#p" />
<use x="444" y="24" xlink:href="#p" />
<use x="12" y="36" xlink:href="#p" />
<use x="36" y="36" xlink:href="#p" />
<use x="48" y="36" xlink:href="#p" />
<use x="60" y="36" xlink:href="#p" />
<use x="84" y="36" xlink:href="#p" />
<use x="108" y="36" xlink:href="#p" />
<use x="120" y="36" xlink:href="#p" />
<use x="180" y="36" xlink:href="#p" />
<use x="192" y="36" xlink:href="#p" />
<use x="204" y="36" xlink:href="#p" />
<use x="216" y="36" xlink:href="#p" />
<use x="240" y="36" xlink:href="#p" />
<use x="252" y="36" xlink:href="#p" />
<use x="264" y="36" xlink:href="#p" />
<use x="276" y="36" xlink:href="#p" />
<use x="324" y="36" xlink:href="#p" />
<use x="372" y="36" xlink:href="#p" />
<use x="396" y="36" xlink:href="#p" />
<use x="408" y="36" xlink:href="#p" />
<use x="420" y="36" xlink:href="#p" />
<use x="444" y="36" xlink:href="#p" />
<use x="12" y="48" xlink:href="#p" />
<use x="36" y="48" xlink:href="#p" />
<use x="48" y="48" xlink:href="#p" />
<use x="60" y="48" xlink:href="#p" />
<use x="84" y="48" xlink:href="#p" />
<use x="120" y="48" xlink:href="#p" />
<use x="144" y="48" xlink:href="#p" />
<use x="168" y="48" xlink:href="#p" />
<use x="192" y="48" xlink:href="#p" />
<use x="204" y="48" xlink:href="#p" />
<use x="216" y="48" xlink:href="#p" />
<use x="288" y="48" xlink:href="#p" />
<use x="300" y="48" xlink:href="#p" />
<use x="312" y="48" xlink:href="#p" />
<use x="324" y="48" xlink:href="#p" />
<use x="336" y="48" xlink:href="#p" />
<use x="372" y="48" xlink:href="#p" />
<use x="396" y="48" xlink:href="#p" />
<use x="408" y="48" xlink:href="#p" />
<use x="420" y="48" xlink:href="#p" />
<use x="444" y="48" xlink:href="#p" />
<use x="12" y="60" xlink:href="#p" />
<use x="36" y="60" xlink:href="#p" />
<use x="48" y="60" xlink:href="#p" />
<use x="60" y="60" xlink:href="#p" />
<use x="84" y="60" xlink:href="#p" />
<use x="132" y="60" xlink:href="#p" />
<use x="144" y="60" xlink:href="#p" />
<use x="156" y="60" xlink:href="#p" />
<use x="168" y="60" xlink:href="#p" />
<use x="180" y="60" xlink:href="#p" />
<use x="192" y="60" xlink:href="#p" />
<use x="204" y="60" xlink:href="#p" />
<use x="240" y="60" xlink:href="#p" />
<use x="276" y="60" xlink:href="#p" />
<use x="300" y="60" xlink:href="#p" />
<use x="324" y="60" xlink:href="#p" />
<use x="372" y="60" xlink:href="#p" />
<use x="396" y="60" xlink:href="#p" />
<use x="408" y="60" xlink:href="#p" />
<use x="420" y="60" xlink:href="#p" />
<use x="444" y="60" xlink:href="#p" />
<use x="12" y="72" xlink:href="#p" />
<use x="84" y="72" xlink:href="#p" />
<use x="108" y="72" xlink:href="#p" />
<use x="168" y="72" xlink:href="#p" />
<use x="180" y="72" xlink:href="#p" />
<use x="192" y="72" xlink:href="#p" />
<use x="228" y="72" xlink:href="#p" />
<use x="264" y="72" xlink:href="#p" />
<use x="288" y="72" xlink:href="#p" />
<use x="300" y="72" xlink:href="#p" />
<use x="324" y="72" xlink:href="#p" />
<use x="336" y="72" xlink:href="#p" />
<use x="348" y="72" xlink:href="#p" />
<use x="372" y="72" xlink:href="#p" />
<use x="444" y="72" xlink:href="#p" />
<use x="12" y="84" xlink:href="#p" />
<use x="24" y="84" xlink:href="#p" />
<use x="36" y="84" xlink:href="#p" />
<use x="48" y="84" xlink:href="#p" />
<use x="60" y="84" xlink:href="#p" />
<use x="72" y="84" xlink:href="#p" />
<use x="84" y="84" xlink:href="#p" />
<use x="108" y="84" xlink:href="#p" />
<use x="132" y="84" xlink:href="#p" />
<use x="156" y="84" xlink:href="#p" />
<use x="180" y="84" xlink:href="#p" />
<use x="204" y="84" xlink:href="#p" />
<use x="228" y="84" xlink:href="#p" />
<use x="252" y="84" xlink:href="#p" />
<use x="276" y="84" xlink:href="#p" />
<use x="300" y="84" xlink:href="#p" />
<use x="324" y="84" xlink:href="#p" />
<use x="348" y="84" xlink:href="#p" />
<use x="372" y="84" xlink:href="#p" />
<use x="384" y="84" xlink:href="#p" />
<use x="396" y="84" xlink:href="#p" />
<use x="408" y="84" xlink:href="#p" />
<use x="420" y="84" xlink:href="#p" />
<use x="432" y="84" xlink:href="#p" />
<use x="444" y="84" xlink:href="#p" />
<use x="108" y="96" xlink:href="#p" />
<use x="180" y="96" xlink:href="#p" />
<use x="192" y="96" xlink:href="#p" />
<use x="216" y="96" xlink:href="#p" />
<use x="240" y="96" xlink:href="#p" />
<use x="276" y="96" xlink:href="#p" />
<use x="300" y="96" xlink:href="#p" />
<use x="312" y="96" xlink:href="#p" />
<use x="348" y="96" xlink:href="#p" />
<use x="36" y="108" xlink:href="#p" />
<use x="48" y="108" xlink:href="#p" />
<use x="60" y="108" xlink:href="#p" />
<use x="84" y="108" xlink:href="#p" />
<use x="108" y="108" xlink:href="#p" />
<use x="120" y="108" xlink:href="#p" />
<use x="144" y="108" xlink:href="#p" />
<use x="180" y="108" xlink:href="#p" />
<use x="192" y="108" xlink:href="#p" />
<use x="204" y="108" xlink:href="#p" />
<use x="228" y="108" xlink:href="#p" />
<use x="276" y="108" xlink:href="#p" />
<use x="312" y="108" xlink:href="#p" />
<use x="324" y="108" xlink:href="#p" />
<use x="348" y="108" xlink:href="#p" />
<use x="360" y="108" xlink:href="#p" />
<use x="372" y="108" xlink:href="#p" />
<use x="384" y="108" xlink:href="#p" />
<use x="420" y="108" xlink:href="#p" />
<use x="432" y="108" xlink:href="#p" />
<use x="444" y="108" xlink:href="#p" />
<use x="24" y="120" xlink:href="#p" />
<use x="36" y="120" xlink:href="#p" />
<use x="72" y="120" xlink:href="#p" />
<use x="168" y="120" xlink:href="#p" />
<use x="204" y="120" xlink:href="#p" />
<use x="252" y="120" xlink:href="#p" />
<use x="276" y="120" xlink:href="#p" />
<use x="288" y="120" xlink:href="#p" />
<use x="300" y="120" xlink:href="#p" />
<use x="312" y="120" xlink:href="#p" />
<use x="336" y="120" xlink:href="#p" />
<use x="348" y="120" xlink:href="#p" />
<use x="444" y="120" xlink:href="#p" />
<use x="36" y="132" xlink:href="#p" />
<use x="84" y="132" xlink:href="#p" />
<use x="108" y="132" xlink:href="#p" />
<use x="120" y="132" xlink:href="#p" />
<use x="132" y="132" xlink:href="#p" />
<use x="144" y="132" xlink:href="#p" />
<use x="180" y="132" xlink:href="#p" />
<use x="192" y="132" xlink:href="#p" />
<use x="204" y="132" xlink:href="#p" />
<use x="216" y="132" xlink:href="#p" />
<use x="228" y="132" xlink:href="#p" />
<use x="252" y="132" xlink:href="#p" />
<use x="312" y="132" xlink:href="#p" />
<use x="324" y="132" xlink:href="#p" />
<use x="336" y="132" xlink:href="#p" />
<use x="372" y="132" xlink:href="#p" />
<use x="384" y="132" xlink:href="#p" />
<use x="396" y="132" xlink:href="#p" />
<use x="420" y="132" xlink:href="#p" />
<use x="432" y="132" xlink:href="#p" />
<use x="444" y="132" xlink:href="#p" />
<use x="48" y="144" xlink:href="#p" />
<use x="120" y="144" xlink:href="#p" />
<use x="156" y="144" xlink:href="#p" />
<use x="180" y="144" xlink:href="#p" />
<use x="216" y="144" xlink:href="#p" />
<use x="228" y="144" xlink:href="#p" />
<use x="240" y="144" xlink:href="#p" />
<use x="264" y="144" xlink:href="#p" />
<use x="276" y="144" xlink:href="#p" />
<use x="288" y="144" xlink:href="#p" />
<use x="324" y="144" xlink:href="#p" />
<use x="336" y="144" xlink:href="#p" />
<use x="372" y="144" xlink:href="#p" />
<use x="384" y="144" xlink:href="#p" />
<use x="396" y="144" xlink:href="#p" />
<use x="432" y="144" xlink:href="#p" />
<use x="444" y="144" xlink:href="#p" />
<use x="24" y="156" xlink:href="#p" />
<use x="36" y="156" xlink:href="#p" />
<use x="60" y="156" xlink:href="#p" />
<use x="84" y="156" xlink:href="#p" />
<use x="168" y="156" xlink:href="#p" />
<use x="192" y="156" xlink:href="#p" />
<use x="204" y="156" xlink:href="#p" />
<use x="240" y="156" xlink:href="#p" />
<use x="264" y="156" xlink:href="#p" />
<use x="300" y="156" xlink:href="#p" />
<use x="312" y="156" xlink:href="#p" />
<use x="324" y="156" xlink:href="#p" />
<use x="360" y="156" xlink:href="#p" />
<use x="372" y="156" xlink:href="#p" />
<use x="384" y="156" xlink:href="#p" />
<use x="396" y="156" xlink:href="#p" />
<use x="408" y="156" xlink:href="#p" />
<use x="420" y="156" xlink:href="#p" />
<use x="432" y="156" xlink:href="#p" />
<use x="444" y="156" xlink:href="#p" />
<use x="24" y="168" xlink:href="#p" />
<use x="36" y="168" xlink:href="#p" />
<use x="48" y="168" xlink:href="#p" />
<use x="60" y="168" xlink:href="#p" />
<use x="96" y="168" xlink:href="#p" />
<use x="120" y="168" xlink:href="#p" />
<use x="192" y="168" xlink:href="#p" />
<use x="216" y="168" xlink:href="#p" />
<use x="228" y="168" xlink:href="#p" />
<use x="240" y="168" xlink:href="#p" />
<use x="252" y="168" xlink:href="#p" />
<use x="312" y="168" xlink:href="#p" />
<use x="324" y="168" xlink:href="#p" />
<use x="336" y="168" xlink:href="#p" />
<use x="348" y="168" xlink:href="#p" />
<use x="360" y="168" xlink:href="#p" />
<use x="384" y="168" xlink:href="#p" />
<use x="408" y="168" xlink:href="#p" />
<use x="420" y="168" xlink:href="#p" />
<use x="12" y="180" xlink:href="#p" />
<use x="36" y="180" xlink:href="#p" />
<use x="84" y="180" xlink:href="#p" />
<use x="96" y="180" xlink:href="#p" />
<use x="108" y="180" xlink:href="#p" />
<use x="120" y="180" xlink:href="#p" />
<use x="132" y="180" xlink:href="#p" />
<use x="144" y="180" xlink:href="#p" />
<use x="168" y="180" xlink:href="#p" />
<use x="180" y="180" xlink:href="#p" />
<use x="192" y="180" xlink:href="#p" />
<use x="204" y="180" xlink:href="#p" />
<use x="228" y="180" xlink:href="#p" />
<use x="240" y="180" xlink:href="#p" />
<use x="252" y="180" xlink:href="#p" />
<use x="264" y="180" xlink:href="#p" />
<use x="276" y="180" xlink:href="#p" />
<use x="288" y="180" xlink:href="#p" />
<use x="300" y="180" xlink:href="#p" />
<use x="312" y="180" xlink:href="#p" />
<use x="324" y="180" xlink:href="#p" />
<use x="336" y="180" xlink:href="#p" />
<use x="348" y="180" xlink:href="#p" />
<use x="372" y="180" xlink:href="#p" />
<use x="408" y="180" xlink:href="#p" />
<use x="432" y="180" xlink:href="#p" />
<use x="444" y="180" xlink:href="#p" />
<use x="12" y="192" xlink:href="#p" />
<use x="24" y="192" xlink:href="#p" />
<use x="60" y="192" xlink:href="#p" />
<use x="96" y="192" xlink:href="#p" />
<use x="108" y="192" xlink:href="#p" />
<use x="120" y="192" xlink:href="#p" />
<use x="156" y="192" xlink:href="#p" />
<use x="180" y="192" xlink:href="#p" />
<use x="192" y="192" xlink:href="#p" />
<use x="204" y="192" xlink:href="#p" />
<use x="216" y="192" xlink:href="#p" />
<use x="228" y="192" xlink:href="#p" />
<use x="288" y="192" xlink:href="#p" />
<use x="300" y="192" xlink:href="#p" />
<use x="324" y="192" xlink:href="#p" />
<use x="360" y="192" xlink:href="#p" />
<use x="372" y="192" xlink:href="#p" />
<use x="384" y="192" xlink:href="#p" />
<use x="396" y="192" xlink:href="#p" />
<use x="432" y="192" xlink:href="#p" />
<use x="72" y="204" xlink:href="#p" />
<use x="84" y="204" xlink:href="#p" />
<use x="132" y="204" xlink:href="#p" />
<use x="144" y="204" xlink:href="#p" />
<use x="156" y="204" xlink:href="#p" />
<use x="180" y="204" xlink:href="#p" />
<use x="216" y="204" xlink:href="#p" />
<use x="240" y="204" xlink:href="#p" />
<use x="264" y="204" xlink:href="#p" />
<use x="276" y="204" xlink:href="#p" />
<use x="300" y="204" xlink:href="#p" />
<use x="312" y="204" xlink:href="#p" />
<use x="324" y="204" xlink:href="#p" />
<use x="360" y="204" xlink:href="#p" />
<use x="372" y="204" xlink:href="#p" />
<use x="396" y="204" xlink:href="#p" />
<use x="420" y="204" xlink:href="#p" />
<use x="432" y="204" xlink:href="#p" />
<use x="444" y="204" xlink:href="#p" />
<use x="24" y="216" xlink:href="#p" />
<use x="36" y="216" xlink:href="#p" />
<use x="48" y="216" xlink:href="#p" />
<use x="72" y="216" xlink:href="#p" />
<use x="120" y="216" xlink:href="#p" />
<use x="168" y="216" xlink:href="#p" />
<use x="180" y="216" xlink:href="#p" />
<use x="192" y="216" xlink:href="#p" />
<use x="276" y="216" xlink:href="#p" />
<use x="288" y="216" xlink:href="#p" />
<use x="348" y="216" xlink:href="#p" />
<use x="360" y="216" xlink:href="#p" />
<use x="384" y="216" xlink:href="#p" />
<use x="12" y="228" xlink:href="#p" />
<use x="24" y="228" xlink:href="#p" />
<use x="36" y="228" xlink:href="#p" />
<use x="60" y="228" xlink:href="#p" />
<use x="84" y="228" xlink:href="#p" />
<use x="96" y="228" xlink:href="#p" />
<use x="132" y="228" xlink:href="#p" />
<use x="156" y="228" xlink:href="#p" />
<use x="168" y="228" xlink:href="#p" />
<use x="180" y="228" xlink:href="#p" />
<use x="204" y="228" xlink:href="#p" />
<use x="228" y="228" xlink:href="#p" />
<use x="252" y="228" xlink:href="#p" />
<use x="264" y="228" xlink:href="#p" />
<use x="276" y="228" xlink:href="#p" />
<use x="288" y="228" xlink:href="#p" />
<use x="312" y="228" xlink:href="#p" />
<use x="336" y="228" xlink:href="#p" />
<use x="432" y="228" xlink:href="#p" />
<use x="444" y="228" xlink:href="#p" />
<use x="24" y="240" xlink:href="#p" />
<use x="48" y="240" xlink:href="#p" />
<use x="60" y="240" xlink:href="#p" />
<use x="108" y="240" xlink:href="#p" />
<use x="120" y="240" xlink:href="#p" />
<use x="168" y="240" xlink:href="#p" />
<use x="180" y="240" xlink:href="#p" />
<use x="192" y="240" xlink:href="#p" />
<use x="264" y="240" xlink:href="#p" />
<use x="276" y="240" xlink:href="#p" />
<use x="300" y="240" xlink:href="#p" />
<use x="324" y="240" xlink:href="#p" />
<use x="348" y="240" xlink:href="#p" />
<use x="396" y="240" xlink:href="#p" />
<use x="432" y="240" xlink:href="#p" />
<use x="444" y="240" xlink:href="#p" />
<use x="12" y="252" xlink:href="#p" />
<use x="24" y="252" xlink:href="#p" />
<use x="72" y="252" xlink:href="#p" />
<use x="84" y="252" xlink:href="#p" />
<use x="108" y="252" xlink:href="#p" />
<use x="120" y="252" xlink:href="#p" />
<use x="132" y="252" xlink:href="#p" />
<use x="144" y="252" xlink:href="#p" />
<use x="156" y="252" xlink:href="#p" />
<use x="168" y="252" xlink:href="#p" />
<use x="216" y="252" xlink:href="#p" />
<use x="252" y="252" xlink:href="#p" />
<use x="264" y="252" xlink:href="#p" />
<use x="288" y="252" xlink:href="#p" />
<use x="300" y="252" xlink:href="#p" />
<use x="324" y="252" xlink:href="#p" />
<use x="360" y="252" xlink:href="#p" />
<use x="372" y="252" xlink:href="#p" />
<use x="384" y="252" xlink:href="#p" />
<use x="396" y="252" xlink:href="#p" />
<use x="408" y="252" xlink:href="#p" />
<use x="420" y="252" xlink:href="#p" />
<use x="432" y="252" xlink:href="#p" />
<use x="444" y="252" xlink:href="#p" />
<use x="12" y="264" xlink:href="#p" />
<use x="48" y="264" xlink:href="#p" />
<use x="60" y="264" xlink:href="#p" />
<use x="72" y="264" xlink:href="#p" />
<use x="96" y="264" xlink:href="#p" />
<use x="120" y="264" xlink:href="#p" />
<use x="180" y="264" xlink:href="#p" />
<use x="192" y="264" xlink:href="#p" />
<use x="204" y="264" xlink:href="#p" />
<use x="216" y="264" xlink:href="#p" />
<use x="228" y="264" xlink:href="#p" />
<use x="252" y="264" xlink:href="#p" />
<use x="276" y="264" xlink:href="#p" />
<use x="360" y="264" xlink:href="#p" />
<use x="384" y="264" xlink:href="#p" />
<use x="432" y="264" xlink:href="#p" />
<use x="12" y="276" xlink:href="#p" />
<use x="24" y="276" xlink:href="#p" />
<use x="60" y="276" xlink:href="#p" />
<use x="72" y="276" xlink:href="#p" />
<use x="84" y="276" xlink:href="#p" />
<use x="144" y="276" xlink:href="#p" />
<use x="156" y="276" xlink:href="#p" />
<use x="192" y="276" xlink:href="#p" />
<use x="216" y="276" xlink:href="#p" />
<use x="228" y="276" xlink:href="#p" />
<use x="240" y="276" xlink:href="#p" />
<use x="252" y="276" xlink:href="#p" />
<use x="288" y="276" xlink:href="#p" />
<use x="312" y="276" xlink:href="#p" />
<use x="324" y="276" xlink:href="#p" />
<use x="336" y="276" xlink:href="#p" />
<use x="372" y="276" xlink:href="#p" />
<use x="444" y="276" xlink:href="#p" />
<use x="48" y="288" xlink:href="#p" />
<use x="60" y="288" xlink:href="#p" />
<use x="96" y="288" xlink:href="#p" />
<use x="132" y="288" xlink:href="#p" />
<use x="144" y="288" xlink:href="#p" />
<use x="168" y="288" xlink:href="#p" />
<use x="192" y="288" xlink:href="#p" />
<use x="216" y="288" xlink:href="#p" />
<use x="372" y="288" xlink:href="#p" />
<use x="384" y="288" xlink:href="#p" />
<use x="432" y="288" xlink:href="#p" />
<use x="444" y="288" xlink:href="#p" />
<use x="12" y="300" xlink:href="#p" />
<use x="36" y="300" xlink:href="#p" />
<use x="48" y="300" xlink:href="#p" />
<use x="84" y="300" xlink:href="#p" />
<use x="96" y="300" xlink:href="#p" />
<use x="108" y="300" xlink:href="#p" />
<use x="132" y="300" xlink:href="#p" />
<use x="144" y="300" xlink:href="#p" />
<use x="216" y="300" xlink:href="#p" />
<use x="228" y="300" xlink:href="#p" />
<use x="240" y="300" xlink:href="#p" />
<use x="252" y="300" xlink:href="#p" />
<use x="264" y="300" xlink:href="#p" />
<use x="300" y="300" xlink:href="#p" />
<use x="312" y="300" xlink:href="#p" />
<use x="324" y="300" xlink:href="#p" />
<use x="348" y="300" xlink:href="#p" />
<use x="372" y="300" xlink:href="#p" />
<use x="396" y="300" xlink:href="#p" />
<use x="420" y="300" xlink:href="#p" />
<use x="444" y="300" xlink:href="#p" />
<use x="12" y="312" xlink:href="#p" />
<use x="24" y="312" xlink:href="#p" />
<use x="72" y="312" xlink:href="#p" />
<use x="108" y="312" xlink:href="#p" />
<use x="132" y="312" xlink:href="#p" />
<use x="144" y="312" xlink:href="#p" />
<use x="192" y="312" xlink:href="#p" />
<use x="204" y="312" xlink:href="#p" />
<use x="228" y="312" xlink:href="#p" />
<use x="240" y="312" xlink:href="#p" />
<use x="264" y="312" xlink:href="#p" />
<use x="300" y="312" xlink:href="#p" />
<use x="336" y="312" xlink:href="#p" />
<use x="348" y="312" xlink:href="#p" />
<use x="360" y="312" xlink:href="#p" />
<use x="384" y="312" xlink:href="#p" />
<use x="444" y="312" xlink:href="#p" />
<use x="12" y="324" xlink:href="#p" />
<use x="48" y="324" xlink:href="#p" />
<use x="84" y="324" xlink:href="#p" />
<use x="108" y="324" xlink:href="#p" />
<use x="120" y="324" xlink:href="#p" />
<use x="132" y="324" xlink:href="#p" />
<use x="156" y="324" xlink:href="#p" />
<use x="168" y="324" xlink:href="#p" />
<use x="216" y="324" xlink:href="#p" />
<use x="240" y="324" xlink:href="#p" />
<use x="264" y="324" xlink:href="#p" />
<use x="300" y="324" xlink:href="#p" />
<use x="324" y="324" xlink:href="#p" />
<use x="336" y="324" xlink:href="#p" />
<use x="348" y="324" xlink:href="#p" />
<use x="372" y="324" xlink:href="#p" />
<use x="384" y="324" xlink:href="#p" />
<use x="396" y="324" xlink:href="#p" />
<use x="432" y="324" xlink:href="#p" />
<use x="444" y="324" xlink:href="#p" />
<use x="12" y="336" xlink:href="#p" />
<use x="48" y="336" xlink:href="#p" />
<use x="60" y="336" xlink:href="#p" />
<use x="108" y="336" xlink:href="#p" />
<use x="168" y="336" xlink:href="#p" />
<use x="180" y="336" xlink:href="#p" />
<use x="204" y="336" xlink:href="#p" />
<use x="240" y="336" xlink:href="#p" />
<use x="252" y="336" xlink:href="#p" />
<use x="300" y="336" xlink:href="#p" />
<use x="324" y="336" xlink:href="#p" />
<use x="336" y="336" xlink:href="#p" />
<use x="348" y="336" xlink:href="#p" />
<use x="360" y="336" xlink:href="#p" />
<use x="384" y="336" xlink:href="#p" />
<use x="432" y="336" xlink:href="#p" />
<use x="12" y="348" xlink:href="#p" />
<use x="36" y="348" xlink:href="#p" />
<use x="48" y="348" xlink:href="#p" />
<use x="60" y="348" xlink:href="#p" />
<use x="72" y="348" xlink:href="#p" />
<use x="84" y="348" xlink:href="#p" />
<use x="96" y="348" xlink:href="#p" />
<use x="120" y="348" xlink:href="#p" />
<use x="132" y="348" xlink:href="#p" />
<use x="168" y="348" xlink:href="#p" />
<use x="180" y="348" xlink:href="#p" />
<use x="204" y="348" xlink:href="#p" />
<use x="216" y="348" xlink:href="#p" />
<use x="240" y="348" xlink:href="#p" />
<use x="252" y="348" xlink:href="#p" />
<use x="264" y="348" xlink:href="#p" />
<use x="276" y="348" xlink:href="#p" />
<use x="300" y="348" xlink:href="#p" />
<use x="312" y="348" xlink:href="#p" />
<use x="348" y="348" xlink:href="#p" />
<use x="360" y="348" xlink:href="#p" />
<use x="372" y="348" xlink:href="#p" />
<use x="384" y="348" xlink:href="#p" />
<use x="396" y="348" xlink:href="#p" />
<use x="420" y="348" xlink:href="#p" />
<use x="432" y="348" xlink:href="#p" />
<use x="108" y="360" xlink:href="#p" />
<use x="132" y="360" xlink:href="#p" />
<use x="144" y="360" xlink:href="#p" />
<use x="180" y="360" xlink:href="#p" />
<use x="192" y="360" xlink:href="#p" />
<use x="204" y="360" xlink:href="#p" />
<use x="240" y="360" xlink:href="#p" />
<use x="252" y="360" xlink:href="#p" />
<use x="276" y="360" xlink:href="#p" />
<use x="312" y="360" xlink:href="#p" />
<use x="336" y="360" xlink:href="#p" />
<use x="348" y="360" xlink:href="#p" />
<use x="396" y="360" xlink:href="#p" />
<use x="432" y="360" xlink:href="#p" />
<use x="12" y="372" xlink:href="#p" />
<use x="24" y="372" xlink:href="#p" />
<use x="36" y="372" xlink:href="#p" />
<use x="48" y="372" xlink:href="#p" />
<use x="60" y="372" xlink:href="#p" />
<use x="72" y="372" xlink:href="#p" />
<use x="84" y="372" xlink:href="#p" />
<use x="132" y="372" xlink:href="#p" />
<use x="144" y="372" xlink:href="#p" />
<use x="168" y="372" xlink:href="#p" />
<use x="216" y="372" xlink:href="#p" />
<use x="264" y="372" xlink:href="#p" />
<use x="276" y="372" xlink:href="#p" />
<use x="324" y="372" xlink:href="#p" />
<use x="336" y="372" xlink:href="#p" />
<use x="348" y="372" xlink:href="#p" />
<use x="372" y="372" xlink:href="#p" />
<use x="396" y="372" xlink:href="#p" />
<use x="408" y="372" xlink:href="#p" />
<use x="432" y="372" xlink:href="#p" />
<use x="444" y="372" xlink:href="#p" />
<use x="12" y="384" xlink:href="#p" />
<use x="84" y="384" xlink:href="#p" />
<use x="120" y="384" xlink:href="#p" />
<use x="156" y="384" xlink:href="#p" />
<use x="168" y="384" xlink:href="#p" />
<use x="180" y="384" xlink:href="#p" />
<use x="228" y="384" xlink:href="#p" />
<use x="324" y="384" xlink:href="#p" />
<use x="348" y="384" xlink:href="#p" />
<use x="396" y="384" xlink:href="#p" />
<use x="12" y="396" xlink:href="#p" />
<use x="36" y="396" xlink:href="#p" />
<use x="48" y="396" xlink:href="#p" />
<use x="60" y="396" xlink:href="#p" />
<use x="84" y="396" xlink:href="#p" />
<use x="108" y="396" xlink:href="#p" />
<use x="132" y="396" xlink:href="#p" />
<use x="168" y="396" xlink:href="#p" />
<use x="180" y="396" xlink:href="#p" />
<use x="192" y="396" xlink:href="#p" />
<use x="204" y="396" xlink:href="#p" />
<use x="216" y="396" xlink:href="#p" />
<use x="228" y="396" xlink:href="#p" />
<use x="240" y="396" xlink:href="#p" />
<use x="252" y="396" xlink:href="#p" />
<use x="264" y="396" xlink:href="#p" />
<use x="276" y="396" xlink:href="#p" />
<use x="300" y="396" xlink:href="#p" />
<use x="312" y="396" xlink:href="#p" />
<use x="336" y="396" xlink:href="#p" />
<use x="348" y="396" xlink:href="#p" />
<use x="360" y="396" xlink:href="#p" />
<use x="372" y="396" xlink:href="#p" />
<use x="384" y="396" xlink:href="#p" />
<use x="396" y="396" xlink:href="#p" />
<use x="420" y="396" xlink:href="#p" />
<use x="432" y="396" xlink:href="#p" />
<use x="12" y="408" xlink:href="#p" />
<use x="36" y="408" xlink:href="#p" />
<use x="48" y="408" xlink:href="#p" />
<use x="60" y="408" xlink:href="#p" />
<use x="84" y="408" xlink:href="#p" />
<use x="108" y="408" xlink:href="#p" />
<use x="180" y="408" xlink:href="#p" />
<use x="252" y="408" xlink:href="#p" />
<use x="264" y="408" xlink:href="#p" />
<use x="300" y="408" xlink:href="#p" />
<use x="312" y="408" xlink:href="#p" />
<use x="372" y="408" xlink:href="#p" />
<use x="396" y="408" xlink:href="#p" />
<use x="408" y="408" xlink:href="#p" />
<use x="12" y="420" xlink:href="#p" />
<use x="36" y="420" xlink:href="#p" />
<use x="48" y="420" xlink:href="#p" />
<use x="60" y="420" xlink:href="#p" />
<use x="84" y="420" xlink:href="#p" />
<use x="108" y="420" xlink:href="#p" />
<use x="120" y="420" xlink:href="#p" />
<use x="168" y="420" xlink:href="#p" />
<use x="180" y="420" xlink:href="#p" />
<use x="204" y="420" xlink:href="#p" />
<use x="228" y="420" xlink:href="#p" />
<use x="264" y="420" xlink:href="#p" />
<use x="276" y="420" xlink:href="#p" />
<use x="300" y="420" xlink:href="#p" />
<use x="324" y="420" xlink:href="#p" />
<use x="336" y="420" xlink:href="#p" />
<use x="348" y="420" xlink:href="#p" />
<use x="360" y="420" xlink:href="#p" />
<use x="384" y="420" xlink:href="#p" />
<use x="420" y="420" xlink:href="#p" />
<use x="444" y="420" xlink:href="#p" />
<use x="12" y="432" xlink:href="#p" />
<use x="84" y="432" xlink:href="#p" />
<use x="144" y="432" xlink:href="#p" />
<use x="168" y="432" xlink:href="#p" />
<use x="180" y="432" xlink:href="#p" />
<use x="192" y="432" xlink:href="#p" />
<use x="228" y="432" xlink:href="#p" />
<use x="240" y="432" xlink:href="#p" />
<use x="252" y="432" xlink:href="#p" />
<use x="276" y="432" xlink:href="#p" />
<use x="300" y="432" xlink:href="#p" />
<use x="336" y="432" xlink:href="#p" />
<use x="348" y="432" xlink:href="#p" />
<use x="360" y="432" xlink:href="#p" />
<use x="372" y="432" xlink:href="#p" />
<use x="444" y="432" xlink:href="#p" />
<use x="12" y="444" xlink:href="#p" />
<use x="24" y="444" xlink:href="#p" />
<use x="36" y="444" xlink:href="#p" />
<use x="48" y="444" xlink:href="#p" />
<use x="60" y="444" xlink:href="#p" />
<use x="72" y="444" xlink:href="#p" />
<use x="84" y="444" xlink:href="#p" />
<use x="132" y="444" xlink:href="#p" />
<use x="168" y="444" xlink:href="#p" />
<use x="204" y="444" xlink:href="#p" />
<use x="216" y="444" xlink:href="#p" />
<use x="240" y="444" xlink:href="#p" />
<use x="252" y="444" xlink:href="#p" />
<use x="276" y="444" xlink:href="#p" />
<use x="288" y="444" xlink:href="#p" />
<use x="300" y="444" xlink:href="#p" />
<use x="324" y="444" xlink:href="#p" />
<use x="336" y="444" xlink:href="#p" />
<use x="372" y="444" xlink:href="#p" />
<use x="384" y="444" xlink:href="#p" />
<use x="408" y="444" xlink:href="#p" />
<use x="420" y="444" xlink:href="#p" />
<use x="432" y="444" xlink:href="#p" />
<use x="444" y="444" xlink:href="#p" />
</g>
</svg>
\ No newline at end of file
<template>
<div>
<el-button type="primary" @click="dialogVisible = true" plain round>
<d2-icon name="question-circle-o" class="d2-mr-5"/>
需要帮助吗
</el-button>
<el-dialog
title="帮助"
width="600px"
:visible.sync="dialogVisible"
:append-to-body="true">
<div style="margin-top: -25px;">
<h2 class="d2-mt-0">
这里有一些参考资料
</h2>
<el-button-group>
<el-button @click="$open('https://d2.pub/zh/doc/d2-admin')">
<d2-icon name="book" class="d2-mr-5"/>
文档
</el-button>
<el-button @click="$open('https://github.com/d2-projects/d2-admin/issues?q=is%3Aissue+is%3Aclosed')">
<d2-icon name="question" class="d2-mr-5"/>
历史提问
</el-button>
<el-button @click="$open('https://github.com/d2-projects/d2-admin/issues/new/choose')">
<d2-icon name="plus" class="d2-mr-5"/>
提交问题
</el-button>
</el-button-group>
<h2>询问其它使用者或作者</h2>
<el-row :gutter="20">
<el-col :span="12">
<img src="./image/qq.svg" style="width: 100%;">
<div class="d2-help--qr-info">
请使用手机 QQ 扫面上方二维码<br/>
1群 806395827 (满) | 2群 592981556
</div>
</el-col>
<el-col :span="12">
<img src="./image/we.svg" style="width: 100%;">
<div class="d2-help--qr-info">
请使用手机微信扫面上方二维码<br/>
添加作者微信好友,邀请加入微信群
</div>
</el-col>
</el-row>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
data () {
return {
dialogVisible: false
}
}
}
</script>
<style lang="scss" scoped>
.d2-help--qr-info {
background-color: #f4f4f5;
color: #909399;
width: 100%;
padding: 8px 16px;
margin: 0;
box-sizing: border-box;
border-radius: 4px;
position: relative;
overflow: hidden;
opacity: 1;
display: flex;
align-items: center;
transition: opacity .2s;
}
</style>
<template>
<div class="d2-page-cover">
<div class="d2-page-cover__logo">
<slot/>
</div>
<p class="d2-page-cover__title">D2 Admin {{$version}}</p>
<p class="d2-page-cover__sub-title">优雅的中后台集成方案</p>
<p class="d2-page-cover__build-time">FINAL BUILD TIME {{$buildTime}}</p>
<slot name="footer"/>
<a target="blank" href="https://github.com/d2-projects/d2-admin">
<img
style="position: absolute; top: 0; right: 0; border: 0; width: 150px;"
src="./image/darkblue@2x.png"
alt="Fork me on GitHub">
</a>
</div>
</template>
<style lang="scss" scoped>
.d2-page-cover {
@extend %full;
@extend %unable-select;
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
.d2-page-cover__logo {
img {
width: 200px;
}
}
.d2-page-cover__title {
margin: 0px;
margin-bottom: 20px;
font-weight: bold;
color: $color-text-main;
}
.d2-page-cover__sub-title {
margin: 0px;
margin-bottom: 5px;
color: $color-text-normal;
}
.d2-page-cover__build-time {
margin: 0px;
margin-bottom: 10px;
font-size: 12px;
color: $color-text-placehoder;
}
}
</style>
import page from './page'
export default page
<template>
<d2-container class="page">
<d2-page-cover>
<d2-icon-svg class="logo" name="d2-admin"/>
<template slot="footer">
<div class="btn-group">
<span class="btn-group__btn" @click="$open('https://github.com/d2-projects')">开源组织</span> |
<span class="btn-group__btn" @click="$open('https://d2.pub/zh/doc/d2-admin')">文档</span> |
<span class="btn-group__btn" @click="$open('https://github.com/d2-projects/d2-admin-start-kit')">简化版</span> |
<span class="btn-group__btn" @click="$open('https://juejin.im/user/57a48b632e958a006691b946/posts')">掘金</span> |
<el-popover :width="172" trigger="hover">
<p class="d2-mt-0 d2-mb-10">今日前端</p>
<img src="./image/qr@2x.png" style="width: 172px;">
<span slot="reference" class="btn-group__btn btn-group__btn--link">
<d2-icon name="weixin"/>
微信公众号
</span>
<p style="font-size: 12px; margin-top: 0px; margin-bottom: 0px;">
官方公众号,主要推送前端技术类文章、框架资源、学习教程,以及 D2 系列项目更新信息
</p>
</el-popover>
</div>
<d2-badge/>
<d2-help/>
</template>
</d2-page-cover>
</d2-container>
</template>
<script>
import D2Badge from './components/d2-badge'
import D2Help from './components/d2-help'
import D2PageCover from './components/d2-page-cover'
export default {
components: {
D2Badge,
D2Help,
D2PageCover
},
data () {
return {
filename: __filename
}
}
}
</script>
<style lang="scss" scoped>
.page {
.logo {
width: 120px;
}
.btn-group {
color: $color-text-placehoder;
font-size: 12px;
line-height: 12px;
margin-top: 0px;
margin-bottom: 20px;
.btn-group__btn {
color: $color-text-sub;
&:hover {
color: $color-text-main;
}
&.btn-group__btn--link {
color: $color-primary;
}
}
}
}
</style>
<template>
<d2-container>
<el-table
:data="log"
size="mini"
style="width: 100%"
empty-text="暂无日志信息"
stripe>
<!-- 时间 -->
<el-table-column
prop="time"
label="Time"
width="140">
</el-table-column>
<!-- 信息 -->
<el-table-column
prop="message"
label="Message">
</el-table-column>
<!-- 触发页面 -->
<el-table-column
label="Url"
align="center"
min-width="200">
<template slot-scope="scope">
{{get(scope.row, 'meta.url')}}
</template>
</el-table-column>
<!-- 触发组件 -->
<el-table-column
label="Tag"
align="center"
min-width="120">
<template slot-scope="scope">
<el-tag
v-if="get(scope.row, 'meta.instance.$vnode.componentOptions.tag')"
type="info"
size="mini">
&#60;{{get(scope.row, 'meta.instance.$vnode.componentOptions.tag')}}&gt;
</el-tag>
</template>
</el-table-column>
<!-- 查看详情 -->
<el-table-column
fixed="right"
align="center"
label="More"
width="100">
<template slot-scope="scope">
<el-button
type="primary"
size="mini"
@click="handleShowMore(scope.row)">
<d2-icon name="eye"/>
</el-button>
</template>
</el-table-column>
</el-table>
<el-button
slot="footer"
type="primary"
size="mini"
:loading="uploading"
@click="handleUpload">
<d2-icon name="cloud-upload"/>
Upload {{log.length}} log data
</el-button>
</d2-container>
</template>
<script>
import { mapState } from 'vuex'
import { get } from 'lodash'
export default {
data () {
return {
uploading: false
}
},
computed: {
...mapState('d2admin/log', [
'log'
])
},
methods: {
get,
handleShowMore (log) {
// 打印一条日志的所有信息到控制台
this.$notify({
type: 'info',
title: '日志详情',
message: '完整的日志内容已经打印到控制台'
})
this.$log.capsule('D2Admin', 'handleShowMore', 'primary')
console.group(log.message)
console.log('time: ', log.time)
console.log('type: ', log.type)
console.log(log.meta)
console.groupEnd()
},
// 日志上传
handleUpload () {
this.uploading = true
this.$notify({
type: 'info',
title: '日志上传',
message: `开始上传${this.log.length}条日志`
})
setTimeout(() => {
this.uploading = false
this.$notify({
type: 'success',
title: '日志上传',
message: '上传成功'
})
}, 3000)
}
}
}
</script>
import page from './page'
export default page
<template>
<div class="page-login">
<div class="page-login--layer page-login--layer-area">
<ul class="circles">
<li v-for="n in 10" :key="n"></li>
</ul>
</div>
<div
class="page-login--layer page-login--layer-time"
flex="main:center cross:center">
{{time}}
</div>
<div class="page-login--layer">
<div
class="page-login--content"
flex="dir:top main:justify cross:stretch box:justify">
<div class="page-login--content-header">
<p class="page-login--content-header-motto">
时间是一切财富中最宝贵的财富
</p>
</div>
<div
class="page-login--content-main"
flex="dir:top main:center cross:center">
<!-- logo -->
<img class="page-login--logo" src="./image/logo@2x.png">
<!-- form -->
<div class="page-login--form">
<el-card shadow="never">
<el-form
ref="loginForm"
label-position="top"
:rules="rules"
:model="formLogin"
size="default">
<el-form-item prop="username">
<el-input
type="text"
v-model="formLogin.username"
placeholder="用户名">
<i slot="prepend" class="fa fa-user-circle-o"></i>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
type="password"
v-model="formLogin.password"
placeholder="密码">
<i slot="prepend" class="fa fa-keyboard-o"></i>
</el-input>
</el-form-item>
<el-form-item prop="code">
<el-input
type="text"
v-model="formLogin.code"
placeholder="验证码">
<template slot="append">
<img class="login-code" src="./image/login-code.png">
</template>
</el-input>
</el-form-item>
<el-button
size="default"
@click="submit"
type="primary"
class="button-login">
登录
</el-button>
</el-form>
</el-card>
<p
class="page-login--options"
flex="main:justify cross:center">
<span><d2-icon name="question-circle"/> 忘记密码</span>
<span>注册用户</span>
</p>
<!-- quick login -->
<el-button class="page-login--quick" size="default" type="info" @click="dialogVisible = true">
快速选择用户(测试功能)
</el-button>
</div>
</div>
<div class="page-login--content-footer">
<p class="page-login--content-footer-locales">
<a
v-for="language in $languages"
:key="language.value"
@click="onChangeLocale(language.value)">
{{ language.label }}
</a>
</p>
<p class="page-login--content-footer-copyright">
Copyright
<d2-icon name="copyright"/>
2018 D2 Projects 开源组织出品
<a href="https://github.com/FairyEver">
@FairyEver
</a>
</p>
<p class="page-login--content-footer-options">
<a href="#">帮助</a>
<a href="#">隐私</a>
<a href="#">条款</a>
</p>
</div>
</div>
</div>
<el-dialog
title="快速选择用户"
:visible.sync="dialogVisible"
width="400px">
<el-row :gutter="10" style="margin: -20px 0px -10px 0px;">
<el-col v-for="(user, index) in users" :key="index" :span="8">
<div class="page-login--quick-user" @click="handleUserBtnClick(user)">
<d2-icon name="user-circle-o"/>
<span>{{user.name}}</span>
</div>
</el-col>
</el-row>
</el-dialog>
</div>
</template>
<script>
import dayjs from 'dayjs'
import { mapActions } from 'vuex'
import localeMixin from '@/locales/mixin.js'
export default {
mixins: [
localeMixin
],
data () {
return {
timeInterval: null,
time: dayjs().format('HH:mm:ss'),
// 快速选择用户
dialogVisible: false,
users: [
{
name: 'Admin',
username: 'admin',
password: 'admin'
},
{
name: 'Editor',
username: 'editor',
password: 'editor'
},
{
name: 'User1',
username: 'user1',
password: 'user1'
}
],
// 表单
formLogin: {
username: 'admin',
password: 'admin',
code: 'v9am'
},
// 表单校验
rules: {
username: [
{
required: true,
message: '请输入用户名',
trigger: 'blur'
}
],
password: [
{
required: true,
message: '请输入密码',
trigger: 'blur'
}
],
code: [
{
required: true,
message: '请输入验证码',
trigger: 'blur'
}
]
}
}
},
mounted () {
this.timeInterval = setInterval(() => {
this.refreshTime()
}, 1000)
},
beforeDestroy () {
clearInterval(this.timeInterval)
},
methods: {
...mapActions('d2admin/account', [
'login'
]),
refreshTime () {
this.time = dayjs().format('HH:mm:ss')
},
/**
* @description 接收选择一个用户快速登录的事件
* @param {Object} user 用户信息
*/
handleUserBtnClick (user) {
this.formLogin.username = user.username
this.formLogin.password = user.password
this.submit()
},
/**
* @description 提交表单
*/
// 提交登录信息
submit () {
this.$refs.loginForm.validate((valid) => {
if (valid) {
// 登录
// 注意 这里的演示没有传验证码
// 具体需要传递的数据请自行修改代码
this.login({
username: this.formLogin.username,
password: this.formLogin.password
})
.then(() => {
// 重定向对象不存在则返回顶层路径
this.$router.replace(this.$route.query.redirect || '/')
})
} else {
// 登录表单校验失败
this.$message.error('表单校验失败,请检查')
}
})
}
}
}
</script>
<style lang="scss">
.page-login {
@extend %unable-select;
$backgroundColor: #F0F2F5;
// ---
background-color: $backgroundColor;
height: 100%;
position: relative;
// 层
.page-login--layer {
@extend %full;
overflow: auto;
}
.page-login--layer-area {
overflow: hidden;
}
// 时间
.page-login--layer-time {
font-size: 24em;
font-weight: bold;
color: rgba(0, 0, 0, 0.03);
overflow: hidden;
}
// 登陆页面控件的容器
.page-login--content {
height: 100%;
min-height: 500px;
}
// header
.page-login--content-header {
padding: 1em 0;
.page-login--content-header-motto {
margin: 0px;
padding: 0px;
color: $color-text-normal;
text-align: center;
font-size: 12px;
}
}
// main
.page-login--logo {
width: 240px;
margin-bottom: 2em;
margin-top: -2em;
}
// 登录表单
.page-login--form {
width: 280px;
// 卡片
.el-card {
margin-bottom: 15px;
}
// 登录按钮
.button-login {
width: 100%;
}
// 输入框左边的图表区域缩窄
.el-input-group__prepend {
padding: 0px 14px;
}
.login-code {
height: 40px - 2px;
display: block;
margin: 0px -20px;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
}
// 登陆选项
.page-login--options {
margin: 0px;
padding: 0px;
font-size: 14px;
color: $color-primary;
margin-bottom: 15px;
font-weight: bold;
}
.page-login--quick {
width: 100%;
}
}
// 快速选择用户面板
.page-login--quick-user {
@extend %flex-center-col;
padding: 10px 0px;
border-radius: 4px;
&:hover {
background-color: $color-bg;
i {
color: $color-text-normal;
}
span {
color: $color-text-normal;
}
}
i {
font-size: 36px;
color: $color-text-sub;
}
span {
font-size: 12px;
margin-top: 10px;
color: $color-text-sub;
}
}
// footer
.page-login--content-footer {
padding: 1em 0;
.page-login--content-footer-locales {
padding: 0px;
margin: 0px;
margin-bottom: 15px;
font-size: 12px;
line-height: 12px;
text-align: center;
color: $color-text-normal;
a {
color: $color-text-normal;
margin: 0 .5em;
&:hover {
color: $color-text-main;
}
}
}
.page-login--content-footer-copyright {
padding: 0px;
margin: 0px;
margin-bottom: 10px;
font-size: 12px;
line-height: 12px;
text-align: center;
color: $color-text-normal;
a {
color: $color-text-normal;
}
}
.page-login--content-footer-options {
padding: 0px;
margin: 0px;
font-size: 12px;
line-height: 12px;
text-align: center;
a {
color: $color-text-normal;
margin: 0 1em;
}
}
}
// 背景
.circles {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
margin: 0px;
padding: 0px;
li {
position: absolute;
display: block;
list-style: none;
width: 20px;
height: 20px;
background: #FFF;
animation: animate 25s linear infinite;
bottom: -200px;
@keyframes animate {
0%{
transform: translateY(0) rotate(0deg);
opacity: 1;
border-radius: 0;
}
100%{
transform: translateY(-1000px) rotate(720deg);
opacity: 0;
border-radius: 50%;
}
}
&:nth-child(1) {
left: 15%;
width: 80px;
height: 80px;
animation-delay: 0s;
}
&:nth-child(2) {
left: 5%;
width: 20px;
height: 20px;
animation-delay: 2s;
animation-duration: 12s;
}
&:nth-child(3) {
left: 70%;
width: 20px;
height: 20px;
animation-delay: 4s;
}
&:nth-child(4) {
left: 40%;
width: 60px;
height: 60px;
animation-delay: 0s;
animation-duration: 18s;
}
&:nth-child(5) {
left: 65%;
width: 20px;
height: 20px;
animation-delay: 0s;
}
&:nth-child(6) {
left: 75%;
width: 150px;
height: 150px;
animation-delay: 3s;
}
&:nth-child(7) {
left: 35%;
width: 200px;
height: 200px;
animation-delay: 7s;
}
&:nth-child(8) {
left: 50%;
width: 25px;
height: 25px;
animation-delay: 15s;
animation-duration: 45s;
}
&:nth-child(9) {
left: 20%;
width: 15px;
height: 15px;
animation-delay: 2s;
animation-duration: 35s;
}
&:nth-child(10) {
left: 85%;
width: 150px;
height: 150px;
animation-delay: 0s;
animation-duration: 11s;
}
}
}
}
</style>
module.exports = {
env: {
jest: true
},
rules: {
'import/no-extraneous-dependencies': 'off'
}
}
\ No newline at end of file
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const VueFilenameInjector = require('@d2-projects/vue-filename-injector')
const ThemeColorReplacer = require('webpack-theme-color-replacer')
const forElementUI = require('webpack-theme-color-replacer/forElementUI')
const cdnDependencies = require('./dependencies-cdn')
// 拼接路径
const resolve = dir => require('path').join(__dirname, dir)
// 增加环境变量
process.env.VUE_APP_VERSION = require('./package.json').version
process.env.VUE_APP_BUILD_TIME = require('dayjs')().format('YYYY-M-D HH:mm:ss')
// 基础路径 注意发布之前要先修改这里
let publicPath = process.env.VUE_APP_PUBLIC_PATH || '/'
// 设置不参与构建的库
let externals = {}
cdnDependencies.forEach(package => { externals[package.name] = package.library })
// 引入文件的 cdn 链接
const cdn = {
css: cdnDependencies.map(e => e.css).filter(e => e),
js: cdnDependencies.map(e => e.js).filter(e => e)
}
module.exports = {
// 根据你的实际情况更改这里
publicPath,
lintOnSave: true,
devServer: {
publicPath // 和 publicPath 保持一致
},
css: {
loaderOptions: {
// 设置 scss 公用变量文件
sass: {
prependData: `@import '~@/assets/style/public.scss';`
}
}
},
configureWebpack: config => {
const configNew = {}
if (process.env.NODE_ENV === 'production') {
configNew.externals = externals
configNew.plugins = [
// gzip
new CompressionWebpackPlugin({
filename: '[path].gz[query]',
test: new RegExp('\\.(' + ['js', 'css'].join('|') + ')$'),
threshold: 10240,
minRatio: 0.8,
deleteOriginalAssets: false
})
]
}
if (process.env.NODE_ENV === 'development') {
// 关闭 host check,方便使用 ngrok 之类的内网转发工具
configNew.devServer = {
disableHostCheck: true
}
}
return configNew
},
// 默认设置: https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-service/lib/config/base.js
chainWebpack: config => {
/**
* 添加 CDN 参数到 htmlWebpackPlugin 配置中
*/
config.plugin('html').tap(args => {
if (process.env.NODE_ENV === 'production') {
args[0].cdn = cdn
} else {
args[0].cdn = []
}
return args
})
/**
* 删除懒加载模块的 prefetch preload,降低带宽压力
* https://cli.vuejs.org/zh/guide/html-and-static-assets.html#prefetch
* https://cli.vuejs.org/zh/guide/html-and-static-assets.html#preload
* 而且预渲染时生成的 prefetch 标签是 modern 版本的,低版本浏览器是不需要的
*/
config.plugins
.delete('prefetch')
.delete('preload')
// 解决 cli3 热更新失效 https://github.com/vuejs/vue-cli/issues/1559
config.resolve
.symlinks(true)
config
.plugin('theme-color-replacer')
.use(ThemeColorReplacer, [{
fileName: 'css/theme-colors.[contenthash:8].css',
matchColors: [
...forElementUI.getElementUISeries(process.env.VUE_APP_ELEMENT_COLOR) // Element-ui主色系列
],
externalCssFiles: [ './node_modules/element-ui/lib/theme-chalk/index.css' ], // optional, String or string array. Set external css files (such as cdn css) to extract colors.
changeSelector: forElementUI.changeSelector
}])
config
// 开发环境 sourcemap 不包含列信息
.when(process.env.NODE_ENV === 'development',
config => config.devtool('cheap-source-map')
)
// 预览环境构建 vue-loader 添加 filename
.when(process.env.VUE_APP_SCOURCE_LINK === 'TRUE',
VueFilenameInjector(config, {
propName: process.env.VUE_APP_SOURCE_VIEWER_PROP_NAME
})
)
// markdown
config.module
.rule('md')
.test(/\.md$/)
.use('text-loader')
.loader('text-loader')
.end()
// svg
const svgRule = config.module.rule('svg')
svgRule.uses.clear()
svgRule
.include
.add(resolve('src/assets/svg-icons/icons'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'd2-[name]'
})
.end()
// image exclude
const imagesRule = config.module.rule('images')
imagesRule
.test(/\.(png|jpe?g|gif|webp|svg)(\?.*)?$/)
.exclude
.add(resolve('src/assets/svg-icons/icons'))
.end()
// 重新设置 alias
config.resolve.alias
.set('@api', resolve('src/api'))
// 判断环境加入模拟数据
const entry = config.entry('app')
if (process.env.VUE_APP_BUILD_MODE !== 'NOMOCK') {
entry
.add('@/mock')
.end()
}
// 分析工具
if (process.env.npm_config_report) {
config
.plugin('webpack-bundle-analyzer')
.use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
}
},
// 不输出 map 文件
productionSourceMap: false,
// i18n
pluginOptions: {
i18n: {
locale: 'zh-chs',
fallbackLocale: 'en',
localeDir: 'locales',
enableInSFC: true
}
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment