Hippo4j console ui migrated to this project (#818)

pull/823/head
chen.ma 2 years ago
parent 946e7eaa00
commit c42283b970

2
.gitignore vendored

@ -39,4 +39,4 @@ build/
### Docs ###
docs/node_modules
docs/build
docs/.docusaurus
docs/.docusaurus

@ -0,0 +1,14 @@
# https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

@ -0,0 +1,17 @@
# just a flag
ENV = 'development'
# base api
VUE_APP_BASE_API = ''
# no mock api
VUE_APP_API = ''
# vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable,
# to control whether the babel-plugin-dynamic-import-node plugin is enabled.
# It only does one thing by converting all import() to require().
# This configuration can significantly increase the speed of hot updates,
# when you have a large number of pages.
# Detail: https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/babel-preset-app/index.js
VUE_CLI_BABEL_TRANSPILE_MODULES = true

@ -0,0 +1,5 @@
# just a flag
ENV = 'production'
# base api
VUE_APP_BASE_API = ''

@ -0,0 +1,8 @@
NODE_ENV = production
# just a flag
ENV = 'staging'
# base api
VUE_APP_BASE_API = '/stage-api'

@ -0,0 +1,5 @@
build/*.js
src/assets
public
dist
*.vue

@ -0,0 +1,17 @@
module.exports = {
root: true,
parserOptions: {
parser: 'babel-eslint',
sourceType: 'module',
},
env: {
browser: true,
node: true,
es6: true,
},
extends: ['plugin:vue/recommended', 'eslint:recommended', 'prettier'],
rules: {
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'no-console': process.env.NODE_ENV === 'production' ? 2 : 0,
},
};

@ -0,0 +1,23 @@
.DS_Store
node_modules/
dist/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
**/*.log
tests/**/coverage/
tests/e2e/reports
selenium-debug.log
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.local
package-lock.json
yarn.lock

@ -0,0 +1,5 @@
module.exports = {
singleQuote: true,
trailingComma: 'all',
printWidth: 100,
};

@ -0,0 +1,5 @@
language: node_js
node_js: 10
script: npm run test
notifications:
email: false

@ -0,0 +1,23 @@
## 说明
该项目由 [datax-web-ui](https://github.com/WeiYe-Jing/datax-web-ui)、[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) 修改而来。
## Build Setup
运行:
```
npm install [ 慢的话用 npm install --registry https://registry.npm.taobao.org]
```
启动:
```
npm run dev
```
打包:
```
npm run build:prod
```

@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/app'
]
}

@ -0,0 +1,24 @@
module.exports = {
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
transform: {
'^.+\\.vue$': 'vue-jest',
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
'jest-transform-stub',
'^.+\\.jsx?$': 'babel-jest'
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
snapshotSerializers: ['jest-serializer-vue'],
testMatch: [
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
],
collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'],
coverageDirectory: '<rootDir>/tests/unit/coverage',
// 'collectCoverage': true,
'coverageReporters': [
'lcov',
'text-summary'
],
testURL: 'http://localhost/'
}

@ -0,0 +1,107 @@
{
"name": "vue-element-admin",
"version": "4.2.1",
"description": "hippo4j console ui",
"author": "jingwk",
"license": "MIT",
"scripts": {
"dev": "vue-cli-service serve",
"build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
"lint": "eslint --ext .js,.vue src",
"test:unit": "jest --clearCache && vue-cli-service test:unit",
"test:ci": "npm run lint && npm run test:unit",
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
"new": "plop"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"src/**/*.{js,vue}": [
"eslint --fix",
"git add"
]
},
"keywords": [
"vue",
"admin",
"dashboard",
"element-ui",
"boilerplate",
"admin-template",
"management-system"
],
"repository": {
"type": "git",
"url": "git+https://github.com/PanJiaChen/vue-element-admin.git"
},
"bugs": {
"url": "https://github.com/PanJiaChen/vue-element-admin/issues"
},
"dependencies": {
"axios": ">=0.18.1",
"clipboard": "2.0.4",
"codemirror": "5.45.0",
"echarts": "^5.2.2",
"element-ui": "^2.15.7",
"fuse.js": "3.4.4",
"js-cookie": "2.2.0",
"jsonlint": "1.6.3",
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"path-to-regexp": "2.4.0",
"prettier": "^2.5.1",
"screenfull": "4.2.0",
"vue": "2.6.10",
"vue-cookie": "^1.1.4",
"vue-count-to": "1.0.13",
"vue-router": "3.0.2",
"vue-splitpane": "1.0.4",
"vue2-jsoneditor": "^1.0.6",
"vuedraggable": "2.20.0",
"vuex": "3.1.0"
},
"devDependencies": {
"@babel/core": "7.0.0",
"@babel/register": "7.0.0",
"@vue/cli-plugin-babel": "3.5.3",
"@vue/cli-plugin-eslint": "3.5.1",
"@vue/cli-plugin-unit-jest": "3.5.3",
"@vue/cli-service": "3.5.3",
"@vue/test-utils": "1.0.0-beta.29",
"autoprefixer": "^9.5.1",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "10.0.1",
"babel-jest": "23.6.0",
"chalk": "2.4.2",
"chokidar": "2.1.5",
"connect": "3.6.6",
"eslint": "5.15.3",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-vue": "5.2.2",
"html-webpack-plugin": "3.2.0",
"lint-staged": "8.1.5",
"plop": "2.3.0",
"runjs": "^4.3.2",
"sass": "^1.48.0",
"sass-loader": "^8.0.0",
"script-ext-html-webpack-plugin": "2.1.3",
"script-loader": "0.7.2",
"serve-static": "^1.13.2",
"svg-sprite-loader": "4.1.3",
"svgo": "1.2.0",
"vue-template-compiler": "2.6.10"
},
"engines": {
"node": ">=8.9",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions"
]
}

@ -0,0 +1,7 @@
const viewGenerator = require('./plop-templates/view/prompt')
const componentGenerator = require('./plop-templates/component/prompt')
module.exports = function(plop) {
plop.setGenerator('view', viewGenerator)
plop.setGenerator('component', componentGenerator)
}

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= webpackConfig.name %></title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

@ -0,0 +1,11 @@
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
name: 'App',
};
</script>

@ -0,0 +1,38 @@
import request from '@/utils/request'
// dashborad
export function chartInfo() {
return request({
url: '/hippo4j/v1/cs/dashboard',
method: 'get'
})
}
export function lineChart() {
return request({
url: '/hippo4j/v1/cs/dashboard/line/chart',
method: 'get'
})
}
export function pieChart() {
return request({
url: '/hippo4j/v1/cs/dashboard/pie/chart',
method: 'get'
})
}
export function tenantChart() {
return request({
url: '/hippo4j/v1/cs/dashboard/tenant/chart',
method: 'get'
})
}
export function ranking() {
return request({
url: '/hippo4j/v1/cs/dashboard/ranking',
method: 'get'
})
}

@ -0,0 +1,24 @@
import request from '@/utils/request'
export function list(data) {
return request({
url: '/hippo4j/v1/cs/adapter/thread-pool/query?mark=' + data.mark + '&tenant=' + data.tenantId + '&item=' + data.itemId + '&threadPoolKey=' + data.threadPoolKey,
method: 'get'
})
}
export function listKey(data) {
return request({
url: '/hippo4j/v1/cs/adapter/thread-pool/query/key?mark=' + data.mark + '&tenant=' + data.tenantId + '&item=' + data.itemId,
method: 'get'
})
}
export function updatePool(data) {
return request({
url: '/hippo4j/v1/cs/adapter/thread-pool/update',
method: 'post',
data
})
}

@ -0,0 +1,41 @@
import request from '@/utils/request'
export function list(listArray) {
return request({
url: '/hippo4j/v1/cs/thread/pool/list/instance/' + listArray[0] + '/' + listArray[1],
method: 'get'
})
}
export function tenantList(data) {
return request({
url: '/hippo4j/v1/cs/item/query/page',
method: 'post',
data
})
}
export function updated(data) {
return request({
url: '/hippo4j/v1/cs/configs?identify=' + data.identify,
method: 'post',
data
})
}
export function created(data) {
return request({
url: '/hippo4j/v1/cs/thread/pool/save_or_update',
method: 'post',
data
})
}
export function deleted(data) {
return request({
url: '/hippo4j/v1/cs/thread/pool/delete',
method: 'delete',
data
})
}

@ -0,0 +1,48 @@
import request from '@/utils/request';
export function list(data) {
return request({
url: '/hippo4j/v1/cs/item/query/page',
method: 'post',
data,
});
}
export function tenantList(data) {
return request({
url: '/hippo4j/v1/cs/item/query/page',
method: 'post',
data,
});
}
export function updated(data) {
return request({
url: '/hippo4j/v1/cs/item/update',
method: 'post',
data,
});
}
export function created(data) {
return request({
url: '/hippo4j/v1/cs/item/save',
method: 'post',
data,
});
}
export function deleted(data) {
return request({
url: '/hippo4j/v1/cs/item/delete/' + data[0] + '/' + data[1],
method: 'delete',
});
}
export function getJobProjectList(params) {
return request({
url: 'v1/cs/jobProject/list',
method: 'get',
params,
});
}

@ -0,0 +1,9 @@
import request from '@/utils/request';
export function list(data) {
return request({
url: '/hippo4j/v1/cs/log/query/page',
method: 'post',
data,
});
}

@ -0,0 +1,25 @@
import request from '@/utils/request';
export function list(data) {
return request({
url: '/hippo4j/v1/cs/log/query/page',
method: 'post',
data,
});
}
export function active(data) {
return request({
url: '/hippo4j/v1/cs/monitor/info',
method: 'post',
data,
});
}
export function lastTaskCountFun(data) {
return request({
url: '/hippo4j/v1/cs/monitor/last/task/count',
method: 'post',
data,
});
}

@ -0,0 +1,48 @@
import request from '@/utils/request';
export function list(data) {
return request({
url: '/hippo4j/v1/cs/notify/query/page',
method: 'post',
data,
});
}
export function tenantList(data) {
return request({
url: '/hippo4j/v1/cs/item/query/page',
method: 'post',
data,
});
}
export function updated(data) {
return request({
url: '/hippo4j/v1/cs/notify/update',
method: 'post',
data,
});
}
export function created(data) {
return request({
url: '/hippo4j/v1/cs/notify/save',
method: 'post',
data,
});
}
export function deleted(data) {
return request({
url: '/hippo4j/v1/cs/notify/remove',
method: 'delete',
data,
});
}
export function enable(data) {
return request({
url: '/hippo4j/v1/cs/notify/enable/' + data.id + '/' + data.enable,
method: 'post',
});
}

@ -0,0 +1,32 @@
import request from '@/utils/request';
export function list(data) {
return request({
url: '/hippo4j/v1/cs/tenant/query/page',
method: 'post',
data,
});
}
export function updated(data) {
return request({
url: '/hippo4j/v1/cs/tenant/update',
method: 'post',
data,
});
}
export function created(data) {
return request({
url: '/hippo4j/v1/cs/tenant/save',
method: 'post',
data,
});
}
export function deleted(data) {
return request({
url: '/hippo4j/v1/cs/tenant/delete/' + data,
method: 'delete',
});
}

@ -0,0 +1,102 @@
import request from '@/utils/request'
export function list(data) {
return request({
url: '/hippo4j/v1/cs/thread/pool/query/page',
method: 'post',
data
})
}
export function listClient(data) {
return request({
url: '/hippo4j/v1/cs/thread/pool/list/client/instance/' + data.itemId,
method: 'get',
data
})
}
export function info(data) {
return request({
url: '/hippo4j/v1/cs/configs?tpId=' + data.tpId + '&itemId=' + data.itemId + '&namespace=' + data.tenantId + '&instanceId=' + data.identify,
method: 'get'
})
}
export function runState(data) {
return request({
url: '/hippo4j/v1/cs/thread/pool/run/state/' + data.tpId + '?clientAddress=' + data.clientAddress,
method: 'get'
})
}
export function runThreadState(data) {
return request({
url: '/hippo4j/v1/cs/thread/pool/run/thread/state/' + data.tpId + '?clientAddress=' + data.clientAddress,
method: 'get'
})
}
export function webBaseInfo(data) {
return request({
// async: false,
url: '/hippo4j/v1/cs/thread/pool/web/base/info' + '?clientAddress=' + data.clientAddress,
method: 'get'
})
}
export function webBaseState(data) {
return request({
// async: false,
url: '/hippo4j/v1/cs/thread/pool/web/run/state' + '?clientAddress=' + data.clientAddress,
method: 'get'
})
}
export function webUpdatePool(data) {
return request({
url: '/hippo4j/v1/cs/thread/pool/web/update/pool',
method: 'post',
data
})
}
export function tenantList(data) {
return request({
url: '/hippo4j/v1/cs/item/query/page',
method: 'post',
data
})
}
export function updated(data) {
return request({
url: '/hippo4j/v1/cs/thread/pool/save_or_update',
method: 'post',
data
})
}
export function created(data) {
return request({
url: '/hippo4j/v1/cs/thread/pool/save_or_update',
method: 'post',
data
})
}
export function deleted(data) {
return request({
url: '/hippo4j/v1/cs/thread/pool/delete',
method: 'delete',
data
})
}
export function alarmEnable(data) {
return request({
url: '/hippo4j/v1/cs/thread/pool/alarm/enable/' + data.id + '/' + data.isAlarm,
method: 'post'
})
}

@ -0,0 +1,40 @@
import request from '@/utils/request'
export function getList(data) {
return request({
url: '/hippo4j/v1/cs/auth/users/page',
method: 'post',
data
})
}
export function updateUser(data) {
return request({
url: '/hippo4j/v1/cs/auth/users/update',
method: 'put',
data
})
}
export function createUser(data) {
return request({
url: '/hippo4j/v1/cs/auth/users/add',
method: 'post',
data
})
}
export function deleteUser(name) {
return request({
url: '/hippo4j/v1/cs/auth/users/remove/' + name,
method: 'delete'
})
}
export function getCurrentUser(name) {
return request({
url: '/hippo4j/v1/cs/auth/users/info/' + name,
method: 'get'
})
}

