初始化

This commit is contained in:
骑着蜗牛追导弹 2023-04-27 16:44:20 +08:00
parent 481c3f5682
commit 4c646c1482
167 changed files with 36192 additions and 15 deletions

2
.browserslistrc Normal file
View File

@ -0,0 +1,2 @@
> 1%
last 2 versions

5
.editorconfig Normal file
View File

@ -0,0 +1,5 @@
[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true

4
.env.development Normal file
View File

@ -0,0 +1,4 @@
# 开发环境
# 页面 title 前缀
VUE_APP_TITLE=D2Admin Dev

13
.env.preview Normal file
View File

@ -0,0 +1,13 @@
# 构建预览页面
# 指定构建模式
NODE_ENV=production
# 标记当前构建方式
VUE_APP_BUILD_MODE=PREVIEW
# 显示源码按钮
VUE_APP_SCOURCE_LINK=TRUE
# 部署路径
VUE_APP_PUBLIC_PATH=/

14
.eslintignore Normal file
View File

@ -0,0 +1,14 @@
# 忽略目录
build/
tests/
node_modules/
# D2CRUD 演示
src/views/demo/d2-crud/
# node 覆盖率文件
coverage/
# 忽略文件
**/*-min.js
**/*.min.js

28
.eslintrc.js Normal file
View File

@ -0,0 +1,28 @@
module.exports = {
root: true,
env: {
node: true
},
'extends': [
'plugin:vue/essential',
'@vue/standard'
],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
},
parserOptions: {
parser: 'babel-eslint'
},
overrides: [
{
files: [
'**/__tests__/*.{j,t}s?(x)',
'**/tests/unit/**/*.spec.{j,t}s?(x)'
],
env: {
jest: true
}
}
]
}

18
.gitignore vendored
View File

@ -41,8 +41,8 @@ build/Release
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
@ -74,11 +74,9 @@ web_modules/
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
@ -86,7 +84,7 @@ dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
@ -104,13 +102,3 @@ dist
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

5
.postcssrc.js Normal file
View File

@ -0,0 +1,5 @@
module.exports = {
plugins: {
autoprefixer: {}
}
}

7
babel.config.js Normal file
View File

@ -0,0 +1,7 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
// 允许两种编码引入方式共存,也就是 common 规范与 es6 规范的共存处理
sourceType: 'unambiguous'
}

165
d2-admin.babel Normal file
View File

@ -0,0 +1,165 @@
<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>

24
dependencies-cdn.js Normal file
View File

@ -0,0 +1,24 @@
// If you want to re enable these configurations, please make sure that the version number of each package is the latest
module.exports = [
// { name: 'vue', library: 'Vue', js: 'https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.min.js', css: '' },
// { name: 'vue-i18n', library: 'VueI18n', js: 'https://cdn.jsdelivr.net/npm/vue-i18n@8.15.1/dist/vue-i18n.min.js', css: '' },
// { name: 'vue-router', library: 'VueRouter', js: 'https://cdn.jsdelivr.net/npm/vue-router@3.1.3/dist/vue-router.min.js', css: '' },
// { name: 'vuex', library: 'Vuex', js: 'https://cdn.jsdelivr.net/npm/vuex@3.1.2/dist/vuex.min.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: 'axios-mock-adapter', library: 'AxiosMockAdapter', js: 'https://cdn.jsdelivr.net/npm/axios-mock-adapter@1.18.1/dist/axios-mock-adapter.min.js', css: '' },
// { name: 'element-ui', library: 'ELEMENT', js: 'https://cdn.jsdelivr.net/npm/element-ui@2.15.6/lib/index.js', css: 'https://cdn.jsdelivr.net/npm/element-ui@2.15.6/lib/theme-chalk/index.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@5.2.3/dist/fuse.min.js', css: '' },
// { name: 'hotkeys-js', library: 'hotkeys', js: 'https://cdn.jsdelivr.net/npm/hotkeys-js@3.7.3/dist/hotkeys.min.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.2/dist/screenfull.min.js', css: '' },
// { name: 'sortablejs', library: 'Sortable', js: 'https://cdn.jsdelivr.net/npm/sortablejs@1.10.1/Sortable.min.js', css: '' }
]