@ -0,0 +1,54 @@
import request from '@/utils/request'
export function getTables(params) {
return request({
url: '/api/metadata/getTables',
method: 'get',
params
})
}
// 获取schema
export function getTableSchema(params) {
return request({
url: '/api/metadata/getDBSchema',
method: 'get',
params
})
}
// 获取字段
export function getColumns(params) {
return request({
url: '/api/metadata/getColumns',
method: 'get',
params
})
}
// 根据sql获取字段
export function getColumnsByQuerySql(params) {
return request({
url: '/api/metadata/getColumnsByQuerySql',
method: 'get',
params
})
}
// 根据datasourceID、tablename创建表【目标端】
export function createTable(params) {
return request({
url: '/api/metadata/createTable',
method: 'post',
params
})
}
// 判断字段是否存在,存在,即更新值,否则添加字段
export function updateColumnsValue(query) {
return request({
url: '/api/metadata/updateColumnsValue',
method: 'post',
data: query
})
}

@ -0,0 +1,17 @@
import request from '@/utils/request'
export function searchUser(name) {
return request({
url: '/search/user',
method: 'get',
params: { name }
})
}
export function transactionList(query) {
return request({
url: '/transaction/list',
method: 'get',
params: query
})
}

@ -0,0 +1,38 @@
import request from '@/utils/request'
export function getRoutes() {
return request({
url: '/routes',
method: 'get'
})
}
export function getRoles() {
return request({
url: '/roles',
method: 'get'
})
}
export function addRole(data) {
return request({
url: '/role',
method: 'post',
data
})
}
export function updateRole(id, data) {
return request({
url: `/role/${id}`,
method: 'put',
data
})
}
export function deleteRole(id) {
return request({
url: `/role/${id}`,
method: 'delete'
})
}

@ -0,0 +1,23 @@
import request from '@/utils/request'
export function login(data) {
return request({
url: '/hippo4j/v1/cs/auth/login',
method: 'post',
data
})
}
export function getInfo() {
return request({
url: '/hippo4j/v1/cs/user/info',
method: 'get'
})
}
export function logout() {
return request({
url: '/hippo4j/v1/cs/user/logout',
method: 'post'
})
}

@ -0,0 +1,27 @@
import request from '@/utils/request'
export function list(data) {
return request({
url: '/hippo4j/v1/cs/configs/verify/query/application/page',
method: 'post',
data
})
}
export function verify(data) {
return request({
url: '/hippo4j/v1/cs/configs/verify',
method: 'post',
data
})
}
export function applicationDetail(data){
return request({
url: '/hippo4j/v1/cs/configs/verify/query/application/detail?id='+data,
method: 'get',
data
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

File diff suppressed because one or more lines are too long

@ -0,0 +1,111 @@
<template>
<transition :name="transitionName">
<div v-show="visible" :style="customStyle" class="back-to-ceiling" @click="backToTop">
<svg width="16" height="16" viewBox="0 0 17 17" xmlns="http://www.w3.org/2000/svg" class="Icon Icon--backToTopArrow" aria-hidden="true" style="height:16px;width:16px"><path d="M12.036 15.59a1 1 0 0 1-.997.995H5.032a.996.996 0 0 1-.997-.996V8.584H1.03c-1.1 0-1.36-.633-.578-1.416L7.33.29a1.003 1.003 0 0 1 1.412 0l6.878 6.88c.782.78.523 1.415-.58 1.415h-3.004v7.004z" /></svg>
</div>
</transition>
</template>
<script>
export default {
name: 'BackToTop',
props: {
visibilityHeight: {
type: Number,
default: 400
},
backPosition: {
type: Number,
default: 0
},
customStyle: {
type: Object,
default: function() {
return {
right: '50px',
bottom: '50px',
width: '40px',
height: '40px',
'border-radius': '4px',
'line-height': '45px',
background: '#e7eaf1'
}
}
},
transitionName: {
type: String,
default: 'fade'
}
},
data() {
return {
visible: false,
interval: null,
isMoving: false
}
},
mounted() {
window.addEventListener('scroll', this.handleScroll)
},
beforeDestroy() {
window.removeEventListener('scroll', this.handleScroll)
if (this.interval) {
clearInterval(this.interval)
}
},
methods: {
handleScroll() {
this.visible = window.pageYOffset > this.visibilityHeight
},
backToTop() {
if (this.isMoving) return
const start = window.pageYOffset
let i = 0
this.isMoving = true
this.interval = setInterval(() => {
const next = Math.floor(this.easeInOutQuad(10 * i, start, -start, 500))
if (next <= this.backPosition) {
window.scrollTo(0, this.backPosition)
clearInterval(this.interval)
this.isMoving = false
} else {
window.scrollTo(0, next)
}
i++
}, 16.7)
},
easeInOutQuad(t, b, c, d) {
if ((t /= d / 2) < 1) return c / 2 * t * t + b
return -c / 2 * (--t * (t - 2) - 1) + b
}
}
}
</script>
<style scoped>
.back-to-ceiling {
position: fixed;
display: inline-block;
text-align: center;
cursor: pointer;
}
.back-to-ceiling:hover {
background: #d5dbe7;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity .5s;
}
.fade-enter,
.fade-leave-to {
opacity: 0
}
.back-to-ceiling .Icon {
fill: #9aaabf;
background: none;
}
</style>

@ -0,0 +1,82 @@
<template>
<el-breadcrumb class="app-breadcrumb" separator="/">
<transition-group name="breadcrumb">
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
<span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
</el-breadcrumb-item>
</transition-group>
</el-breadcrumb>
</template>
<script>
import pathToRegexp from 'path-to-regexp'
export default {
data() {
return {
levelList: null
}
},
watch: {
$route(route) {
// if you go to the redirect page, do not update the breadcrumbs
if (route.path.startsWith('/redirect/')) {
return
}
this.getBreadcrumb()
}
},
created() {
this.getBreadcrumb()
},
methods: {
getBreadcrumb() {
// only show routes with meta.title
let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
const first = matched[0]
if (!this.isDashboard(first)) {
matched = [{ path: '/dashboard', meta: { title: 'Dashboard' }}].concat(matched)
}
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
},
isDashboard(route) {
const name = route && route.name
if (!name) {
return false
}
return name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase()
},
pathCompile(path) {
// To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
const { params } = this.$route
var toPath = pathToRegexp.compile(path)
return toPath(params)
},
handleLink(item) {
const { redirect, path } = item
if (redirect) {
this.$router.push(redirect)
return
}
this.$router.push(this.pathCompile(path))
}
}
}
</script>
<style lang="scss" scoped>
.app-breadcrumb.el-breadcrumb {
display: inline-block;
font-size: 14px;
line-height: 50px;
margin-left: 8px;
.no-redirect {
color: #97a8be;
cursor: text;
}
}
</style>

@ -0,0 +1,155 @@
<template>
<div :id="id" :class="className" :style="{height:height,width:width}" />
</template>
<script>
import echarts from 'echarts'
import resize from './mixins/resize'
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
id: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '200px'
},
height: {
type: String,
default: '200px'
}
},
data() {
return {
chart: null
}
},
mounted() {
this.initChart()
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(document.getElementById(this.id))
const xAxisData = []
const data = []
const data2 = []
for (let i = 0; i < 50; i++) {
xAxisData.push(i)
data.push((Math.sin(i / 5) * (i / 5 - 10) + i / 6) * 5)
data2.push((Math.sin(i / 5) * (i / 5 + 10) + i / 6) * 3)
}
this.chart.setOption({
backgroundColor: '#08263a',
grid: {
left: '5%',
right: '5%'
},
xAxis: [{
show: false,
data: xAxisData
}, {
show: false,
data: xAxisData
}],
visualMap: {
show: false,
min: 0,
max: 50,
dimension: 0,
inRange: {
color: ['#4a657a', '#308e92', '#b1cfa5', '#f5d69f', '#f5898b', '#ef5055']
}
},
yAxis: {
axisLine: {
show: false
},
axisLabel: {
textStyle: {
color: '#4a657a'
}
},
splitLine: {
show: true,
lineStyle: {
color: '#08263f'
}
},
axisTick: {
show: false
}
},
series: [{
name: 'back',
type: 'bar',
data: data2,
z: 1,
itemStyle: {
normal: {
opacity: 0.4,
barBorderRadius: 5,
shadowBlur: 3,
shadowColor: '#111'
}
}
}, {
name: 'Simulate Shadow',
type: 'line',
data,
z: 2,
showSymbol: false,
animationDelay: 0,
animationEasing: 'linear',
animationDuration: 1200,
lineStyle: {
normal: {
color: 'transparent'
}
},
areaStyle: {
normal: {
color: '#08263a',
shadowBlur: 50,
shadowColor: '#000'
}
}
}, {
name: 'front',
type: 'bar',
data,
xAxisIndex: 1,
z: 3,
itemStyle: {
normal: {
barBorderRadius: 5
}
}
}],
animationEasing: 'elasticOut',
animationEasingUpdate: 'elasticOut',
animationDelay(idx) {
return idx * 20
},
animationDelayUpdate(idx) {
return idx * 20
}
})
}
}
}
</script>

@ -0,0 +1,227 @@
<template>
<div :id="id" :class="className" :style="{height:height,width:width}" />
</template>
<script>
import echarts from 'echarts'
import resize from './mixins/resize'
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
id: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '200px'
},
height: {
type: String,
default: '200px'
}
},
data() {
return {
chart: null
}
},
mounted() {
this.initChart()
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(document.getElementById(this.id))
this.chart.setOption({
backgroundColor: '#394056',
title: {
top: 20,
text: 'Requests',
textStyle: {
fontWeight: 'normal',
fontSize: 16,
color: '#F1F1F3'
},
left: '1%'
},
tooltip: {
trigger: 'axis',
axisPointer: {
lineStyle: {
color: '#57617B'
}
}
},
legend: {
top: 20,
icon: 'rect',
itemWidth: 14,
itemHeight: 5,
itemGap: 13,
data: ['CMCC', 'CTCC', 'CUCC'],
right: '4%',
textStyle: {
fontSize: 12,
color: '#F1F1F3'
}
},
grid: {
top: 100,
left: '2%',
right: '2%',
bottom: '2%',
containLabel: true
},
xAxis: [{
type: 'category',
boundaryGap: false,
axisLine: {
lineStyle: {
color: '#57617B'
}
},
data: ['13:00', '13:05', '13:10', '13:15', '13:20', '13:25', '13:30', '13:35', '13:40', '13:45', '13:50', '13:55']
}],
yAxis: [{
type: 'value',
name: '(%)',
axisTick: {
show: false
},
axisLine: {
lineStyle: {
color: '#57617B'
}
},
axisLabel: {
margin: 10,
textStyle: {
fontSize: 14
}
},
splitLine: {
lineStyle: {
color: '#57617B'
}
}
}],
series: [{
name: 'CMCC',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
lineStyle: {
normal: {
width: 1
}
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(137, 189, 27, 0.3)'
}, {
offset: 0.8,
color: 'rgba(137, 189, 27, 0)'
}], false),
shadowColor: 'rgba(0, 0, 0, 0.1)',
shadowBlur: 10
}
},
itemStyle: {
normal: {
color: 'rgb(137,189,27)',
borderColor: 'rgba(137,189,2,0.27)',
borderWidth: 12
}
},
data: [220, 182, 191, 134, 150, 120, 110, 125, 145, 122, 165, 122]
}, {
name: 'CTCC',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
lineStyle: {
normal: {
width: 1
}
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(0, 136, 212, 0.3)'
}, {
offset: 0.8,
color: 'rgba(0, 136, 212, 0)'
}], false),
shadowColor: 'rgba(0, 0, 0, 0.1)',
shadowBlur: 10
}
},
itemStyle: {
normal: {
color: 'rgb(0,136,212)',
borderColor: 'rgba(0,136,212,0.2)',
borderWidth: 12
}
},
data: [120, 110, 125, 145, 122, 165, 122, 220, 182, 191, 134, 150]
}, {
name: 'CUCC',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
lineStyle: {
normal: {
width: 1
}
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(219, 50, 51, 0.3)'
}, {
offset: 0.8,
color: 'rgba(219, 50, 51, 0)'
}], false),
shadowColor: 'rgba(0, 0, 0, 0.1)',
shadowBlur: 10
}
},
itemStyle: {
normal: {
color: 'rgb(219,50,51)',
borderColor: 'rgba(219,50,51,0.2)',
borderWidth: 12
}
},
data: [220, 182, 125, 145, 122, 191, 134, 150, 120, 110, 165, 122]
}]
})
}
}
}
</script>