3
jest.config.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = {
preset: '@vue/cli-plugin-unit-jest'
}

11
jsconfig.json Normal file
View File

@ -0,0 +1,11 @@
{
"compilerOptions": {
"target": "es2017",
"allowSyntheticDefaultImports": false,
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"exclude": ["node_modules", "dist"]
}

15919
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

73
package.json Normal file
View File

@ -0,0 +1,73 @@
{
"name": "d2-admin",
"version": "1.20.1",
"scripts": {
"serve": "vue-cli-service serve --open",
"dev": "npm run serve",
"build": "vue-cli-service build",
"build:preview": "NODE_OPTIONS=--max_old_space_size=4096 vue-cli-service build --mode preview",
"lint": "vue-cli-service lint --fix",
"test:unit": "vue-cli-service test:unit"
},
"dependencies": {
"axios": "^0.19.0",
"axios-mock-adapter": "^1.18.1",
"better-scroll": "^1.15.2",
"core-js": "^3.4.3",
"dayjs": "^1.8.17",
"element-ui": "^2.15.6",
"faker": "^4.1.0",
"flex.css": "^1.1.7",
"fuse.js": "^5.2.3",
"hotkeys-js": "^3.7.3",
"js-cookie": "^2.2.1",
"lodash": "^4.17.19",
"lowdb": "^1.0.0",
"nprogress": "^0.2.0",
"screenfull": "^5.0.2",
"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.5.0",
"@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": "^5.1.2",
"@vue/test-utils": "^1.0.2",
"babel-eslint": "^10.0.3",
"compression-webpack-plugin": "^3.0.1",
"cz-conventional-changelog": "^3.2.0",
"eslint": "^6.8.0",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"eslint-plugin-vue": "^6.2.2",
"sass": "^1.23.7",
"sass-loader": "^8.0.0",
"svg-sprite-loader": "^4.1.6",
"text-loader": "^0.0.1",
"vue-cli-plugin-i18n": "^1.0.1",
"vue-template-compiler": "^2.6.10",
"webpack-bundle-analyzer": "^3.6.0",
"webpack-theme-color-replacer": "^1.3.3"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
},
"repository": {
"type": "git",
"url": "https://github.com/d2-projects/d2-admin.git"
}
}

BIN
public/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@ -0,0 +1,6 @@
<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>

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

60
public/index.html Normal file
View File

@ -0,0 +1,60 @@
<!DOCTYPE html>
<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 %>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>
Sorry, D2Admin will not work properly without JavaScript support. Enable JavaScript for browsers and continue.
</strong>
</noscript>
<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>

28
src/App.vue Normal file
View File

@ -0,0 +1,28 @@
<template>
<div id="app">
<router-view/>
</div>
</template>
<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>

17
src/api/index.js Normal file
View File

@ -0,0 +1,17 @@
import { assign, map } from 'lodash'
import faker from 'faker/locale/zh_CN'
import { service, request, serviceForMock, requestForMock, mock } from './service'
import * as tools from './tools'
const files = require.context('./modules', true, /\.api\.js$/)
const generators = files.keys().map(key => files(key).default)
export default assign({}, ...map(generators, generator => generator({
service,
request,
serviceForMock,
requestForMock,
mock,
faker,
tools
})))

102
src/api/service.js Normal file
View File

@ -0,0 +1,102 @@
import axios from 'axios'
import Adapter from 'axios-mock-adapter'
import { get } from 'lodash'
import util from '@/libs/util'
import { errorLog, errorCreate } from './tools'
/**
* @description 创建请求实例
*/
function createService () {
// 创建一个 axios 实例
const service = axios.create()
// 请求拦截
service.interceptors.request.use(
config => 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 200:
// [ 示例 ] code === 200 代表没有错误
return dataAxios.data
case 400:
// [ 示例 ] code === 400 代表有错误
errorCreate(`[ code: 400 ] ${dataAxios.msg}: ${response.config.url}`)
break
default:
// 不是正确的 code
errorCreate(`[ code: ${code} ] ${dataAxios.msg}: ${response.config.url}`)
break
}
}
},
error => {
const status = get(error, 'response.status')
switch (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)
}
)
return service
}
/**
* @description 创建请求方法
* @param {Object} service axios 实例
*/
function createRequestFunction (service) {
return function (config) {
const token = util.cookies.get('token')
const configDefault = {
headers: {
Authorization: token,
'Content-Type': get(config, 'headers.Content-Type', 'application/json')
},
timeout: 5000,
baseURL: process.env.VUE_APP_API,
data: {}
}
return service(Object.assign(configDefault, config))
}
}
// 用于真实网络请求的实例和请求方法
export const service = createService()
export const request = createRequestFunction(service)
// 用于模拟网络请求的实例和请求方法
export const serviceForMock = createService()
export const requestForMock = createRequestFunction(serviceForMock)
// 网络请求数据模拟工具
export const mock = new Adapter(serviceForMock)

86
src/api/tools.js Normal file
View File

@ -0,0 +1,86 @@
import { Message } from 'element-ui'
import store from '@/store'
import util from '@/libs/util'
/**
* @description 安全地解析 json 字符串
* @param {String} jsonString 需要解析的 json 字符串
* @param {String} defaultValue 默认值
*/
export function parse (jsonString = '{}', defaultValue = {}) {
let result = defaultValue
try {
result = JSON.parse(jsonString)
} catch (error) {
console.log(error)
}
return result
}
/**
* @description 接口请求返回
* @param {Any} data 返回值
* @param {String} msg 状态信息
* @param {Number} code 状态码
*/
export function response (data = {}, msg = '', code = 0) {
return [
200,
{ code, msg, data }
]
}
/**
* @description 接口请求返回 正确返回
* @param {Any} data 返回值
* @param {String} msg 状态信息
*/
export function responseSuccess (data = {}, msg = '成功') {
return response(data, msg)
}
/**
* @description 接口请求返回 错误返回
* @param {Any} data 返回值
* @param {String} msg 状态信息
* @param {Number} code 状态码
*/
export function responseError (data = {}, msg = '请求失败', code = 500) {
return response(data, msg, code)
}
/**
* @description 记录和显示错误
* @param {Error} error 错误对象
*/
export 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
})
}
/**
* @description 创建一个错误
* @param {String} msg 错误信息
*/
export function errorCreate (msg) {
const error = new Error(msg)
errorLog(error)
throw error
}

View File

@ -0,0 +1,27 @@
// 过渡动画 横向渐变
.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);
}

View File

@ -0,0 +1,12 @@
// 优化显示
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;
}
}
}

View File

@ -0,0 +1,31 @@
// 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;
}
// 修复IE宽度不能撑满
.el-table__body,
.el-table__header {
width: 100% !important;
}
// Chrome下表格头部错位修复
.el-table th.gutter,
.el-table colgroup.gutter {
display: table-cell !important;
}

View File

@ -0,0 +1,9 @@
// markdown 样式补丁
.markdown-body {
ul {
list-style: disc;
}
h1, h2 {
border-bottom: none;
}
}

View File

@ -0,0 +1,8 @@
#nprogress {
.bar {
background: $color-primary !important;
}
.peg {
box-shadow: 0 0 10px $color-primary, 0 0 5px $color-primary !important;
}
}

View File

@ -0,0 +1,5 @@
.tree-view-wrapper.tree-view-small {
.tree-view-item {
font-size: 10px;
}
}

View File

@ -0,0 +1,9 @@
// vue-splitpane 样式补丁
.vue-grid-item {
&.vue-grid-placeholder {
border: 1px solid $color-border-1;
background-color: rgba(#FFF, .3);
opacity: 1;
border-radius: 4px;
}
}

View File

@ -0,0 +1,5 @@
// vue-splitpane 样式补丁
.splitter-pane-resizer {
background-color: $color-border-1 !important;
opacity: 1 !important;
}

View File

@ -0,0 +1,67 @@
@import 'public';
// 补丁 base
@import '~@/assets/style/fixed/base.scss';
// 补丁 element
@import '~@/assets/style/fixed/element.scss';
// 补丁 markdown
@import '~@/assets/style/fixed/markdown.scss';
// 补丁 n-progress
@import '~@/assets/style/fixed/n-progress.scss';
// 补丁 vue-splitpane
@import '~@/assets/style/fixed/vue-splitpane.scss';
// 补丁 vue-grid-layout
@import '~@/assets/style/fixed/vue-grid-layout.scss';
// 补丁 tree-view
@import '~@/assets/style/fixed/tree-view.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; }

View File

@ -0,0 +1,44 @@
@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;
}