@ -0,0 +1,271 @@
<template>
<div :id="id" :class="className" :style="{height:height,width:width}" />
</template>
<script>
import echarts from 'echarts'
import resize from './mixins/resize'
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
id: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '200px'
},
height: {
type: String,
default: '200px'
}
},
data() {
return {
chart: null
}
},
mounted() {
this.initChart()
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(document.getElementById(this.id))
const xData = (function() {
const data = []
for (let i = 1; i < 13; i++) {
data.push(i + 'month')
}
return data
}())
this.chart.setOption({
backgroundColor: '#344b58',
title: {
text: 'statistics',
x: '20',
top: '20',
textStyle: {
color: '#fff',
fontSize: '22'
},
subtextStyle: {
color: '#90979c',
fontSize: '16'
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
textStyle: {
color: '#fff'
}
}
},
grid: {
left: '5%',
right: '5%',
borderWidth: 0,
top: 150,
bottom: 95,
textStyle: {
color: '#fff'
}
},
legend: {
x: '5%',
top: '10%',
textStyle: {
color: '#90979c'
},
data: ['female', 'male', 'average']
},
calculable: true,
xAxis: [{
type: 'category',
axisLine: {
lineStyle: {
color: '#90979c'
}
},
splitLine: {
show: false
},
axisTick: {
show: false
},
splitArea: {
show: false
},
axisLabel: {
interval: 0
},
data: xData
}],
yAxis: [{
type: 'value',
splitLine: {
show: false
},
axisLine: {
lineStyle: {
color: '#90979c'
}
},
axisTick: {
show: false
},
axisLabel: {
interval: 0
},
splitArea: {
show: false
}
}],
dataZoom: [{
show: true,
height: 30,
xAxisIndex: [
0
],
bottom: 30,
start: 10,
end: 80,
handleIcon: 'path://M306.1,413c0,2.2-1.8,4-4,4h-59.8c-2.2,0-4-1.8-4-4V200.8c0-2.2,1.8-4,4-4h59.8c2.2,0,4,1.8,4,4V413z',
handleSize: '110%',
handleStyle: {
color: '#d3dee5'
},
textStyle: {
color: '#fff' },
borderColor: '#90979c'
}, {
type: 'inside',
show: true,
height: 15,
start: 1,
end: 35
}],
series: [{
name: 'female',
type: 'bar',
stack: 'total',
barMaxWidth: 35,
barGap: '10%',
itemStyle: {
normal: {
color: 'rgba(255,144,128,1)',
label: {
show: true,
textStyle: {
color: '#fff'
},
position: 'insideTop',
formatter(p) {
return p.value > 0 ? p.value : ''
}
}
}
},
data: [
709,
1917,
2455,
2610,
1719,
1433,
1544,
3285,
5208,
3372,
2484,
4078
]
},
{
name: 'male',
type: 'bar',
stack: 'total',
itemStyle: {
normal: {
color: 'rgba(0,191,183,1)',
barBorderRadius: 0,
label: {
show: true,
position: 'top',
formatter(p) {
return p.value > 0 ? p.value : ''
}
}
}
},
data: [
327,
1776,
507,
1200,
800,
482,
204,
1390,
1001,
951,
381,
220
]
}, {
name: 'average',
type: 'line',
stack: 'total',
symbolSize: 10,
symbol: 'circle',
itemStyle: {
normal: {
color: 'rgba(252,230,48,1)',
barBorderRadius: 0,
label: {
show: true,
position: 'top',
formatter(p) {
return p.value > 0 ? p.value : ''
}
}
}
},
data: [
1036,
3693,
2962,
3810,
2519,
1915,
1748,
4675,
6209,
4323,
2865,
4298
]
}
]
})
}
}
}
</script>

@ -0,0 +1,34 @@
import { debounce } from '@/utils'
export default {
data() {
return {
$_sidebarElm: null
}
},
mounted() {
this.__resizeHandler = debounce(() => {
if (this.chart) {
this.chart.resize()
}
}, 100)
window.addEventListener('resize', this.__resizeHandler)
this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
},
beforeDestroy() {
window.removeEventListener('resize', this.__resizeHandler)
this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
},
methods: {
// use $_ for mixins properties
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
$_sidebarResizeHandler(e) {
if (e.propertyName === 'width') {
this.__resizeHandler()
}
}
}
}

@ -0,0 +1,78 @@
<template>
<div v-if="errorLogs.length>0">
<el-badge :is-dot="true" style="line-height: 25px;margin-top: -5px;" @click.native="dialogTableVisible=true">
<el-button style="padding: 8px 10px;" size="small" type="danger">
<svg-icon icon-class="bug" />
</el-button>
</el-badge>
<el-dialog :visible.sync="dialogTableVisible" width="80%" append-to-body>
<div slot="title">
<span style="padding-right: 10px;">Error Log</span>
<el-button size="mini" type="primary" icon="el-icon-delete" @click="clearAll">Clear All</el-button>
</div>
<el-table :data="errorLogs" border>
<el-table-column label="Message">
<template slot-scope="{row}">
<div>
<span class="message-title">Msg:</span>
<el-tag type="danger">
{{ row.err.message }}
</el-tag>
</div>
<br>
<div>
<span class="message-title" style="padding-right: 10px;">Info: </span>
<el-tag type="warning">
{{ row.vm.$vnode.tag }} error in {{ row.info }}
</el-tag>
</div>
<br>
<div>
<span class="message-title" style="padding-right: 16px;">Url: </span>
<el-tag type="success">
{{ row.url }}
</el-tag>
</div>
</template>
</el-table-column>
<el-table-column label="Stack">
<template slot-scope="scope">
{{ scope.row.err.stack }}
</template>
</el-table-column>
</el-table>
</el-dialog>
</div>
</template>
<script>
export default {
name: 'ErrorLog',
data() {
return {
dialogTableVisible: false
}
},
computed: {
errorLogs() {
return this.$store.getters.errorLogs
}
},
methods: {
clearAll() {
this.dialogTableVisible = false
this.$store.dispatch('errorLog/clearErrorLog')
}
}
}
</script>
<style scoped>
.message-title {
font-size: 16px;
color: #333;
font-weight: bold;
padding-right: 8px;
}
</style>

@ -0,0 +1,54 @@
<template>
<a href="https://github.com/opengoofy/hippo4j" target="_blank" class="github-corner" aria-label="View source on Github">
<svg
width="80"
height="80"
viewBox="0 0 250 250"
style="fill:#40c9c6; color:#fff;"
aria-hidden="true"
>
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z" />
<path
d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
fill="currentColor"
style="transform-origin: 130px 106px;"
class="octo-arm"
/>
<path
d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
fill="currentColor"
class="octo-body"
/>
</svg>
</a>
</template>
<style scoped>
.github-corner:hover .octo-arm {
animation: octocat-wave 560ms ease-in-out
}
@keyframes octocat-wave {
0%,
100% {
transform: rotate(0)
}
20%,
60% {
transform: rotate(-25deg)
}
40%,
80% {
transform: rotate(10deg)
}
}
@media (max-width:500px) {
.github-corner:hover .octo-arm {
animation: none
}
.github-corner .octo-arm {
animation: octocat-wave 560ms ease-in-out
}
}
</style>

@ -0,0 +1,44 @@
<template>
<div style="padding: 0 15px;" @click="toggleClick">
<svg
:class="{'is-active':isActive}"
class="hamburger"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
width="64"
height="64"
>
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
</svg>
</div>
</template>
<script>
export default {
name: 'Hamburger',
props: {
isActive: {
type: Boolean,
default: false
}
},
methods: {
toggleClick() {
this.$emit('toggleClick')
}
}
}
</script>
<style scoped>
.hamburger {
display: inline-block;
vertical-align: middle;
width: 20px;
height: 20px;
}
.hamburger.is-active {
transform: rotate(180deg);
}
</style>

@ -0,0 +1,180 @@
<template>
<div :class="{'show':show}" class="header-search">
<svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
<el-select
ref="headerSearchSelect"
v-model="search"
:remote-method="querySearch"
filterable
default-first-option
remote
placeholder="Search"
class="header-search-select"
@change="change"
>
<el-option v-for="item in options" :key="item.path" :value="item" :label="item.title.join(' > ')" />
</el-select>
</div>
</template>
<script>
// fuse is a lightweight fuzzy-search module
// make search results more in line with expectations
import Fuse from 'fuse.js'
import path from 'path'
export default {
name: 'HeaderSearch',
data() {
return {
search: '',
options: [],
searchPool: [],
show: false,
fuse: undefined
}
},
computed: {
routes() {
return this.$store.getters.permission_routes
}
},
watch: {
routes() {
this.searchPool = this.generateRoutes(this.routes)
},
searchPool(list) {
this.initFuse(list)
},
show(value) {
if (value) {
document.body.addEventListener('click', this.close)
} else {
document.body.removeEventListener('click', this.close)
}
}
},
mounted() {
this.searchPool = this.generateRoutes(this.routes)
},
methods: {
click() {
this.show = !this.show
if (this.show) {
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus()
}
},
close() {
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur()
this.options = []
this.show = false
},
change(val) {
this.$router.push(val.path)
this.search = ''
this.options = []
this.$nextTick(() => {
this.show = false
})
},
initFuse(list) {
this.fuse = new Fuse(list, {
shouldSort: true,
threshold: 0.4,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: [{
name: 'title',
weight: 0.7
}, {
name: 'path',
weight: 0.3
}]
})
},
// Filter out the routes that can be displayed in the sidebar
// And generate the internationalized title
generateRoutes(routes, basePath = '/', prefixTitle = []) {
let res = []
for (const router of routes) {
// skip hidden router
if (router.hidden) { continue }
const data = {
path: path.resolve(basePath, router.path),
title: [...prefixTitle]
}
if (router.meta && router.meta.title) {
data.title = [...data.title, router.meta.title]
if (router.redirect !== 'noRedirect') {
// only push the routes with title
// special case: need to exclude parent router without redirect
res.push(data)
}
}
// recursive child routes
if (router.children) {
const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
if (tempRoutes.length >= 1) {
res = [...res, ...tempRoutes]
}
}
}
return res
},
querySearch(query) {
if (query !== '') {
this.options = this.fuse.search(query)
} else {
this.options = []
}
}
}
}
</script>
<style lang="scss" scoped>
.header-search {
font-size: 0 !important;
.search-icon {
cursor: pointer;
font-size: 18px;
vertical-align: middle;
}
.header-search-select {
font-size: 18px;
transition: width 0.2s;
width: 0;
overflow: hidden;
background: transparent;
border-radius: 0;
display: inline-block;
vertical-align: middle;
/deep/ .el-input__inner {
border-radius: 0;
border: 0;
padding-left: 0;
padding-right: 0;
box-shadow: none !important;
border-bottom: 1px solid #d9d9d9;
vertical-align: middle;
}
}
&.show {
.header-search-select {
width: 210px;
margin-left: 10px;
}
}
}
</style>

@ -0,0 +1,19 @@
/**
* database64文件格式转换为2进制
*
* @param {[String]} data dataURL 的格式为 data:image/png;base64,****,逗号之前都是一些说明性的文字我们只需要逗号之后的就行了
* @param {[String]} mime [description]
* @return {[blob]} [description]
*/
export default function(data, mime) {
data = data.split(',')[1]
data = window.atob(data)
var ia = new Uint8Array(data.length)
for (var i = 0; i < data.length; i++) {
ia[i] = data.charCodeAt(i)
}
// canvas.toDataURL 返回的默认格式就是 image/png
return new Blob([ia], {
type: mime
})
}

@ -0,0 +1,39 @@
/**
* 点击波纹效果
*
* @param {[event]} e [description]
* @param {[Object]} arg_opts [description]
* @return {[bollean]} [description]
*/
export default function(e, arg_opts) {
var opts = Object.assign({
ele: e.target, // 波纹作用元素
type: 'hit', // hit点击位置扩散center中心点扩展
bgc: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
}, arg_opts)
var target = opts.ele
if (target) {
var rect = target.getBoundingClientRect()
var ripple = target.querySelector('.e-ripple')
if (!ripple) {
ripple = document.createElement('span')
ripple.className = 'e-ripple'
ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
target.appendChild(ripple)
} else {
ripple.className = 'e-ripple'
}
switch (opts.type) {
case 'center':
ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px'
ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px'
break
default:
ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px'
ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px'
}
ripple.style.backgroundColor = opts.bgc
ripple.className = 'e-ripple z-active'
return false
}
}

@ -0,0 +1,232 @@
export default {
zh: {
hint: '点击,或拖动图片至此处',
loading: '正在上传……',
noSupported: '浏览器不支持该功能请使用IE10以上或其他现在浏览器',
success: '上传成功',
fail: '图片上传失败',
preview: '头像预览',
btn: {
off: '取消',
close: '关闭',
back: '上一步',
save: '保存'
},
error: {
onlyImg: '仅限图片格式',
outOfSize: '单文件大小不能超过 ',
lowestPx: '图片最低像素为(宽*高):'
}
},
'zh-tw': {
hint: '點擊,或拖動圖片至此處',
loading: '正在上傳……',
noSupported: '瀏覽器不支持該功能請使用IE10以上或其他現代瀏覽器',
success: '上傳成功',
fail: '圖片上傳失敗',
preview: '頭像預覽',
btn: {
off: '取消',
close: '關閉',
back: '上一步',
save: '保存'
},
error: {
onlyImg: '僅限圖片格式',
outOfSize: '單文件大小不能超過 ',
lowestPx: '圖片最低像素為(寬*高):'
}
},
en: {
hint: 'Click or drag the file here to upload',
loading: 'Uploading…',
noSupported: 'Browser is not supported, please use IE10+ or other browsers',
success: 'Upload success',
fail: 'Upload failed',
preview: 'Preview',
btn: {
off: 'Cancel',
close: 'Close',
back: 'Back',
save: 'Save'
},
error: {
onlyImg: 'Image only',
outOfSize: 'Image exceeds size limit: ',
lowestPx: 'Image\'s size is too low. Expected at least: '
}
},
ro: {
hint: 'Atinge sau trage fișierul aici',
loading: 'Se încarcă',
noSupported: 'Browser-ul tău nu suportă acest feature. Te rugăm încearcă cu alt browser.',
success: 'S-a încărcat cu succes',
fail: 'A apărut o problemă la încărcare',
preview: 'Previzualizează',
btn: {
off: 'Anulează',
close: 'Închide',
back: 'Înapoi',
save: 'Salvează'
},
error: {
onlyImg: 'Doar imagini',
outOfSize: 'Imaginea depășește limita de: ',
loewstPx: 'Imaginea este prea mică; Minim: '
}
},
ru: {
hint: 'Нажмите, или перетащите файл в это окно',
loading: 'Загружаю……',
noSupported: 'Ваш браузер не поддерживается, пожалуйста, используйте IE10 + или другие браузеры',
success: 'Загрузка выполнена успешно',
fail: 'Ошибка загрузки',
preview: 'Предпросмотр',
btn: {
off: 'Отменить',
close: 'Закрыть',
back: 'Назад',
save: 'Сохранить'
},
error: {
onlyImg: 'Только изображения',
outOfSize: 'Изображение превышает предельный размер: ',
lowestPx: 'Минимальный размер изображения: '
}
},
'pt-br': {
hint: 'Clique ou arraste o arquivo aqui para carregar',
loading: 'Carregando…',
noSupported: 'Browser não suportado, use o IE10+ ou outro browser',
success: 'Sucesso ao carregar imagem',
fail: 'Falha ao carregar imagem',
preview: 'Pré-visualizar',
btn: {
off: 'Cancelar',
close: 'Fechar',
back: 'Voltar',
save: 'Salvar'
},
error: {
onlyImg: 'Apenas imagens',
outOfSize: 'A imagem excede o limite de tamanho: ',
lowestPx: 'O tamanho da imagem é muito pequeno. Tamanho mínimo: '
}
},
fr: {
hint: 'Cliquez ou glissez le fichier ici.',
loading: 'Téléchargement…',
noSupported: 'Votre navigateur n\'est pas supporté. Utilisez IE10 + ou un autre navigateur s\'il vous plaît.',
success: 'Téléchargement réussit',
fail: 'Téléchargement echoué',
preview: 'Aperçu',
btn: {
off: 'Annuler',
close: 'Fermer',
back: 'Retour',
save: 'Enregistrer'
},
error: {
onlyImg: 'Image uniquement',
outOfSize: 'L\'image sélectionnée dépasse la taille maximum: ',
lowestPx: 'L\'image sélectionnée est trop petite. Dimensions attendues: '
}
},
nl: {
hint: 'Klik hier of sleep een afbeelding in dit vlak',
loading: 'Uploaden…',
noSupported: 'Je browser wordt helaas niet ondersteund. Gebruik IE10+ of een andere browser.',
success: 'Upload succesvol',
fail: 'Upload mislukt',
preview: 'Voorbeeld',
btn: {
off: 'Annuleren',
close: 'Sluiten',
back: 'Terug',
save: 'Opslaan'
},
error: {
onlyImg: 'Alleen afbeeldingen',
outOfSize: 'De afbeelding is groter dan: ',
lowestPx: 'De afbeelding is te klein! Minimale afmetingen: '
}
},
tr: {
hint: 'Tıkla veya yüklemek istediğini buraya sürükle',
loading: 'Yükleniyor…',
noSupported: 'Tarayıcı desteklenmiyor, lütfen IE10+ veya farklı tarayıcı kullanın',
success: 'Yükleme başarılı',
fail: 'Yüklemede hata oluştu',
preview: 'Önizle',
btn: {
off: 'İptal',
close: 'Kapat',
back: 'Geri',
save: 'Kaydet'
},
error: {
onlyImg: 'Sadece resim',
outOfSize: 'Resim yükleme limitini aşıyor: ',
lowestPx: 'Resmin boyutu çok küçük. En az olması gereken: '
}
},
'es-MX': {
hint: 'Selecciona o arrastra una imagen',
loading: 'Subiendo...',
noSupported: 'Tu navegador no es soportado, porfavor usa IE10+ u otros navegadores mas recientes',
success: 'Subido exitosamente',
fail: 'Sucedió un error',
preview: 'Vista previa',
btn: {
off: 'Cancelar',
close: 'Cerrar',
back: 'Atras',
save: 'Guardar'
},
error: {
onlyImg: 'Unicamente imagenes',
outOfSize: 'La imagen excede el tamaño maximo:',
lowestPx: 'La imagen es demasiado pequeño. Se espera por lo menos:'
}
},
de: {
hint: 'Klick hier oder zieh eine Datei hier rein zum Hochladen',
loading: 'Hochladen…',
noSupported: 'Browser wird nicht unterstützt, bitte verwende IE10+ oder andere Browser',
success: 'Upload erfolgreich',
fail: 'Upload fehlgeschlagen',
preview: 'Vorschau',
btn: {
off: 'Abbrechen',
close: 'Schließen',
back: 'Zurück',
save: 'Speichern'
},
error: {
onlyImg: 'Nur Bilder',
outOfSize: 'Das Bild ist zu groß: ',
lowestPx: 'Das Bild ist zu klein. Mindestens: '
}
},
ja: {
hint: 'クリック・ドラッグしてファイルをアップロード',
loading: 'アップロード中...',
noSupported: 'このブラウザは対応されていません。IE10+かその他の主要ブラウザをお使いください。',
success: 'アップロード成功',
fail: 'アップロード失敗',
preview: 'プレビュー',
btn: {
off: 'キャンセル',
close: '閉じる',
back: '戻る',
save: '保存'
},
error: {
onlyImg: '画像のみ',
outOfSize: '画像サイズが上限を超えています。上限: ',
lowestPx: '画像が小さすぎます。最小サイズ: '
}
}
}

@ -0,0 +1,7 @@
export default {
'jpg': 'image/jpeg',
'png': 'image/png',
'gif': 'image/gif',
'svg': 'image/svg+xml',
'psd': 'image/photoshop'
}

@ -0,0 +1,72 @@
<template>
<div class="json-editor">
<textarea ref="textarea" />
</div>
</template>
<script>
import CodeMirror from 'codemirror'
import 'codemirror/addon/lint/lint.css'
import 'codemirror/lib/codemirror.css'
import 'codemirror/theme/rubyblue.css'
require('script-loader!jsonlint')
import 'codemirror/mode/javascript/javascript'
import 'codemirror/addon/lint/lint'
import 'codemirror/addon/lint/json-lint'
export default {
name: 'JsonEditor',
/* eslint-disable vue/require-prop-types */
props: ['value'],
data() {
return {
jsonEditor: false
}
},
watch: {
value(value) {
const editorValue = this.jsonEditor.getValue()
if (value !== editorValue) {
this.jsonEditor.setValue(JSON.stringify(this.value, null, 2))
}
}
},
mounted() {
this.jsonEditor = CodeMirror.fromTextArea(this.$refs.textarea, {
lineNumbers: true,
mode: 'application/json',
gutters: ['CodeMirror-lint-markers'],
theme: 'rubyblue',
lint: true
})
this.jsonEditor.setValue(JSON.stringify(this.value, null, 2))
this.jsonEditor.on('change', cm => {
this.$emit('changed', cm.getValue())
this.$emit('input', cm.getValue())
})
},
methods: {
getValue() {
return this.jsonEditor.getValue()
}
}
}
</script>
<style scoped>
.json-editor{
height: 100%;
position: relative;
}
.json-editor >>> .CodeMirror {
height: auto;
min-height: 300px;
}
.json-editor >>> .CodeMirror-scroll{
min-height: 300px;
}
.json-editor >>> .cm-s-rubyblue span.cm-string {
color: #F08047;
}
</style>

@ -0,0 +1,102 @@
<template>
<div :class="{ hidden: hidden }" class="pagination-container">
<el-pagination
:background="background"
:current-page.sync="currentPage"
:page-size.sync="pageSize"
:layout="layout"
:page-sizes="pageSizes"
:total="total"
v-bind="$attrs"
:hide-on-single-page="true"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template>
<script>
import { scrollTo } from '@/utils/scroll-to';
export default {
name: 'Pagination',
props: {
total: {
required: true,
type: Number,
},
page: {
type: Number,
default: 1,
},
limit: {
type: Number,
default: 20,
},
pageSizes: {
type: Array,
default() {
return [10, 20, 30, 50];
},
},
layout: {
type: String,
default: 'total, sizes, prev, pager, next, jumper',
},
background: {
type: Boolean,
default: true,
},
autoScroll: {
type: Boolean,
default: true,
},
hidden: {
type: Boolean,
default: false,
},
},
computed: {
currentPage: {
get() {
return this.page;
},
set(val) {
this.$emit('update:page', val);
},
},
pageSize: {
get() {
return this.limit;
},
set(val) {
this.$emit('update:limit', val);
},
},
},
methods: {
handleSizeChange(val) {
this.$emit('pagination', { page: this.currentPage, limit: val });
if (this.autoScroll) {
scrollTo(0, 800);
}
},
handleCurrentChange(val) {
this.$emit('pagination', { page: val, limit: this.pageSize });
if (this.autoScroll) {
scrollTo(0, 800);
}
},
},
};
</script>
<style scoped>
.pagination-container {
background: #fff;
padding: 32px 16px;
}
.pagination-container.hidden {
display: none;
}
</style>

@ -0,0 +1,145 @@
<template>
<div ref="rightPanel" :class="{show:show}" class="rightPanel-container">
<div class="rightPanel-background" />
<div class="rightPanel" style="display: none">
<div class="handle-button" :style="{'top':buttonTop+'px','background-color':theme}" @click="show=!show">
<i :class="show?'el-icon-close':'el-icon-setting'" />
</div>
<div class="rightPanel-items">
<slot />
</div>
</div>
</div>
</template>
<script>
import { addClass, removeClass } from '@/utils'
export default {
name: 'RightPanel',
props: {
clickNotClose: {
default: false,
type: Boolean
},
buttonTop: {
default: 250,
type: Number
}
},
data() {
return {
show: false
}
},
computed: {
theme() {
return this.$store.state.settings.theme
}
},
watch: {
show(value) {
if (value && !this.clickNotClose) {
this.addEventClick()
}
if (value) {
addClass(document.body, 'showRightPanel')
} else {
removeClass(document.body, 'showRightPanel')
}
}
},
mounted() {
this.insertToBody()
},
beforeDestroy() {
const elx = this.$refs.rightPanel
elx.remove()
},
methods: {
addEventClick() {
window.addEventListener('click', this.closeSidebar)
},
closeSidebar(evt) {
const parent = evt.target.closest('.rightPanel')
if (!parent) {
this.show = false
window.removeEventListener('click', this.closeSidebar)
}
},
insertToBody() {
const elx = this.$refs.rightPanel
const body = document.querySelector('body')
body.insertBefore(elx, body.firstChild)
}
}
}
</script>
<style>
.showRightPanel {
overflow: hidden;
position: relative;
width: calc(100% - 15px);
}
</style>
<style lang="scss" scoped>
.rightPanel-background {
position: fixed;
top: 0;
left: 0;
opacity: 0;
transition: opacity .3s cubic-bezier(.7, .3, .1, 1);
background: rgba(0, 0, 0, .2);
z-index: -1;
}
.rightPanel {
width: 100%;
max-width: 260px;
height: 100vh;
position: fixed;
top: 0;
right: 0;
box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, .05);
transition: all .25s cubic-bezier(.7, .3, .1, 1);
transform: translate(100%);
background: #fff;
z-index: 40000;
}
.show {
transition: all .3s cubic-bezier(.7, .3, .1, 1);
.rightPanel-background {
z-index: 20000;
opacity: 1;
width: 100%;
height: 100%;
}
.rightPanel {
transform: translate(0);
}
}
.handle-button {
width: 48px;
height: 48px;
position: absolute;
left: -48px;
text-align: center;
font-size: 24px;
border-radius: 6px 0 0 6px !important;
z-index: 0;
pointer-events: auto;
cursor: pointer;
color: #fff;
line-height: 48px;
i {
font-size: 24px;
line-height: 48px;
}
}
</style>

@ -0,0 +1,60 @@
<template>
<div>
<svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" @click="click" />
</div>
</template>
<script>
import screenfull from 'screenfull'
export default {
name: 'Screenfull',
data() {
return {
isFullscreen: false
}
},
mounted() {
this.init()
},
beforeDestroy() {
this.destroy()
},
methods: {
click() {
if (!screenfull.enabled) {
this.$message({
message: 'you browser can not work',
type: 'warning'
})
return false
}
screenfull.toggle()
},
change() {
this.isFullscreen = screenfull.isFullscreen
},
init() {
if (screenfull.enabled) {
screenfull.on('change', this.change)
}
},
destroy() {
if (screenfull.enabled) {
screenfull.off('change', this.change)
}
}
}
}
</script>
<style scoped>
.screenfull-svg {
display: inline-block;
cursor: pointer;
fill: #5a5e66;;
width: 20px;
height: 20px;
vertical-align: 10px;
}
</style>

@ -0,0 +1,91 @@
<template>
<div :style="{height:height+'px',zIndex:zIndex}">
<div
:class="className"
:style="{top:(isSticky ? stickyTop +'px' : ''),zIndex:zIndex,position:position,width:width,height:height+'px'}"
>
<slot>
<div>sticky</div>
</slot>
</div>
</div>
</template>
<script>
export default {
name: 'Sticky',
props: {
stickyTop: {
type: Number,
default: 0
},
zIndex: {
type: Number,
default: 1
},
className: {
type: String,
default: ''
}
},
data() {
return {
active: false,
position: '',
width: undefined,
height: undefined,
isSticky: false
}
},
mounted() {
this.height = this.$el.getBoundingClientRect().height
window.addEventListener('scroll', this.handleScroll)
window.addEventListener('resize', this.handleResize)
},
activated() {
this.handleScroll()
},
destroyed() {
window.removeEventListener('scroll', this.handleScroll)
window.removeEventListener('resize', this.handleResize)
},
methods: {
sticky() {
if (this.active) {
return
}
this.position = 'fixed'
this.active = true
this.width = this.width + 'px'
this.isSticky = true
},
handleReset() {
if (!this.active) {
return
}
this.reset()
},
reset() {
this.position = ''
this.width = 'auto'
this.active = false
this.isSticky = false
},
handleScroll() {
const width = this.$el.getBoundingClientRect().width
this.width = width || 'auto'
const offsetTop = this.$el.getBoundingClientRect().top
if (offsetTop < this.stickyTop) {
this.sticky()
return
}
this.handleReset()
},
handleResize() {
if (this.isSticky) {
this.width = this.$el.getBoundingClientRect().width + 'px'
}
}
}
}
</script>

@ -0,0 +1,62 @@
<template>
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
<svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
<use :xlink:href="iconName" />
</svg>
</template>
<script>
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
import { isExternal } from '@/utils/validate'
export default {
name: 'SvgIcon',
props: {
iconClass: {
type: String,
required: true
},
className: {
type: String,
default: ''
}
},
computed: {
isExternal() {
return isExternal(this.iconClass)
},
iconName() {
return `#icon-${this.iconClass}`
},
svgClass() {
if (this.className) {
return 'svg-icon ' + this.className
} else {
return 'svg-icon'
}
},
styleExternalIcon() {
return {
mask: `url(${this.iconClass}) no-repeat 50% 50%`,
'-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
}
}
}
}
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
.svg-external-icon {
background-color: currentColor;
mask-size: cover!important;
display: inline-block;
}
</style>