View File

@ -0,0 +1,2 @@
@import './setting.scss';
@import '../theme.scss';

View File

@ -0,0 +1,64 @@
// 主题名称
$theme-name: 'chester';
// 主题背景颜色
$theme-bg-color: #2C3643;
// 主题背景图片遮罩
$theme-bg-mask: rgba(#000, 0);
// 消息提示
$theme-message-info-background-color: #FFFFFF;
$theme-message-info-text-color: #222A34;
$theme-message-info-border-color: #222A34;
// 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 #2A2D2E;
$theme-multiple-page-control-color: #CCCCCC;
$theme-multiple-page-control-color-active: #242D38;
$theme-multiple-page-control-nav-prev-color: #CCCCCC;
$theme-multiple-page-control-nav-next-color: #CCCCCC;
$theme-multiple-page-control-border-color: #2A2D2E;
$theme-multiple-page-control-border-color-active: #FFFFFF;
$theme-multiple-page-control-background-color: #242D38;
$theme-multiple-page-control-background-color-active: #FFFFFF;
// 顶栏和侧边栏中展开的菜单 hover 状态下
$theme-menu-item-color-hover: #CCCCCC;
$theme-menu-item-background-color-hover: #2A2D2E;
// 顶栏上的文字颜色
$theme-header-item-color: #CCCCCC;
$theme-header-item-background-color: transparent;
// 顶栏上的项目在 hover
$theme-header-item-color-hover: #CCCCCC;
$theme-header-item-background-color-hover: #2A2D2E;
// 顶栏上的项目在 focus
$theme-header-item-color-focus: #CCCCCC;
$theme-header-item-background-color-focus: #222A34;
// 顶栏上的项目在 active
$theme-header-item-color-active: #FFFFFF;
$theme-header-item-background-color-active: #222A34;
// 侧边栏上的文字颜色
$theme-aside-item-color: #CCCCCC;
$theme-aside-item-background-color: transparent;
// 侧边栏上的项目在 hover
$theme-aside-item-color-hover: #CCCCCC;
$theme-aside-item-background-color-hover: #2A2D2E;
// 侧边栏上的项目在 focus
$theme-aside-item-color-focus: #CCCCCC;
$theme-aside-item-background-color-focus: #222A34;
// 侧边栏上的项目在 active
$theme-aside-item-color-active: #FFFFFF;
$theme-aside-item-background-color-active: #222A34;
// 侧边栏菜单为空的时候显示的元素
$theme-aside-menu-empty-icon-color: #CCCCCC;
$theme-aside-menu-empty-text-color: #CCCCCC;
$theme-aside-menu-empty-background-color: #242D38;
$theme-aside-menu-empty-icon-color-hover: #FFFFFF;
$theme-aside-menu-empty-text-color-hover: #FFFFFF;
$theme-aside-menu-empty-background-color-hover: #242D38;

View File

@ -0,0 +1,2 @@
@import './setting.scss';
@import '../theme.scss';

View File

@ -0,0 +1,64 @@
// 主题名称
$theme-name: 'd2';
// 主题背景颜色
$theme-bg-color: #ebf1f6;
// 主题背景图片遮罩
$theme-bg-mask: rgba(#000, 0);
// 消息提示
$theme-message-info-background-color: $color-bg;
$theme-message-info-text-color: $color-text-normal;
$theme-message-info-border-color: $color-border-1;
// 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-background-color: transparent;
// 顶栏上的项目在 hover
$theme-header-item-color-hover: #2f74ff;
$theme-header-item-background-color-hover: rgba(#FFF, .5);
// 顶栏上的项目在 focus
$theme-header-item-color-focus: #2f74ff;
$theme-header-item-background-color-focus: rgba(#FFF, .5);
// 顶栏上的项目在 active
$theme-header-item-color-active: #2f74ff;
$theme-header-item-background-color-active: rgba(#FFF, .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);

View File

@ -0,0 +1,2 @@
@import './setting.scss';
@import '../theme.scss';

View File

@ -0,0 +1,64 @@
// 主题名称
$theme-name: 'element';
// 主题背景颜色
$theme-bg-color: #314255;
// 主题背景图片遮罩
$theme-bg-mask: rgba(#000, 0);
// 消息提示
$theme-message-info-background-color: #FFFFFF;
$theme-message-info-text-color: #202D3D;
$theme-message-info-border-color: #202D3D;
// 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 #011527;
$theme-multiple-page-control-color: #BFCBD9;
$theme-multiple-page-control-color-active: #46A0FC;
$theme-multiple-page-control-nav-prev-color: #BFCBD9;
$theme-multiple-page-control-nav-next-color: #BFCBD9;
$theme-multiple-page-control-border-color: #011527;
$theme-multiple-page-control-border-color-active: #FFFFFF;
$theme-multiple-page-control-background-color: #212D3D;
$theme-multiple-page-control-background-color-active: #FFFFFF;
// 顶栏和侧边栏中展开的菜单 hover 状态下
$theme-menu-item-color-hover: #BFCBD9;
$theme-menu-item-background-color-hover: #011527;
// 顶栏上的文字颜色
$theme-header-item-color: #BFCBD9;
$theme-header-item-background-color: transparent;
// 顶栏上的项目在 hover
$theme-header-item-color-hover: #BFCBD9;
$theme-header-item-background-color-hover: #011527;
// 顶栏上的项目在 focus
$theme-header-item-color-focus: #BFCBD9;
$theme-header-item-background-color-focus: #202D3D;
// 顶栏上的项目在 active
$theme-header-item-color-active: #46A0FC;
$theme-header-item-background-color-active: #202D3D;
// 侧边栏上的文字颜色
$theme-aside-item-color: #BFCBD9;
$theme-aside-item-background-color: transparent;
// 侧边栏上的项目在 hover
$theme-aside-item-color-hover: #BFCBD9;
$theme-aside-item-background-color-hover: #011527;
// 侧边栏上的项目在 focus
$theme-aside-item-color-focus: #BFCBD9;
$theme-aside-item-background-color-focus: #202D3D;
// 侧边栏上的项目在 active
$theme-aside-item-color-active: #46A0FC;
$theme-aside-item-background-color-active: #202D3D;
// 侧边栏菜单为空的时候显示的元素
$theme-aside-menu-empty-icon-color: #BFCBD9;
$theme-aside-menu-empty-text-color: #BFCBD9;
$theme-aside-menu-empty-background-color: #202D3D;
$theme-aside-menu-empty-icon-color-hover: #46A0FC;
$theme-aside-menu-empty-text-color-hover: #46A0FC;
$theme-aside-menu-empty-background-color-hover: #202D3D;

View File

@ -0,0 +1,2 @@
@import './setting.scss';
@import '../theme.scss';

View File

@ -0,0 +1,64 @@
// 主题名称
$theme-name: 'line';
// 主题背景颜色
$theme-bg-color: #f8f8f9;
// 主题背景图片遮罩
$theme-bg-mask: rgba(#000, 0);
// 消息提示
$theme-message-info-background-color: $color-bg;
$theme-message-info-text-color: $color-text-normal;
$theme-message-info-border-color: $color-border-1;
// 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);

View File

@ -0,0 +1,9 @@
@import '~@/assets/style/theme/theme-base.scss';
@import '~@/assets/style/theme/d2/index.scss';
@import '~@/assets/style/theme/chester/index.scss';
@import '~@/assets/style/theme/element/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';

View File

@ -0,0 +1,2 @@
@import './setting.scss';
@import '../theme.scss';

View File

@ -0,0 +1,64 @@
// 主题名称
$theme-name: 'star';
// 主题背景颜色
$theme-bg-color: #EFF4F8;
// 主题背景图片遮罩
$theme-bg-mask: rgba(#000, .3);
// 消息提示
$theme-message-info-background-color: $color-bg;
$theme-message-info-text-color: $color-text-normal;
$theme-message-info-border-color: $color-border-1;
// 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);

View File

@ -0,0 +1,455 @@
// 减小弹出菜单的项目高度
.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: 402px;
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 {
position: relative;
.d2-layout-header-aside-menu-side {
@extend %full;
overflow: hidden;
}
}
.d2-theme-container-transition {
transition: width .3s;
}
.d2-theme-container-main {
padding: 0px;
position: relative;
overflow: hidden;
.d2-theme-container-main-layer {
position: absolute;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
}
.d2-theme-container-main-body {
position: relative;
margin-top: 5px;
}
}
}
}
}
// 主题公用
.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 {
float: left;
text-align: center;
img {
height: 60px;
}
}
.logo-transition {
transition: width .3s;
}
// 折叠侧边栏切换按钮
.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;
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,423 @@
// 每个主题特有的设置
.theme-#{$theme-name} {
.el-message {
&.el-message--info {
background-color: $theme-message-info-background-color;
color: $theme-message-info-text-color;
border-color: $theme-message-info-border-color;
}
}
.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-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;
// 边框圆角
border-radius: 5px;
.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;
}
}
}
}
}
}
}

View File

@ -0,0 +1,2 @@
@import './setting.scss';
@import '../theme.scss';

View File

@ -0,0 +1,64 @@
// 主题名称
$theme-name: 'tomorrow-night-blue';
// 主题背景颜色
$theme-bg-color: #002253;
// 主题背景图片遮罩
$theme-bg-mask: rgba(#000, 0);
// 消息提示
$theme-message-info-background-color: $color-bg;
$theme-message-info-text-color: $color-text-normal;
$theme-message-info-border-color: $color-border-1;
// 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);

View File

@ -0,0 +1,9 @@
@import './setting.scss';
@import '../theme.scss';
.theme-#{$theme-name} {
.d2-layout-header-aside-group {
background: #bc00e3;
background: linear-gradient(120deg, #bc00e3 0%, #4EFFFB 100%);
}
}

View File

@ -0,0 +1,64 @@
// 主题名称
$theme-name: 'violet';
// 主题背景颜色
$theme-bg-color: #000;
// 主题背景图片遮罩
$theme-bg-mask: rgba(#000, 0);
// 消息提示
$theme-message-info-background-color: $color-bg;
$theme-message-info-text-color: $color-text-normal;
$theme-message-info-border-color: $color-border-1;
// 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);

View File

@ -0,0 +1,23 @@
// 主色
$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;

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

@ -0,0 +1,13 @@
<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>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,7 @@
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))