@ -0,0 +1,49 @@
// Inspired by https://github.com/Inndy/vue-clipboard2
const Clipboard = require('clipboard')
if (!Clipboard) {
throw new Error('you should npm install `clipboard` --save at first ')
}
export default {
bind(el, binding) {
if (binding.arg === 'success') {
el._v_clipboard_success = binding.value
} else if (binding.arg === 'error') {
el._v_clipboard_error = binding.value
} else {
const clipboard = new Clipboard(el, {
text() { return binding.value },
action() { return binding.arg === 'cut' ? 'cut' : 'copy' }
})
clipboard.on('success', e => {
const callback = el._v_clipboard_success
callback && callback(e) // eslint-disable-line
})
clipboard.on('error', e => {
const callback = el._v_clipboard_error
callback && callback(e) // eslint-disable-line
})
el._v_clipboard = clipboard
}
},
update(el, binding) {
if (binding.arg === 'success') {
el._v_clipboard_success = binding.value
} else if (binding.arg === 'error') {
el._v_clipboard_error = binding.value
} else {
el._v_clipboard.text = function() { return binding.value }
el._v_clipboard.action = function() { return binding.arg === 'cut' ? 'cut' : 'copy' }
}
},
unbind(el, binding) {
if (binding.arg === 'success') {
delete el._v_clipboard_success
} else if (binding.arg === 'error') {
delete el._v_clipboard_error
} else {
el._v_clipboard.destroy()
delete el._v_clipboard
}
}
}

@ -0,0 +1,13 @@
import Clipboard from './clipboard'
const install = function(Vue) {
Vue.directive('Clipboard', Clipboard)
}
if (window.Vue) {
window.clipboard = Clipboard
Vue.use(install); // eslint-disable-line
}
Clipboard.install = install
export default Clipboard

@ -0,0 +1,77 @@
export default {
bind(el, binding, vnode) {
const dialogHeaderEl = el.querySelector('.el-dialog__header')
const dragDom = el.querySelector('.el-dialog')
dialogHeaderEl.style.cssText += ';cursor:move;'
dragDom.style.cssText += ';top:0px;'
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
const getStyle = (function() {
if (window.document.currentStyle) {
return (dom, attr) => dom.currentStyle[attr]
} else {
return (dom, attr) => getComputedStyle(dom, false)[attr]
}
})()
dialogHeaderEl.onmousedown = (e) => {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - dialogHeaderEl.offsetLeft
const disY = e.clientY - dialogHeaderEl.offsetTop
const dragDomWidth = dragDom.offsetWidth
const dragDomHeight = dragDom.offsetHeight
const screenWidth = document.body.clientWidth
const screenHeight = document.body.clientHeight
const minDragDomLeft = dragDom.offsetLeft
const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth
const minDragDomTop = dragDom.offsetTop
const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomHeight
// 获取到的值带px 正则匹配替换
let styL = getStyle(dragDom, 'left')
let styT = getStyle(dragDom, 'top')
if (styL.includes('%')) {
styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100)
styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100)
} else {
styL = +styL.replace(/\px/g, '')
styT = +styT.replace(/\px/g, '')
}
document.onmousemove = function(e) {
// 通过事件委托,计算移动的距离
let left = e.clientX - disX
let top = e.clientY - disY
// 边界处理
if (-(left) > minDragDomLeft) {
left = -minDragDomLeft
} else if (left > maxDragDomLeft) {
left = maxDragDomLeft
}
if (-(top) > minDragDomTop) {
top = -minDragDomTop
} else if (top > maxDragDomTop) {
top = maxDragDomTop
}
// 移动当前元素
dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`
// emit onDrag event
vnode.child.$emit('dragDialog')
}
document.onmouseup = function(e) {
document.onmousemove = null
document.onmouseup = null
}
}
}
}

@ -0,0 +1,13 @@
import drag from './drag'
const install = function(Vue) {
Vue.directive('el-drag-dialog', drag)
}
if (window.Vue) {
window['el-drag-dialog'] = drag
Vue.use(install); // eslint-disable-line
}
drag.install = install
export default drag

@ -0,0 +1,41 @@
import { addResizeListener, removeResizeListener } from 'element-ui/src/utils/resize-event'
/**
* How to use
* <el-table height="100px" v-el-height-adaptive-table="{bottomOffset: 30}">...</el-table>
* el-table height is must be set
* bottomOffset: 30(default) // The height of the table from the bottom of the page.
*/
const doResize = (el, binding, vnode) => {
const { componentInstance: $table } = vnode
const { value } = binding
if (!$table.height) {
throw new Error(`el-$table must set the height. Such as height='100px'`)
}
const bottomOffset = (value && value.bottomOffset) || 30
if (!$table) return
const height = window.innerHeight - el.getBoundingClientRect().top - bottomOffset
$table.layout.setHeight(height)
$table.doLayout()
}
export default {
bind(el, binding, vnode) {
el.resizeListener = () => {
doResize(el, binding, vnode)
}
// parameter 1 is must be "Element" type
addResizeListener(window.document.body, el.resizeListener)
},
inserted(el, binding, vnode) {
doResize(el, binding, vnode)
},
unbind(el) {
removeResizeListener(window.document.body, el.resizeListener)
}
}

@ -0,0 +1,13 @@
import adaptive from './adaptive'
const install = function(Vue) {
Vue.directive('el-height-adaptive-table', adaptive)
}
if (window.Vue) {
window['el-height-adaptive-table'] = adaptive
Vue.use(install); // eslint-disable-line
}
adaptive.install = install
export default adaptive

@ -0,0 +1,13 @@
import permission from './permission'
const install = function(Vue) {
Vue.directive('permission', permission)
}
if (window.Vue) {
window['permission'] = permission
Vue.use(install); // eslint-disable-line
}
permission.install = install
export default permission

@ -0,0 +1,22 @@
import store from '@/store'
export default {
inserted(el, binding, vnode) {
const { value } = binding
const roles = store.getters && store.getters.roles
if (value && value instanceof Array && value.length > 0) {
const permissionRoles = value
const hasPermission = roles.some(role => {
return permissionRoles.includes(role)
})
if (!hasPermission) {
el.parentNode && el.parentNode.removeChild(el)
}
} else {
throw new Error(`need roles! Like v-permission="['admin','editor']"`)
}
}
}

@ -0,0 +1,91 @@
const vueSticky = {}
let listenAction
vueSticky.install = Vue => {
Vue.directive('sticky', {
inserted(el, binding) {
const params = binding.value || {}
const stickyTop = params.stickyTop || 0
const zIndex = params.zIndex || 1000
const elStyle = el.style
elStyle.position = '-webkit-sticky'
elStyle.position = 'sticky'
// if the browser support css stickyCurrently Safari, Firefox and Chrome Canary
// if (~elStyle.position.indexOf('sticky')) {
// elStyle.top = `${stickyTop}px`;
// elStyle.zIndex = zIndex;
// return
// }
const elHeight = el.getBoundingClientRect().height
const elWidth = el.getBoundingClientRect().width
elStyle.cssText = `top: ${stickyTop}px; z-index: ${zIndex}`
const parentElm = el.parentNode || document.documentElement
const placeholder = document.createElement('div')
placeholder.style.display = 'none'
placeholder.style.width = `${elWidth}px`
placeholder.style.height = `${elHeight}px`
parentElm.insertBefore(placeholder, el)
let active = false
const getScroll = (target, top) => {
const prop = top ? 'pageYOffset' : 'pageXOffset'
const method = top ? 'scrollTop' : 'scrollLeft'
let ret = target[prop]
if (typeof ret !== 'number') {
ret = window.document.documentElement[method]
}
return ret
}
const sticky = () => {
if (active) {
return
}
if (!elStyle.height) {
elStyle.height = `${el.offsetHeight}px`
}
elStyle.position = 'fixed'
elStyle.width = `${elWidth}px`
placeholder.style.display = 'inline-block'
active = true
}
const reset = () => {
if (!active) {
return
}
elStyle.position = ''
placeholder.style.display = 'none'
active = false
}
const check = () => {
const scrollTop = getScroll(window, true)
const offsetTop = el.getBoundingClientRect().top
if (offsetTop < stickyTop) {
sticky()
} else {
if (scrollTop < elHeight + stickyTop) {
reset()
}
}
}
listenAction = () => {
check()
}
window.addEventListener('scroll', listenAction)
},
unbind() {
window.removeEventListener('scroll', listenAction)
}
})
}
export default vueSticky

@ -0,0 +1,13 @@
import waves from './waves'
const install = function(Vue) {
Vue.directive('waves', waves)
}
if (window.Vue) {
window.waves = waves
Vue.use(install) // eslint-disable-line
}
waves.install = install
export default waves

@ -0,0 +1,26 @@
.waves-ripple {
position: absolute;
border-radius: 100%;
background-color: rgba(0, 0, 0, 0.15);
background-clip: padding-box;
pointer-events: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-transform: scale(0);
-ms-transform: scale(0);
transform: scale(0);
opacity: 1;
}
.waves-ripple.z-active {
opacity: 0;
-webkit-transform: scale(2);
-ms-transform: scale(2);
transform: scale(2);
-webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
transition: opacity 1.2s ease-out, transform 0.6s ease-out;
transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out;
}

@ -0,0 +1,72 @@
import './waves.css'
const context = '@@wavesContext'
function handleClick(el, binding) {
function handle(e) {
const customOpts = Object.assign({}, binding.value)
const opts = Object.assign({
ele: el, // 波纹作用元素
type: 'hit', // hit 点击位置扩散 center中心点扩展
color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
},
customOpts
)
const target = opts.ele
if (target) {
target.style.position = 'relative'
target.style.overflow = 'hidden'
const rect = target.getBoundingClientRect()
let ripple = target.querySelector('.waves-ripple')
if (!ripple) {
ripple = document.createElement('span')
ripple.className = 'waves-ripple'
ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
target.appendChild(ripple)
} else {
ripple.className = 'waves-ripple'
}
switch (opts.type) {
case 'center':
ripple.style.top = rect.height / 2 - ripple.offsetHeight / 2 + 'px'
ripple.style.left = rect.width / 2 - ripple.offsetWidth / 2 + 'px'
break
default:
ripple.style.top =
(e.pageY - rect.top - ripple.offsetHeight / 2 - document.documentElement.scrollTop ||
document.body.scrollTop) + 'px'
ripple.style.left =
(e.pageX - rect.left - ripple.offsetWidth / 2 - document.documentElement.scrollLeft ||
document.body.scrollLeft) + 'px'
}
ripple.style.backgroundColor = opts.color
ripple.className = 'waves-ripple z-active'
return false
}
}
if (!el[context]) {
el[context] = {
removeHandle: handle
}
} else {
el[context].removeHandle = handle
}
return handle
}
export default {
bind(el, binding) {
el.addEventListener('click', handleClick(el, binding), false)
},
update(el, binding) {
el.removeEventListener('click', el[context].removeHandle, false)
el.addEventListener('click', handleClick(el, binding), false)
},
unbind(el) {
el.removeEventListener('click', el[context].removeHandle, false)
el[context] = null
delete el[context]
}
}

@ -0,0 +1,68 @@
// import parseTime, formatTime and set to filter
export { parseTime, formatTime } from '@/utils'
/**
* Show plural label if time is plural number
* @param {number} time
* @param {string} label
* @return {string}
*/
function pluralize(time, label) {
if (time === 1) {
return time + label
}
return time + label + 's'
}
/**
* @param {number} time
*/
export function timeAgo(time) {
const between = Date.now() / 1000 - Number(time)
if (between < 3600) {
return pluralize(~~(between / 60), ' minute')
} else if (between < 86400) {
return pluralize(~~(between / 3600), ' hour')
} else {
return pluralize(~~(between / 86400), ' day')
}
}
/**
* Number formatting
* like 10000 => 10k
* @param {number} num
* @param {number} digits
*/
export function numberFormatter(num, digits) {
const si = [
{ value: 1E18, symbol: 'E' },
{ value: 1E15, symbol: 'P' },
{ value: 1E12, symbol: 'T' },
{ value: 1E9, symbol: 'G' },
{ value: 1E6, symbol: 'M' },
{ value: 1E3, symbol: 'k' }
]
for (let i = 0; i < si.length; i++) {
if (num >= si[i].value) {
return (num / si[i].value + 0.1).toFixed(digits).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + si[i].symbol
}
}
return num.toString()
}
/**
* 10000 => "10,000"
* @param {number} num
*/
export function toThousandFilter(num) {
return (+num || 0).toString().replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ','))
}
/**
* Upper case first char
* @param {String} string
*/
export function uppercaseFirst(string) {
return string.charAt(0).toUpperCase() + string.slice(1)
}

@ -0,0 +1,9 @@
import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon'// svg component
// register globally
Vue.component('svg-icon', SvgIcon)
const req = require.context('./svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(req)

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M121.718 73.272v9.953c3.957-7.584 6.199-16.05 6.199-24.995C127.917 26.079 99.273 0 63.958 0 28.644 0 0 26.079 0 58.23c0 .403.028.806.028 1.21l22.97-25.953h13.34l-19.76 27.187h6.42V53.77l13.728-19.477v49.361H22.998V73.272H2.158c5.951 20.284 23.608 36.208 45.998 41.399-1.44 3.3-5.618 11.263-12.565 12.674-8.607 1.764 23.358.428 46.163-13.178 17.519-4.611 31.938-15.849 39.77-30.513h-13.506V73.272H85.02V59.464l22.998-25.977h13.008l-19.429 27.187h6.421v-7.433l13.727-19.402v39.433h-.027zm-78.24 2.822a10.516 10.516 0 0 1-.996-4.535V44.548c0-1.613.332-3.124.996-4.535a11.66 11.66 0 0 1 2.713-3.68c1.134-1.032 2.49-1.864 4.04-2.468 1.55-.605 3.21-.908 4.982-.908h11.292c1.77 0 3.431.303 4.981.908 1.522.604 2.85 1.41 3.986 2.418l-12.26 16.303v-2.898a1.96 1.96 0 0 0-.665-1.512c-.443-.403-.996-.604-1.66-.604-.665 0-1.218.201-1.661.604a1.96 1.96 0 0 0-.664 1.512v9.071L44.364 77.606a10.556 10.556 0 0 1-.886-1.512zm35.73-4.535c0 1.613-.332 3.124-.997 4.535a11.66 11.66 0 0 1-2.712 3.68c-1.134 1.032-2.49 1.864-4.04 2.469-1.55.604-3.21.907-4.982.907H55.185c-1.77 0-3.431-.303-4.981-.907-1.55-.605-2.906-1.437-4.041-2.47a12.49 12.49 0 0 1-1.384-1.512l13.727-18.217v6.375c0 .605.222 1.109.665 1.512.442.403.996.604 1.66.604.664 0 1.218-.201 1.66-.604a1.96 1.96 0 0 0 .665-1.512V53.87L75.97 36.838c.913.932 1.66 1.99 2.214 3.175.664 1.41.996 2.922.996 4.535v27.011h.028z"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1665307144705" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4267" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M575.764966 895.884854H223.765304A95.805493 95.805493 0 0 1 127.880338 799.999887V224.000113c0-25.648316 9.930595-49.808308 28.061426-67.942751s42.182449-28.177024 67.82354-28.177024h575.999775A96.202861 96.202861 0 0 1 895.884854 224.000113v351.999661a31.970084 31.970084 0 1 0 63.940168 0V224.000113A160.031044 160.031044 0 0 0 799.765079 63.940169H223.765304A159.702312 159.702312 0 0 0 63.940169 224.000113v575.999774A159.445829 159.445829 0 0 0 223.765304 959.825022h351.999662a31.970084 31.970084 0 1 0 0-63.940168z" fill="" p-id="4268"></path><path d="M925.376805 758.207581l-83.584612-83.584612a118.27125 118.27125 0 0 0-141.96885-19.221787 32.150706 32.150706 0 0 0-3.912271-4.750357L650.239007 604.975147a254.890078 254.890078 0 0 0 53.767541-156.978534c0-141.383635-114.615462-255.999097-255.999097-255.999097S192.001129 306.612979 192.001129 448.000226s114.615462 255.999097 255.999097 255.999097A254.890078 254.890078 0 0 0 604.975147 650.239007l45.675678 45.675677a32.150706 32.150706 0 0 0 4.750357 3.912272c-25.648316 45.108525-19.250687 103.499988 19.221787 141.968849l83.584612 83.584612a118.206227 118.206227 0 0 0 167.169224 0c46.163357-46.166969 46.163357-121.013092 0-167.172836zM522.719913 624.951934a191.66156 191.66156 0 0 1-182.019961-17.700951 192.745291 192.745291 0 0 1-69.633372-84.53107 191.66156 191.66156 0 0 1 17.70095-182.019961 192.745291 192.745291 0 0 1 84.531071-69.633372 191.66156 191.66156 0 0 1 182.01996 17.70095 192.745291 192.745291 0 0 1 69.633373 84.531071 191.66156 191.66156 0 0 1-17.700951 182.01996A192.745291 192.745291 0 0 1 522.719913 624.951934z m357.407482 255.186298a54.208259 54.208259 0 0 1-76.659567 0L719.875992 796.542783A54.208259 54.208259 0 0 1 796.542783 719.875992l83.584612 83.584612a54.208259 54.208259 0 0 1-0.007225 76.659566z" fill="" p-id="4269"></path></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

@ -0,0 +1,2 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1653104552747" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16631" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
</style></defs><path d="M924.8 385.6c-22.6-53.4-54.9-101.3-96-142.4-41.1-41.1-89-73.4-142.4-96C631.1 123.8 572.5 112 512 112s-119.1 11.8-174.4 35.2c-53.4 22.6-101.3 54.9-142.4 96-41.1 41.1-73.4 89-96 142.4C75.8 440.9 64 499.5 64 560c0 132.7 58.3 257.7 159.9 343.1l1.7 1.4c5.8 4.8 13.1 7.5 20.6 7.5h531.7c7.5 0 14.8-2.7 20.6-7.5l1.7-1.4C901.7 817.7 960 692.7 960 560c0-60.5-11.9-119.1-35.2-174.4zM761.4 836H262.6C184.5 765.5 140 665.6 140 560c0-99.4 38.7-192.8 109-263 70.3-70.3 163.7-109 263-109 99.4 0 192.8 38.7 263 109 70.3 70.3 109 163.7 109 263 0 105.6-44.5 205.5-122.6 276z" p-id="16632"></path><path d="M623.5 421.5c-3.1-3.1-8.2-3.1-11.3 0L527.7 506c-18.7-5-39.4-0.2-54.1 14.5-21.9 21.9-21.9 57.3 0 79.2 21.9 21.9 57.3 21.9 79.2 0 14.7-14.7 19.5-35.4 14.5-54.1l84.5-84.5c3.1-3.1 3.1-8.2 0-11.3l-28.3-28.3zM490 320h44c4.4 0 8-3.6 8-8v-80c0-4.4-3.6-8-8-8h-44c-4.4 0-8 3.6-8 8v80c0 4.4 3.6 8 8 8z m260 218v44c0 4.4 3.6 8 8 8h80c4.4 0 8-3.6 8-8v-44c0-4.4-3.6-8-8-8h-80c-4.4 0-8 3.6-8 8z m12.7-197.2l-31.1-31.1c-3.1-3.1-8.2-3.1-11.3 0l-56.6 56.6c-3.1 3.1-3.1 8.2 0 11.3l31.1 31.1c3.1 3.1 8.2 3.1 11.3 0l56.6-56.6c3.1-3.1 3.1-8.2 0-11.3z m-458.6-31.1c-3.1-3.1-8.2-3.1-11.3 0l-31.1 31.1c-3.1 3.1-3.1 8.2 0 11.3l56.6 56.6c3.1 3.1 8.2 3.1 11.3 0l31.1-31.1c3.1-3.1 3.1-8.2 0-11.3l-56.6-56.6zM262 530h-80c-4.4 0-8 3.6-8 8v44c0 4.4 3.6 8 8 8h80c4.4 0 8-3.6 8-8v-44c0-4.4-3.6-8-8-8z" p-id="16633"></path></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

@ -0,0 +1,2 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1653104348939" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10844" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
</style></defs><path d="M862.4 250.8L562.6 77.7c-31.2-18-70-18-101.1 0L161.6 250.8c-31.2 18-50.6 51.6-50.6 87.6v346.2c0 36 19.4 69.6 50.6 87.6l299.8 173.1c15.6 9 33.1 13.5 50.6 13.5s35-4.5 50.6-13.5l299.8-173.1c31.2-18 50.6-51.6 50.6-87.6V338.4c0-36-19.4-69.6-50.6-87.6zM843 684.6c0 11.1-6 21.4-15.6 27L527.6 884.7c-9.6 5.5-21.5 5.5-31.1 0L196.6 711.6c-9.6-5.5-15.6-15.9-15.6-27V338.4c0-11.1 6-21.4 15.6-27l299.8-173.1c4.8-2.8 10.2-4.2 15.6-4.2s10.8 1.4 15.6 4.2l299.8 173.1c9.6 5.5 15.6 15.9 15.6 27v346.2z" p-id="10845"></path><path d="M409.5 566H408c-19.1 0-34.7 15.5-34.7 34.7v52.8c0 19.1 15.5 34.7 34.7 34.7h1.5c19.1 0 34.7-15.5 34.7-34.7v-52.8c0-19.2-15.5-34.7-34.7-34.7zM511.9 407.1h-1.5c-19.1 0-34.7 15.5-34.7 34.7v211.7c0 19.1 15.5 34.7 34.7 34.7h1.5c19.1 0 34.7-15.5 34.7-34.7V441.8c0-19.2-15.6-34.7-34.7-34.7zM614.2 485.3h-1.5c-19.1 0-34.7 15.5-34.7 34.7v133.6c0 19.1 15.5 34.7 34.7 34.7h1.5c19.1 0 34.7-15.5 34.7-34.7V519.9c0-19.1-15.5-34.6-34.7-34.6z" p-id="10846"></path></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1639799836562" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2215" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M487.112351 943.649605c0 21.881659-17.90207 39.783729-39.783729 39.783729H182.339049c-21.881659 0-39.783729-17.90207-39.783729-39.783729V80.350395c0-21.881659 17.90207-39.783729 39.783729-39.783729H447.328622c21.881659 0 39.783729 17.90207 39.783729 39.783729v863.29921z" fill="#ADD8FF" p-id="2216"></path><path d="M314.833835 790.482046m-65.640921 0a65.640922 65.640922 0 1 0 131.281843 0 65.640922 65.640922 0 1 0-131.281843 0Z" fill="#F0F0FF" p-id="2217"></path><path d="M314.833835 155.500143v63.653155M314.833835 282.806453v334.180078" fill="#F0F0FF" p-id="2218"></path><path d="M466.829018 943.649605a19.524736 19.524736 0 0 1-19.500396 19.500397H182.339049a19.524736 19.524736 0 0 1-19.500397-19.500397V80.350395A19.520679 19.520679 0 0 1 182.339049 60.849998H447.328622a19.524736 19.524736 0 0 1 19.500396 19.500397v863.29921z m40.562609 0V80.350395C507.391627 47.231769 480.447247 20.283333 447.328622 20.283333H182.339049C149.220423 20.283333 122.276043 47.231769 122.276043 80.350395v863.29921c0 33.118626 26.944379 60.067062 60.067062 60.067062h264.989573c33.118626 0 60.063005-26.948436 60.058949-60.067062z" fill="#6E6E96" p-id="2219"></path><path d="M888.72234 939.592939c0 21.881659-17.90207 39.783729-39.783729 39.783729h-264.989573c-21.881659 0-39.783729-17.90207-39.783729-39.783729V76.293728c0-21.881659 17.90207-39.783729 39.783729-39.783729h264.985517c21.881659 0 39.783729 17.90207 39.783729 39.783729l0.004056 863.299211z" fill="#FF9C9C" p-id="2220"></path><path d="M716.443825 786.42538m-65.640922 0a65.640922 65.640922 0 1 0 131.281843 0 65.640922 65.640922 0 1 0-131.281843 0Z" fill="#F0F0FF" p-id="2221"></path><path d="M716.443825 151.443476v63.653155M716.443825 278.749786v334.180078" fill="#F0F0FF" p-id="2222"></path><path d="M868.439007 939.592939a19.524736 19.524736 0 0 1-19.500396 19.500396h-264.989573a19.524736 19.524736 0 0 1-19.500396-19.500396V76.293728A19.520679 19.520679 0 0 1 583.949038 56.793332h264.985517a19.524736 19.524736 0 0 1 19.500396 19.500396l0.004056 863.299211z m40.562609 0V76.293728C909.001616 43.175102 882.061294 16.226666 848.938611 16.226666h-264.985516c-33.118626 0-60.067062 26.948436-60.067062 60.067062v863.299211c0 33.118626 26.948436 60.067062 60.067062 60.067062h264.989573c33.118626 0 60.063005-26.948436 60.058948-60.067062z" fill="#6E6E96" p-id="2223"></path></svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1584161793108" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11842" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M232 152h80v80h-80v200a80 80 0 0 1-80 80 80 80 0 0 1 80 80v200h80v80h-80c-42.816-10.784-80-36-80-80v-160a80 80 0 0 0-80-80H32v-80h40a80 80 0 0 0 80-80v-160a80 80 0 0 1 80-80m560 0a80 80 0 0 1 80 80v160a80 80 0 0 0 80 80H992v80h-40a80 80 0 0 0-80 80v160a80 80 0 0 1-80 80h-80v-80h80V592a80 80 0 0 1 80-80 80 80 0 0 1-80-80V232h-80v-80h80m-280 480a40 40 0 0 1 0 80 40 40 0 0 1 0-80m-160 0a40 40 0 0 1 0 80 40 40 0 0 1 0-80m320 0a40 40 0 0 1 0 80 40 40 0 0 1 0-80z" p-id="11843" fill="#e6e6e6"></path></svg>

After

Width:  |  Height:  |  Size: 882 B

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M84.742 36.8c2.398 7.2 5.595 12.8 11.19 18.4 4.795-4.8 7.992-11.2 10.39-18.4h-21.58zm-52.748 40h20.78l-10.39-28-10.39 28z"/><path d="M111.916 0H16.009C7.218 0 .025 7.2.025 16v96c0 8.8 7.193 16 15.984 16h95.907c8.791 0 15.984-7.2 15.984-16V16c0-8.8-6.394-16-15.984-16zM72.754 103.2c-1.598 1.6-3.197 1.6-4.795 1.6-.8 0-2.398 0-3.197-.8-.8-.8-1.599 0-1.599-.8s-.799-1.6-1.598-3.2c-.8-1.6-.8-2.4-1.599-4l-3.196-8.8H28.797L25.6 96c-1.598 3.2-2.398 5.6-3.197 7.2-.8 1.6-2.398 1.6-4.795 1.6-1.599 0-3.197-.8-4.796-1.6-1.598-1.6-2.397-2.4-2.397-4 0-.8 0-1.6.799-3.2.8-1.6.8-2.4 1.598-4l17.583-44.8c.8-1.6.8-3.2 1.599-4.8.799-1.6 1.598-3.2 2.397-4 .8-.8 1.599-2.4 3.197-3.2 1.599-.8 3.197-.8 4.796-.8 1.598 0 3.196 0 4.795.8 1.598.8 2.398 1.6 3.197 3.2.799.8 1.598 2.4 2.397 4 .8 1.6 1.599 3.2 2.398 5.6l17.583 44c1.598 3.2 2.398 5.6 2.398 7.2-.8.8-1.599 2.4-2.398 4zM116.711 72c-8.791-3.2-15.185-7.2-20.78-12-5.594 5.6-12.787 9.6-21.579 12l-2.397-4c8.791-2.4 15.984-5.6 21.579-11.2C87.939 51.2 83.144 44 81.545 36h-7.992v-3.2h21.58c-1.6-2.4-3.198-5.6-4.796-8l2.397-.8c1.599 2.4 3.997 5.6 5.595 8.8h19.98v4h-7.992c-2.397 8-6.393 15.2-11.189 20 5.595 4.8 11.988 8.8 20.78 11.2l-3.197 4z"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1634054280919" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4073" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M412.16 572.928c-139.264 0-252.928-113.664-252.928-252.928s113.664-252.928 252.928-252.928 252.928 113.664 252.928 252.928-113.664 252.928-252.928 252.928z m0-454.656c-111.104 0-201.728 90.624-201.728 201.728s90.624 201.728 201.728 201.728 201.728-90.624 201.728-201.728-90.624-201.728-201.728-201.728z" p-id="4074"></path><path d="M818.688 974.336c-14.336 0-25.6-11.264-25.6-25.6 0-201.728-163.84-365.568-365.568-365.568s-365.568 163.84-365.568 365.568c0 14.336-11.264 25.6-25.6 25.6s-25.6-11.264-25.6-25.6c0-229.888 186.88-416.768 416.768-416.768 229.888 0 416.768 186.88 416.768 416.768 0 14.336-11.264 25.6-25.6 25.6z" p-id="4075"></path><path d="M653.312 475.136h-25.6v-51.2h25.6c90.112 0 163.328-73.216 163.328-163.328S743.424 97.28 653.312 97.28c-37.376 0-72.704 12.288-101.888 35.328l-19.968 15.872-31.744-39.936 19.968-15.872C558.08 61.952 604.16 46.08 653.312 46.08c118.272 0 214.528 96.256 214.528 214.528s-96.256 214.528-214.528 214.528z" p-id="4076"></path><path d="M989.696 799.744c-14.336 0-25.6-11.264-25.6-25.6 0-164.352-134.144-298.496-298.496-298.496-14.336 0-25.6-11.264-25.6-25.6s11.264-25.6 25.6-25.6c193.024 0 349.696 156.672 349.696 349.696 0 14.336-11.264 25.6-25.6 25.6z" p-id="4077"></path></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

@ -0,0 +1,2 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1653104641144" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="17024" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
</style></defs><path d="M389.0176 634.88c8.4992 8.3968 22.3232 8.3968 30.72 0L634.88 419.84c8.4992-8.3968 8.4992-22.3232 0-30.72-8.4992-8.3968-22.3232-8.3968-30.72 0L389.0176 604.16C380.6208 612.6592 380.6208 626.4832 389.0176 634.88z" p-id="17025"></path><path d="M934.6048 243.0976 780.9024 89.3952c-33.8944-33.8944-88.9856-33.8944-122.9824 0L473.6 273.8176c-33.8944 33.8944-33.8944 88.9856 0 122.9824l30.72 30.72 30.72-30.72-30.72-30.72c-16.896-16.896-16.896-44.544 0-61.44l184.4224-184.4224c16.896-16.9984 44.544-16.9984 61.44 0l153.7024 153.7024c16.896 16.896 16.896 44.544 0 61.44L719.4624 519.68c-16.896 16.896-44.544 16.896-61.44 0l-30.72-30.72-30.72 30.72 30.72 30.72c33.8944 33.8944 88.9856 33.8944 122.9824 0l184.4224-184.4224C968.4992 332.0832 968.4992 276.992 934.6048 243.0976z" p-id="17026"></path><path d="M519.68 596.48l-30.72 30.72 30.72 30.72c16.896 16.896 16.896 44.544 0 61.44L335.2576 903.8848c-16.896 16.896-44.544 16.896-61.44 0L120.1152 750.1824c-16.896-16.9984-16.896-44.544 0-61.44l184.4224-184.4224c16.896-16.896 44.544-16.896 61.44 0l30.72 30.72 30.72-30.72-30.72-30.72c-33.8944-33.8944-88.9856-33.8944-122.9824 0L89.3952 658.0224c-33.8944 33.8944-33.8944 88.9856 0 122.88l153.7024 153.7024c33.8944 33.8944 88.9856 33.8944 122.88 0l184.4224-184.4224c33.8944-33.8944 33.8944-88.9856 0-122.9824L519.68 596.48z" p-id="17027"></path></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

@ -0,0 +1,2 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1653104502742" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15116" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
</style></defs><path d="M856.44 195.75H691.38v-78.64h-59.24v78.64H412.52v-78.64h-59.25v78.64H188.21a31 31 0 0 0-31 31v649a31 31 0 0 0 31 31h668.23a31 31 0 0 0 31-31v-649a31 31 0 0 0-31-31zM828.2 847.52H216.45V255h136.82v42.55h59.24V255h219.63v42.55h59.24V255H828.2z" p-id="15117"></path><path d="M319.02 445.08h406.62v59.24H319.02zM319.02 632.08h406.62v59.24H319.02z" p-id="15118"></path></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -0,0 +1,2 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1658706873562" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5659" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
</style></defs><path d="M512.3 920.64c-8.32 0-16.71-1.12-24.99-3.37l-6.12-2.36-349.81-176.58c-40.06-12.61-67.73-50.63-67.73-93.73V379.38c0-43.08 27.67-81.1 67.73-93.71l355.94-178.95c28.6-7.77 58.57-1.92 82.28 16.2 24.49 18.69 38.54 47.33 38.54 78.55v621.05c0 31.22-14.05 59.86-38.53 78.56-16.85 12.85-36.87 19.56-57.31 19.56z m-5.11-65.85c10.67 1.88 18.73-2.63 22.73-5.68 8.16-6.23 12.83-15.91 12.83-26.59V201.47c0-10.68-4.68-20.37-12.83-26.59-4.01-3.06-12.11-7.6-22.73-5.68L152.1 347.7c-13.58 3.72-23.07 16.74-23.07 31.68V644.6c0 14.94 9.48 27.97 23.06 31.67l6.13 2.36 348.97 176.16zM809.98 776.53c-9.67 0-19.25-4.26-25.7-12.45-11.17-14.19-8.74-34.73 5.44-45.91 66.9-52.74 105.26-131.56 105.26-216.27 0-84.73-38.36-163.55-105.25-216.25-14.18-11.17-16.62-31.73-5.44-45.92 11.17-14.14 31.72-16.62 45.91-5.44 82.72 65.19 130.17 162.73 130.17 267.62 0 104.87-47.45 202.4-130.16 267.6-6.02 4.72-13.15 7.02-20.23 7.02z" p-id="5660"></path></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

@ -0,0 +1,2 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1653104132734" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3670" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
</style></defs><path d="M512 627.2c-64 0-115.2-51.2-115.2-115.2s51.2-115.2 115.2-115.2 115.2 51.2 115.2 115.2S576 627.2 512 627.2zM512 448c-35.84 0-64 28.16-64 64s28.16 64 64 64 64-28.16 64-64S547.84 448 512 448z" p-id="3671"></path><path d="M153.6 627.2c-64 0-115.2-51.2-115.2-115.2s51.2-115.2 115.2-115.2 115.2 51.2 115.2 115.2S215.04 627.2 153.6 627.2zM153.6 448c-35.84 0-64 28.16-64 64s28.16 64 64 64 64-28.16 64-64S186.88 448 153.6 448z" p-id="3672"></path><path d="M870.4 627.2c-64 0-115.2-51.2-115.2-115.2s51.2-115.2 115.2-115.2 115.2 51.2 115.2 115.2S934.4 627.2 870.4 627.2zM870.4 448c-35.84 0-64 28.16-64 64s28.16 64 64 64 64-28.16 64-64S906.24 448 870.4 448z" p-id="3673"></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1,2 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1653104055538" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5254" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
</style></defs><path d="M834.1 469.2A347.49 347.49 0 0 0 751.2 354l-29.1-26.7a8.09 8.09 0 0 0-13 3.3l-13 37.3c-8.1 23.4-23 47.3-44.1 70.8-1.4 1.5-3 1.9-4.1 2-1.1 0.1-2.8-0.1-4.3-1.5-1.4-1.2-2.1-3-2-4.8 3.7-60.2-14.3-128.1-53.7-202C555.3 171 510 123.1 453.4 89.7l-41.3-24.3c-5.4-3.2-12.3 1-12 7.3l2.2 48c1.5 32.8-2.3 61.8-11.3 85.9-11 29.5-26.8 56.9-47 81.5a295.64 295.64 0 0 1-47.5 46.1 352.6 352.6 0 0 0-100.3 121.5A347.75 347.75 0 0 0 160 610c0 47.2 9.3 92.9 27.7 136a349.4 349.4 0 0 0 75.5 110.9c32.4 32 70 57.2 111.9 74.7C418.5 949.8 464.5 959 512 959s93.5-9.2 136.9-27.3A348.6 348.6 0 0 0 760.8 857c32.4-32 57.8-69.4 75.5-110.9a344.2 344.2 0 0 0 27.7-136c0-48.8-10-96.2-29.9-140.9zM713 808.5c-53.7 53.2-125 82.4-201 82.4s-147.3-29.2-201-82.4c-53.5-53.1-83-123.5-83-198.4 0-43.5 9.8-85.2 29.1-124 18.8-37.9 46.8-71.8 80.8-97.9a349.6 349.6 0 0 0 58.6-56.8c25-30.5 44.6-64.5 58.2-101a240 240 0 0 0 12.1-46.5c24.1 22.2 44.3 49 61.2 80.4 33.4 62.6 48.8 118.3 45.8 165.7a74.01 74.01 0 0 0 24.4 59.8 73.36 73.36 0 0 0 53.4 18.8c19.7-1 37.8-9.7 51-24.4 13.3-14.9 24.8-30.1 34.4-45.6 14 17.9 25.7 37.4 35 58.4 15.9 35.8 24 73.9 24 113.1 0 74.9-29.5 145.4-83 198.4z" p-id="5255"></path></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1639799706460" class="icon" viewBox="0 0 1331 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1902" xmlns:xlink="http://www.w3.org/1999/xlink" width="166.375" height="128"><defs><style type="text/css"></style></defs><path d="M134.295082 514.797814l-78.338798 453.245902h559.562842L520.393443 514.797814H134.295082z m1045.794973 0h-386.098361l-78.338798 453.245902h559.562842l-95.125683-453.245902z m-330.142077-458.84153h-386.098361l-78.338797 453.245902h559.562841l-95.125683-453.245902z" fill="#FFD75F" p-id="1903"></path><path d="M435.239169 500.842317l78.685727 374.907104H46.242273l-13.541421 78.338798h559.562842l-95.125683-453.245902H435.239169z m-1.169486-5.595628h487.742951l-95.125683-453.245902h-61.898842l78.685727 374.907104-414.5913 5.595628h-54.059367L385.51082 481.224044l48.558863 14.022645z m722.76494 5.595628h-40.792131l57.579016 374.907104H705.944481l-13.547017 78.338798h559.562842l-95.125683-453.245902z" fill="#F0C237" p-id="1904"></path><path d="M418.737661 481.224044l123.747323-335.737705 284.744743-61.551913h-339.822514zM89.530055 934.469945l123.747322-335.737705 284.750339-61.551912H158.199607zM746.076328 934.469945l123.752918-335.737705 284.744743-61.551912h-339.822514z" fill="#FFFFFF" opacity=".64" p-id="1905"></path><path d="M55.956284 996.021858h559.562842a27.983738 27.983738 0 0 0 27.385005-33.730448l-95.125683-453.245902A27.978142 27.978142 0 0 0 520.393443 486.819672H134.295082a27.966951 27.966951 0 0 0-27.569661 23.210667l-78.338798 453.245901a27.95576 27.95576 0 0 0 6.166382 22.785399A27.950164 27.950164 0 0 0 55.956284 996.021858z m78.338798-453.245902h386.098361a27.994929 27.994929 0 0 1-27.390601-22.231431l95.125683 453.245901a27.989333 27.989333 0 0 1 27.390601-33.736043H55.956284c8.253552 0 16.087432 3.642754 21.403279 9.949027a27.994929 27.994929 0 0 1 6.166382 22.785399l78.338798-453.245902A27.978142 27.978142 0 0 1 134.295082 542.775956zM715.652896 996.021858h559.562842a28.000525 28.000525 0 0 0 27.390601-33.730448l-95.125683-453.245902A28.000525 28.000525 0 0 0 1180.090055 486.819672h-386.098361a27.978142 27.978142 0 0 0-27.569661 23.210667l-78.338798 453.245901a27.994929 27.994929 0 0 0 27.569661 32.745618z m78.338798-453.245902h386.098361a27.989333 27.989333 0 0 1-27.385006-22.231431l95.125683 453.245901a27.978142 27.978142 0 0 1 27.385006-33.736043h-559.562842c8.259148 0 16.087432 3.642754 21.403279 9.949027a27.994929 27.994929 0 0 1 6.166382 22.785399l78.338798-453.245902A27.983738 27.983738 0 0 1 793.991694 542.775956z" fill="#6E6E96" p-id="1906"></path><path d="M385.51082 537.180328h559.562841a27.994929 27.994929 0 0 0 27.390601-33.724853l-95.125683-453.245901A28.000525 28.000525 0 0 0 849.947978 27.978142h-386.098361a27.978142 27.978142 0 0 0-27.569661 23.210667l-78.338798 453.245901A27.966951 27.966951 0 0 0 385.51082 537.180328z m78.338797-453.245902h386.098361a27.989333 27.989333 0 0 1-27.385005-22.231431l95.125683 453.245901a28.000525 28.000525 0 0 1 27.385005-33.730448h-559.562841a27.961355 27.961355 0 0 1 27.569661 32.745618l78.338798-453.245902A27.983738 27.983738 0 0 1 463.849617 83.934426z" fill="#6E6E96" p-id="1907"></path><path d="M869.829246 598.73224l303.792262 277.017181L1121.632525 548.371585zM213.277377 598.73224l300.647519 277.017181L444.561486 553.967213zM542.484984 145.486339l300.994448 271.421552-67.556022-321.882929z" fill="#FFFFFF" opacity=".29" p-id="1908"></path><path d="M111.173945 875.749421L231.927607 693.857923l281.997289 181.891498L213.277377 598.73224zM440.437508 422.346842l116.036547-179.871476 287.005377 174.432525L542.484984 145.486339zM769.107934 869.191344l119.371541-171.601136 285.142033 178.159213L869.829246 598.73224z" fill="#FFFFFF" opacity=".63" p-id="1909"></path></svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1639799941760" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2534" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M976.462606 671.952199c0 165.446108-134.105759 299.551867-299.551867 299.551867v-299.551867h299.551867z" fill="#FFCA5F" p-id="2535"></path><path d="M909.685909 669.827718c-22.587485 121.129427-118.014938 216.55688-239.144365 239.144365v60.407502c165.446108 0 299.551867-134.105759 299.551867-299.551867h-60.407502z" fill="#EDBC58" p-id="2536"></path><path d="M955.217793 671.952199c0 74.339851-28.943934 144.231037-81.5121 196.794955s-122.455104 81.5121-196.794954 81.512099c11.739884 0 21.244813 9.509178 21.244813 21.244813v-299.551867c0 11.739884-9.504929 21.244813-21.244813 21.244813h299.551867a21.244813 21.244813 0 0 1-21.244813-21.244813z m-299.551868 0v299.551867c0 11.739884 9.509178 21.244813 21.244814 21.244814 85.693079 0 166.249162-33.371353 226.843618-93.953063 60.590207-60.585959 93.953062-141.150539 93.953062-226.843618 0-11.735635-9.504929-21.244813-21.244813-21.244813h-299.551867a21.244813 21.244813 0 0 0-21.244814 21.244813z" fill="#6E6E96" p-id="2537"></path><path d="M119.723021 770.026755L512 512H981.510373C981.510373 252.698556 771.301444 42.489627 512 42.489627S42.489627 252.698556 42.489627 512 252.698556 981.510373 512 981.510373V512" fill="#9BDEEB" p-id="2538"></path><path d="M507.751037 38.240664c-98.291253 0-189.512232 30.222871-264.918572 81.856265C288.122158 109.818689 344.013012 106.224066 412.149378 106.224066c249.558573 0 485.223037 89.712598 485.223037 339.275419h-451.877178v451.877179c-249.562822 0-368.521029-244.043419-368.52103-493.601992 0-35.687037 1.759071-67.235585 5.48966-95.130025C54.114788 369.094639 38.240664 436.563917 38.240664 507.751037 38.240664 767.052481 248.449593 977.261411 507.751037 977.261411V507.751037H977.261411C977.261411 248.449593 767.052481 38.240664 507.751037 38.240664z" fill="#8CC8D4" p-id="2539"></path><path d="M97.726141 545.991701C97.726141 307.811851 295.570589 114.721992 539.618257 114.721992c221.277477 0 404.564979 158.736996 436.844349 365.890921C962.402788 233.947884 757.942705 38.240664 507.751037 38.240664 248.449593 38.240664 38.240664 248.449593 38.240664 507.751037S248.449593 977.261411 507.751037 977.261411v-1.130224C278.578988 960.189079 97.726141 773.719104 97.726141 545.991701z" fill="#C4ECF5" p-id="2540"></path><path d="M131.394921 787.774672l392.281228-258.031004a21.266058 21.266058 0 0 1-11.676149 3.492647H981.510373a21.244813 21.244813 0 0 0 21.244814-21.244813C1002.755187 241.396315 782.607934 21.244813 512 21.244813 241.396315 21.244813 21.244813 241.396315 21.244813 512 21.244813 782.607934 241.396315 1002.755187 512 1002.755187a21.244813 21.244813 0 0 0 21.244813-21.244814V512a21.244813 21.244813 0 1 0-42.489626 0V981.510373a21.244813 21.244813 0 0 1 21.244813-21.244813C264.825095 960.26556 63.73444 759.174905 63.73444 512S264.825095 63.73444 512 63.73444 960.26556 264.825095 960.26556 512a21.244813 21.244813 0 0 1 21.244813-21.244813H512c-4.151237 0-8.208996 1.215203-11.676149 3.496896l-392.27698 258.022506a21.244813 21.244813 0 0 0 23.34805 35.500083z" fill="#6E6E96" p-id="2541"></path><path d="M490.755187 551.400631l-306.184498 251.381377-34.824498-27.082888z" fill="#C4ECF5" p-id="2542"></path></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1639799851468" class="icon" viewBox="0 0 1044 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2375" xmlns:xlink="http://www.w3.org/1999/xlink" width="130.5" height="128"><defs><style type="text/css"></style></defs><path d="M754.835364 999.134319V104.799235h166.765953v894.335084" fill="#FFDE66" p-id="2376"></path><path d="M776.778253 999.134319V104.799235l-21.942889 16.299178h166.765953l-21.942889-16.299178v894.335084h43.885777v-923.795606h-210.651729v923.795606z" fill="#6E6E96" p-id="2377"></path><path d="M857.96694 121.098413h41.691488v848.575384h-41.691488z" fill="#6E6E96" opacity=".21" p-id="2378"></path><path d="M465.189236 990.357163V541.366168h166.765953v448.990995" fill="#FF9195" p-id="2379"></path><path d="M487.132124 990.357163V541.366168l-21.942888 31.558262h166.765953l-21.942889-31.558262v448.990995h43.885777v-462.994947h-210.65173v462.994947z" fill="#6E6E96" p-id="2380"></path><path d="M173.348819 990.357163V335.436548h166.765953v654.920615" fill="#7FD8FF" p-id="2381"></path><path d="M195.291708 990.357163V335.436548l-21.942889 30.799038h166.765953l-21.942889-30.799038v654.920615h43.885777V317.807631h-210.651729v672.549532z" fill="#6E6E96" p-id="2382"></path><path d="M1034.24294 1012.300052H32.185829v-1009.372871h43.885777v987.429982l-21.942889-21.942888h980.114223z" fill="#6E6E96" p-id="2383"></path><path d="M276.480395 366.235586h41.691488v606.488272H276.480395zM568.320812 572.92443h41.691488v403.420005h-41.691488z" fill="#6E6E96" opacity=".21" p-id="2384"></path></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

@ -0,0 +1,2 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1653103639871" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="25719" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
</style></defs><path d="M1024 962.752 0 962.752l0-87.424C0 726.656 120 606.72 268.544 606.72l486.464 0c148.48 0 268.992 119.936 268.992 268.544L1024 962.752zM51.008 911.232l921.472 0 0-35.968c0-120.064-97.024-217.472-217.472-217.472L268.544 657.792c-120 0-217.536 97.408-217.536 217.472L51.008 911.232zM512 598.72c-148.48 0-268.992-120-268.992-268.48S363.52 61.248 512 61.248s268.416 120.512 268.416 268.992C780.416 476.224 660.48 598.72 512 598.72zM512 112.768c-120.512 0-217.984 97.024-217.984 217.472 0 120.512 97.472 217.472 217.984 217.472 120 0 217.472-96.96 217.472-217.472C729.472 209.728 632 112.768 512 112.768z" p-id="25720"></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1,2 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1653103706162" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5095" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
</style></defs><path d="M922.60347 767.705615c0 7.167642-2.867057 12.082596-8.498775 14.949653L469.813309 1021.849708 467.663017 1021.849708C466.331883 1023.283236 464.181591 1024 461.314534 1024c-2.867057 0-5.017349-0.716764-6.450877-2.150292L452.713364 1021.849708 8.524374 782.655267C2.892655 779.890605 0.025599 774.873256 0.025599 767.705615L0.025599 255.219239 0.025599 253.068947c0-1.331133 0.716764-2.867057 2.150292-4.300585L2.175891 246.720464l4.300585-4.300585 2.150292-2.150292L452.713364 1.075146c5.734113-1.433528 11.365832-1.433528 17.099945 0l444.188991 239.19444 2.150292 2.150292 4.300585 4.300585 0 2.150292L922.60347 253.068947l0 2.150292L922.60347 767.705615zM34.225489 757.056547l409.989101 222.094495 0-474.088296L34.225489 282.968252 34.225489 757.056547zM655.660017 370.515874 247.718814 150.571671 53.373331 255.219239 461.314534 475.163442 655.660017 370.515874zM284.068997 131.321434 691.907805 351.265637l177.245538-96.148793L461.314534 35.275036 284.068997 131.321434zM888.40358 757.056547l0-474.088296L478.414479 505.062747l0 474.088296L888.40358 757.056547z" p-id="5096"></path></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -0,0 +1,22 @@
# replace default config
# multipass: true
# full: true
plugins:
# - name
#
# or:
# - name: false
# - name: true
#
# or:
# - name:
# param1: 1
# param2: 2
- removeAttrs:
attrs:
- 'fill'
- 'fill-rule'

@ -0,0 +1,55 @@
<template>
<section class="app-main">
<transition name="fade-transform" mode="out-in">
<router-view :key="key" />
</transition>
</section>
</template>
<script>
export default {
name: 'AppMain',
computed: {
cachedViews() {
return this.$store.state.tagsView.cachedViews;
},
key() {
return this.$route.path;
},
},
};
</script>
<style lang="scss" scoped>
.app-main {
/* 50= navbar 50 */
min-height: calc(100vh - 50px);
width: 100%;
position: relative;
overflow: hidden;
}
.fixed-header + .app-main {
padding-top: 50px;
}
.hasTagsView {
.app-main {
/* 84 = navbar + tags-view = 50 + 34 */
min-height: calc(100vh - 84px);
}
.fixed-header + .app-main {
padding-top: 84px;
}
}
</style>
<style lang="scss">
// fix css style bug in open el-dialog
.el-popup-parent--hidden {
.fixed-header {
padding-right: 15px;
}
}
</style>

@ -0,0 +1,157 @@
<template>
<div class="navbar">
<hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container"
@toggleClick="toggleSideBar"/>
<breadcrumb id="breadcrumb-container" class="breadcrumb-container"/>
<div class="right-menu">
<template v-if="device!=='mobile'">
<!-- <search id="header-search" class="right-menu-item" />-->
<!-- <error-log class="errLog-container right-menu-item hover-effect"/> -->
<!-- <screenfull id="screenfull" class="right-menu-item hover-effect" />-->
<!-- <el-tooltip content="Global Size" effect="dark" placement="bottom">-->
<!-- <size-select id="size-select" class="right-menu-item hover-effect" />-->
<!-- </el-tooltip>-->
</template>
<el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
<div class="avatar-wrapper">
<img src="../../../public/hippo4j.gif" class="user-avatar">
<i class="el-icon-caret-bottom"/>
</div>
<el-dropdown-menu slot="dropdown">
<!--<router-link to="/profile/index">
<el-dropdown-item>Profile</el-dropdown-item>
</router-link>-->
<router-link to="/">
<el-dropdown-item>Dashboard</el-dropdown-item>
</router-link>
<el-dropdown-item divided>
<span style="display:block;" @click="logout">Log Out</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import Breadcrumb from '@/components/Breadcrumb'
import Hamburger from '@/components/Hamburger'
import ErrorLog from '@/components/ErrorLog'
export default {
components: {
Breadcrumb,
Hamburger,
ErrorLog
},
computed: {
...mapGetters([
'sidebar',
'avatar',
'device'
])
},
methods: {
toggleSideBar() {
this.$store.dispatch('app/toggleSideBar')
},
async logout() {
this.$cookie.delete('userName')
await this.$store.dispatch('user/logout')
this.$router.push(`/login?redirect=${this.$route.fullPath}`)
}
}
}
</script>
<style lang="scss" scoped>
.navbar {
height: 50px;
overflow: hidden;
position: relative;
background: #fff;
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
.hamburger-container {
line-height: 46px;
height: 100%;
float: left;
cursor: pointer;
transition: background 0.3s;
-webkit-tap-highlight-color: transparent;
&:hover {
background: rgba(0, 0, 0, 0.025);
}
}
.breadcrumb-container {
float: left;
}
.errLog-container {
display: inline-block;
vertical-align: top;
}
.right-menu {
float: right;
height: 100%;
line-height: 50px;
&:focus {
outline: none;
}
.right-menu-item {
display: inline-block;
padding: 0 8px;
height: 100%;
font-size: 18px;
color: #5a5e66;
vertical-align: text-bottom;
&.hover-effect {
cursor: pointer;
transition: background 0.3s;
&:hover {
background: rgba(0, 0, 0, 0.025);
}
}
}
.avatar-container {
margin-right: 30px;
.avatar-wrapper {
margin-top: 5px;
position: relative;
.user-avatar {
cursor: pointer;
width: 40px;
height: 40px;
border-radius: 10px;
}
.el-icon-caret-bottom {
cursor: pointer;
position: absolute;
right: -20px;
top: 25px;
font-size: 12px;
}
}
}
}
}
</style>

@ -0,0 +1,26 @@
export default {
computed: {
device() {
return this.$store.state.app.device
}
},
mounted() {
// In order to fix the click on menu on the ios device will trigger the mouseleave bug
// https://github.com/PanJiaChen/vue-element-admin/issues/1135
this.fixBugIniOS()
},
methods: {
fixBugIniOS() {
const $subMenu = this.$refs.subMenu
if ($subMenu) {
const handleMouseleave = $subMenu.handleMouseleave
$subMenu.handleMouseleave = (e) => {
if (this.device === 'mobile') {
return
}
handleMouseleave(e)
}
}
}
}
}

@ -0,0 +1,29 @@
<script>
export default {
name: 'MenuItem',
functional: true,
props: {
icon: {
type: String,
default: ''
},
title: {
type: String,
default: ''
}
},
render(h, context) {
const { icon, title } = context.props
const vnodes = []
if (icon) {
vnodes.push(<svg-icon icon-class={icon}/>)
}
if (title) {
vnodes.push(<span slot='title'>{(title)}</span>)
}
return vnodes
}
}
</script>

@ -0,0 +1,36 @@
<template>
<!-- eslint-disable vue/require-component-is -->
<component v-bind="linkProps(to)">
<slot />
</component>
</template>
<script>
import { isExternal } from '@/utils/validate'
export default {
props: {
to: {
type: String,
required: true
}
},
methods: {
linkProps(url) {
if (isExternal(url)) {
return {
is: 'a',
href: url,
target: '_blank',
rel: 'noopener'
}
}
return {
is: 'router-link',
to: url
}
}
}
}
</script>

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

Loading…
Cancel
Save