View File

@ -0,0 +1,27 @@
<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>

View File

@ -0,0 +1,33 @@
<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>

View File

@ -0,0 +1,25 @@
<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>

View File

@ -0,0 +1,31 @@
<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>

View File

@ -0,0 +1,26 @@
<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>

View File

@ -0,0 +1,31 @@
<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>

View File

@ -0,0 +1,79 @@
<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>

View File

@ -0,0 +1,62 @@
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
})
}
}
}
}

View File

@ -0,0 +1,67 @@
// 提供滚动方面的功能
// 非滚动优化模式通用
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()
}
}
}

View File

@ -0,0 +1,106 @@
// 组件
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,
this.$slots.header ? <template slot="header">{ this.$slots.header }</template> : null,
this.$slots.footer ? <template slot="footer">{ this.$slots.footer }</template> : null
]
return <div
ref="container"
class="container-component">
<this.component
ref="component"
{ ...{ attrs: this.$attrs } }
onScroll={ e => this.$emit('scroll', e) }>
{ slots }
</this.component>
<d2Source/>
</div>
},
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
}
}
}
}

View File

@ -0,0 +1,22 @@
<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>

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 434 KiB

View File

@ -0,0 +1,17 @@
<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>

8
src/components/index.js Normal file
View File

@ -0,0 +1,8 @@
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'))

37
src/i18n.js Normal file
View File

@ -0,0 +1,37 @@
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

View File

@ -0,0 +1,50 @@
<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>

View File

@ -0,0 +1,68 @@
<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>

Some files were not shown because too many files have changed in this diff Show More