删除magic-boot-ui(基于vue-element-admin vue2版本)

This commit is contained in:
吕金泽
2022-03-05 10:34:47 +08:00
parent 5b2e870ce6
commit 4b2134065e
425 changed files with 0 additions and 139816 deletions
-11
View File
@@ -1,11 +0,0 @@
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
-38
View File
@@ -1,38 +0,0 @@
import request from '@/scripts/request'
export function fetchList(params) {
return request({
url: 'cjBuildingBasis',
method: 'post',
data: params
})
}
export function saveData(params) {
return request({
url: 'cjBuildingBasis/save',
method: 'post',
data: params
})
}
export function removeData(id) {
return request({
url: 'cjBuildingBasis/delete',
method: 'post',
params: {
id: id
}
})
}
export function getDetail(id) {
return request({
url: 'cjBuildingBasis/getDetail',
method: 'get',
params: {
id: id
}
})
}
-20
View File
@@ -1,20 +0,0 @@
import request from '@/scripts/request'
export function saveData(params) {
return request({
url: 'dict/save',
method: 'post',
params
})
}
export function getDictItems() {
return new Promise((resolve, reject) => {
request({
url: 'dict/items/all',
method: 'get'
}).then(res => {
resolve(res.data)
})
})
}
-15
View File
@@ -1,15 +0,0 @@
import request from '@/scripts/request'
export function getMenuTree() {
return request({
url: 'menu/tree',
method: 'get'
})
}
export function getCurrentUserMenu() {
return request({
url: 'menu/current/menus',
method: 'post'
})
}
-49
View File
@@ -1,49 +0,0 @@
import request from '@/scripts/request'
export function login(data) {
return request({
url: 'security/login',
method: 'post',
data
})
}
export function getInfo() {
return request({
url: 'user/info',
method: 'get'
})
}
export function logout() {
return request({
url: 'security/logout',
method: 'get'
})
}
export function fetchList(params) {
return request({
url: 'user/list',
method: 'get',
params
})
}
export function saveData(params) {
return request({
url: 'user/save',
method: 'post',
params
})
}
export function removeData(id) {
return request({
url: 'user/delete',
method: 'post',
params: {
id: id
}
})
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 522 B

@@ -1,138 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin:auto;background:#7aceff;display:block;z-index:1;position:relative" width="1920" height="1080" preserveAspectRatio="xMidYMid" viewBox="0 0 1920 1080">
<g transform="translate(960,540) scale(1,1) translate(-960,-540)"><g transform="translate(-100 416.03196572326607) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 416.03196572326607;1920 416.03196572326607" dur="500s" repeatCount="indefinite" begin="-5.139372331517178s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(0.55)"></path>
</g><g transform="translate(-100 596.4001678117764) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 596.4001678117764;1920 596.4001678117764" dur="500s" repeatCount="indefinite" begin="-130.3016475134896s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(0.55)"></path>
</g><g transform="translate(-100 26.545882090192208) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 26.545882090192208;1920 26.545882090192208" dur="500s" repeatCount="indefinite" begin="-418.3960343898864s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(0.55)"></path>
</g><g transform="translate(-100 571.769019413317) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 571.769019413317;1920 571.769019413317" dur="500s" repeatCount="indefinite" begin="-479.907328466289s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(0.55)"></path>
</g><g transform="translate(-100 299.0294986971487) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 299.0294986971487;1920 299.0294986971487" dur="500s" repeatCount="indefinite" begin="-227.05389635543605s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(0.55)"></path>
</g><g transform="translate(-100 963.5414388315442) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 963.5414388315442;1920 963.5414388315442" dur="500s" repeatCount="indefinite" begin="-257.66135282842185s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(0.55)"></path>
</g><g transform="translate(-100 381.5964835751399) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 381.5964835751399;1920 381.5964835751399" dur="500s" repeatCount="indefinite" begin="-307.0477827472562s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(0.55)"></path>
</g><g transform="translate(-100 645.4789577105932) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 645.4789577105932;1920 645.4789577105932" dur="500s" repeatCount="indefinite" begin="-202.62184460542164s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(0.55)"></path>
</g><g transform="translate(-100 869.0735193051235) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 869.0735193051235;1920 869.0735193051235" dur="500s" repeatCount="indefinite" begin="-255.24368861928292s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(0.55)"></path>
</g><g transform="translate(-100 361.72520676524846) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 361.72520676524846;1920 361.72520676524846" dur="500s" repeatCount="indefinite" begin="-483.79414705548476s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(0.55)"></path>
</g><g transform="translate(-100 86.68805096063784) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 86.68805096063784;1920 86.68805096063784" dur="500s" repeatCount="indefinite" begin="-320.8829128692832s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(0.55)"></path>
</g><g transform="translate(-100 488.9772963132972) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 488.9772963132972;1920 488.9772963132972" dur="250s" repeatCount="indefinite" begin="-170.39139507921476s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#ffffff" transform="scale(0.7)"></path>
</g><g transform="translate(-100 4.576774043616565) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 4.576774043616565;1920 4.576774043616565" dur="250s" repeatCount="indefinite" begin="-316.15263864899003s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#ffffff" transform="scale(0.7)"></path>
</g><g transform="translate(-100 214.60993590372678) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 214.60993590372678;1920 214.60993590372678" dur="250s" repeatCount="indefinite" begin="-398.4521377828001s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#ffffff" transform="scale(0.7)"></path>
</g><g transform="translate(-100 1078.2795968790304) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 1078.2795968790304;1920 1078.2795968790304" dur="250s" repeatCount="indefinite" begin="-91.39136730030228s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#ffffff" transform="scale(0.7)"></path>
</g><g transform="translate(-100 696.282800231443) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 696.282800231443;1920 696.282800231443" dur="250s" repeatCount="indefinite" begin="-9.791027044726896s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#ffffff" transform="scale(0.7)"></path>
</g><g transform="translate(-100 561.7712540738951) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 561.7712540738951;1920 561.7712540738951" dur="250s" repeatCount="indefinite" begin="-193.89859611923643s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#ffffff" transform="scale(0.7)"></path>
</g><g transform="translate(-100 1027.434371957216) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 1027.434371957216;1920 1027.434371957216" dur="250s" repeatCount="indefinite" begin="-208.13490311748794s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#ffffff" transform="scale(0.7)"></path>
</g><g transform="translate(-100 723.5576871943198) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 723.5576871943198;1920 723.5576871943198" dur="250s" repeatCount="indefinite" begin="-397.71421883595184s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#ffffff" transform="scale(0.7)"></path>
</g><g transform="translate(-100 138.14742803728817) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 138.14742803728817;1920 138.14742803728817" dur="250s" repeatCount="indefinite" begin="-468.4075429967608s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#ffffff" transform="scale(0.7)"></path>
</g><g transform="translate(-100 1064.1245308500543) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 1064.1245308500543;1920 1064.1245308500543" dur="250s" repeatCount="indefinite" begin="-127.52573851087668s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#ffffff" transform="scale(0.7)"></path>
</g><g transform="translate(-100 867.7256355602567) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 867.7256355602567;1920 867.7256355602567" dur="250s" repeatCount="indefinite" begin="-404.38720114464013s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#ffffff" transform="scale(0.7)"></path>
</g><g transform="translate(-100 585.4335678795345) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 585.4335678795345;1920 585.4335678795345" dur="166.66666666666666s" repeatCount="indefinite" begin="-232.32351534757112s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#f1f2f3" transform="scale(0.85)"></path>
</g><g transform="translate(-100 55.826384663633284) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 55.826384663633284;1920 55.826384663633284" dur="166.66666666666666s" repeatCount="indefinite" begin="-310.35651449581314s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#f1f2f3" transform="scale(0.85)"></path>
</g><g transform="translate(-100 550.8735693730529) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 550.8735693730529;1920 550.8735693730529" dur="166.66666666666666s" repeatCount="indefinite" begin="-250.08402103222537s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#f1f2f3" transform="scale(0.85)"></path>
</g><g transform="translate(-100 468.8701205905754) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 468.8701205905754;1920 468.8701205905754" dur="166.66666666666666s" repeatCount="indefinite" begin="-487.8153302121583s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#f1f2f3" transform="scale(0.85)"></path>
</g><g transform="translate(-100 507.2526567834844) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 507.2526567834844;1920 507.2526567834844" dur="166.66666666666666s" repeatCount="indefinite" begin="-233.64601277250242s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#f1f2f3" transform="scale(0.85)"></path>
</g><g transform="translate(-100 345.3058813907401) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 345.3058813907401;1920 345.3058813907401" dur="166.66666666666666s" repeatCount="indefinite" begin="-487.12855908306886s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#f1f2f3" transform="scale(0.85)"></path>
</g><g transform="translate(-100 1031.1827146601443) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 1031.1827146601443;1920 1031.1827146601443" dur="166.66666666666666s" repeatCount="indefinite" begin="-10.720882299359303s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#f1f2f3" transform="scale(0.85)"></path>
</g><g transform="translate(-100 18.27432163445976) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 18.27432163445976;1920 18.27432163445976" dur="166.66666666666666s" repeatCount="indefinite" begin="-239.34624845076246s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#f1f2f3" transform="scale(0.85)"></path>
</g><g transform="translate(-100 254.00652063210185) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 254.00652063210185;1920 254.00652063210185" dur="166.66666666666666s" repeatCount="indefinite" begin="-97.67550616205378s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#f1f2f3" transform="scale(0.85)"></path>
</g><g transform="translate(-100 853.1521302679544) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 853.1521302679544;1920 853.1521302679544" dur="166.66666666666666s" repeatCount="indefinite" begin="-215.52668400815244s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#f1f2f3" transform="scale(0.85)"></path>
</g><g transform="translate(-100 120.29600539710484) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 120.29600539710484;1920 120.29600539710484" dur="166.66666666666666s" repeatCount="indefinite" begin="-121.43545841045444s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#f1f2f3" transform="scale(0.85)"></path>
</g><g transform="translate(-100 739.4135223183714) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 739.4135223183714;1920 739.4135223183714" dur="125s" repeatCount="indefinite" begin="-433.4250149061785s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(1)"></path>
</g><g transform="translate(-100 239.0788419164232) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 239.0788419164232;1920 239.0788419164232" dur="125s" repeatCount="indefinite" begin="-407.9383077190322s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(1)"></path>
</g><g transform="translate(-100 573.1972400632184) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 573.1972400632184;1920 573.1972400632184" dur="125s" repeatCount="indefinite" begin="-456.49760543175864s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(1)"></path>
</g><g transform="translate(-100 915.5433684236687) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 915.5433684236687;1920 915.5433684236687" dur="125s" repeatCount="indefinite" begin="-40.03727141414903s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(1)"></path>
</g><g transform="translate(-100 824.8766336499561) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 824.8766336499561;1920 824.8766336499561" dur="125s" repeatCount="indefinite" begin="-16.039906214160293s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(1)"></path>
</g><g transform="translate(-100 499.265059924676) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 499.265059924676;1920 499.265059924676" dur="125s" repeatCount="indefinite" begin="-35.858363803996426s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(1)"></path>
</g><g transform="translate(-100 1022.1802798581422) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 1022.1802798581422;1920 1022.1802798581422" dur="125s" repeatCount="indefinite" begin="-190.07909527181744s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(1)"></path>
</g><g transform="translate(-100 1062.112161307141) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 1062.112161307141;1920 1062.112161307141" dur="125s" repeatCount="indefinite" begin="-108.16335769140706s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(1)"></path>
</g><g transform="translate(-100 249.76500277280388) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 249.76500277280388;1920 249.76500277280388" dur="125s" repeatCount="indefinite" begin="-360.72984703184443s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(1)"></path>
</g><g transform="translate(-100 989.5257835559386) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 989.5257835559386;1920 989.5257835559386" dur="125s" repeatCount="indefinite" begin="-358.39639108375485s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(1)"></path>
</g><g transform="translate(-100 763.1858129038242) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 763.1858129038242;1920 763.1858129038242" dur="125s" repeatCount="indefinite" begin="-57.071504489237036s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(1)"></path>
</g><g transform="translate(-100 394.96112430266106) rotate(0)">
<animateTransform attributeName="transform" type="translate" keyTimes="0;1" values="-100 394.96112430266106;1920 394.96112430266106" dur="125s" repeatCount="indefinite" begin="-175.51156196107908s"></animateTransform>
<path d="M84.717,33.597c0.791-2.503,1.186-5.138,1.186-7.773C85.903,11.594,74.308,0,60.079,0 c-9.881,0-18.445,5.534-22.793,13.702c-1.581-0.527-3.426-0.791-5.138-0.791c-9.486,0-17.128,7.642-17.128,17.128 c0,1.186,0.132,2.372,0.395,3.426C6.719,34.783,0,42.424,0,51.515C0,61.66,8.169,69.829,18.314,69.829h63.373 C91.831,69.829,100,61.66,100,51.515C99.868,42.556,93.281,35.046,84.717,33.597z" fill="#bddeff" transform="scale(1)"></path>
</g></g>
</svg>

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

@@ -1,78 +0,0 @@
<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() {
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: '首页' }}].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() === '首页'.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>
@@ -1,78 +0,0 @@
<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>
@@ -1,44 +0,0 @@
<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>
@@ -1,180 +0,0 @@
<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;
::v-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>
@@ -1,41 +0,0 @@
<template>
<div ref="jsoneditor" style="height: 800px" />
</template>
<script>
import JSONEditor from 'jsoneditor/dist/jsoneditor.js'
import 'jsoneditor/dist/jsoneditor.css'
export default {
name: 'JsonEditor',
props: {
json: {
type: Object,
default: () => {}
},
options: {
type: Object,
default: () => {}
}
},
data() {
return {
editor: null
}
},
watch: {
json(newJson) {
if (this.editor) {
this.editor.destroy()
this.editor = new JSONEditor(this.$refs.jsoneditor, this.options, newJson)
}
}
},
mounted() {
this.editor = new JSONEditor(this.$refs.jsoneditor, this.options, this.json)
}
}
</script>
<style>
</style>
@@ -1,143 +0,0 @@
<template>
<el-button
v-bind="el_"
@click="buttonClick"
>
{{ el_.text }}
</el-button>
</template>
<script>
import { getToken } from '@/scripts/auth'
export default {
name: 'MbButton',
props: {
el: {
type: Object,
default: () => {}
},
btnType: {
type: String,
default: ''
},
requestMethod: {
type: String,
default: 'get'
},
requestUrl: {
type: String,
default: ''
},
requestData: {
type: Object,
default: () => {}
},
beforeConfirm: {
type: String,
default: ''
},
successTips: {
type: String,
default: ''
},
failTips: {
type: String,
default: ''
},
confirmType: {
type: String,
default: 'warning'
},
afterHandler: {
type: Function,
default: () => {}
},
isOpen: {
type: Boolean,
default: false
}
},
data() {
return {
el_: this.el || {},
requestMethod_: this.requestMethod,
beforeConfirm_: this.beforeConfirm,
successTips_: this.successTips,
failTips_: this.failTips
}
},
created() {
if (this.btnType) {
if (this.btnType === 'delete') {
this.requestMethod_ = 'post'
this.el_.type = 'danger'
this.el_.text = '删除'
this.el_.icon = 'el-icon-delete'
this.beforeConfirm_ = '确定删除吗?'
this.successTips_ = '删除成功!'
this.failTips_ = '删除失败!'
}
}
},
methods: {
async buttonClick() {
if (this.beforeConfirm_) {
this.$confirm(this.beforeConfirm_, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: this.confirmType
}).then((res) => {
this.buttonClickRequest().then(() => {
this.afterHandler()
})
})
}
},
buttonClickRequest() {
// var requestOptions = {}
// requestOptions.url = this.requestUrl
// requestOptions.method = this.requestMethod_
// if (requestOptions.method === 'get') {
// requestOptions.params = this.requestData
// } else {
// requestOptions.data = this.requestData
// }
if (this.isOpen) {
return new Promise(() => {
window.open(this.$common.getUrl(process.env.VUE_APP_BASE_API + this.requestUrl, this.requestData) + '&token=' + getToken())
})
}
return new Promise((resolve, reject) => {
if (this.requestMethod_ === 'get') {
this.$get(this.requestUrl, this.requestData).then(res => {
const { data } = res
if (data) {
this.$message({
type: 'success',
message: this.successTips_
})
} else {
this.$message.error(this.failTips_)
}
resolve()
})
} else {
this.$post(this.requestUrl, this.requestData).then(res => {
const { data } = res
if (data) {
this.$message({
type: 'success',
message: this.successTips_
})
} else {
this.$message.error(this.failTips_)
}
resolve()
})
}
})
}
}
}
</script>
@@ -1,91 +0,0 @@
<template>
<el-dialog v-el-drag-dialog :fullscreen="fullscreen" :width="width" :title="title" :visible.sync="dialogVisible" :close-on-click-modal="false" :append-to-body="true" @opened="opened">
<slot name="content" />
<div slot="footer" class="dialog-footer">
<slot name="btns">
<el-button @click="dialogVisible = false">
关闭
</el-button>
<el-button type="primary" :loading="confirmLoading" @click="confirmClick">
确认
</el-button>
</slot>
</div>
</el-dialog>
</template>
<script>
export default {
name: 'MbDialog',
props: {
title: {
type: String,
default: ''
},
width: {
type: String,
default: '50%'
},
fullscreen: {
type: Boolean,
default: false
},
opened: {
type: Function,
default: () => {}
}
},
data() {
return {
dialogVisible: false,
confirmLoading: false
}
},
created() {
if (this.fullscreen) {
document.body.style.setProperty('--el-dialog__wrapper-bottom', '0vh')
document.body.style.setProperty('--el-dialog__wrapper-top', '0vh')
document.body.style.setProperty('--el-dialog__body-max-height', '100vh')
} else {
document.body.style.setProperty('--el-dialog__wrapper-bottom', '15vh')
document.body.style.setProperty('--el-dialog__wrapper-top', '15vh')
document.body.style.setProperty('--el-dialog__body-max-height', '60vh')
}
},
methods: {
confirmClick() {
this.$emit('confirm-click', this)
},
loading(){
this.confirmLoading = true
},
hideLoading(){
this.confirmLoading = false
},
show() {
this.dialogVisible = true
},
hide() {
this.dialogVisible = false
}
}
}
</script>
<style scoped>
.el-dialog__wrapper{
padding-bottom: var(--el-dialog__wrapper-bottom);
padding-top: var(--el-dialog__wrapper-top);
overflow: hidden;
}
.el-dialog__wrapper >>> .el-dialog{
margin-top: 0vh!important;
}
.el-dialog__wrapper >>> .el-dialog__body{
max-height: var(--el-dialog__body-max-height);
overflow: auto;
padding: 25px!important;
}
</style>
@@ -1,77 +0,0 @@
<template>
<div>
<el-row style="margin-bottom: 6px">
<el-button type="primary" @click="tableOptions.data.push({})">添加一行</el-button>
</el-row>
<mb-table v-bind="tableOptions">
<template v-for="col in cols" #[col.field]="{ index }">
<el-input v-if="col.type === 'input'" v-bind="col.properties" v-model="tableOptions.data[index][col.field]" @change="dataChange" />
<mb-select v-else-if="col.type === 'select'" v-bind="col.properties" v-model="tableOptions.data[index][col.field]" @change="dataChange" />
</template>
</mb-table>
</div>
</template>
<script>
export default {
name: 'MbEditorTable',
model: {
prop: 'value',
event: 'change'
},
props: {
// eslint-disable-next-line vue/require-prop-types
value: {
required: true
},
cols: {
type: Array,
default: () => []
},
showNo: {
type: Boolean,
default: true
}
},
data() {
return {
tableOptions: {
data: [],
cols: [],
showNo: this.showNo
}
}
},
created() {
for (var i in this.cols) {
var col = this.cols[i]
this.tableOptions.cols.push({
type: 'dynamic',
field: col.field,
title: col.title
})
}
this.tableOptions.cols.push({
title: '操作',
type: 'btns',
width: 85,
fixed: 'right',
btns: [{
title: '删除',
type: 'danger',
click: (row, index) => {
this.tableOptions.data.splice(index, 1)
}
}]
})
},
methods: {
dataChange() {
console.log('更新')
this.$emit('update:value', this.tableOptions.data)
this.$emit('change', this.tableOptions.data)
}
}
}
</script>
@@ -1,92 +0,0 @@
<template>
<div class="filter-container">
<el-form :inline="true" @keyup.enter.native="search">
<el-form-item :label="it.label" v-for="it in where">
<el-input v-if="it.type == 'input'" @input="input(it.input)" v-model="it.value" :placeholder="it.placeholder || ('请输入' + it.label)" style="width: 200px;" class="filter-item" />
<mb-select v-else-if="it.type == 'select'" v-model="it.value" :placeholder="'请输入' + it.label" v-bind="it.properties" />
<el-date-picker
v-else-if="it.type == 'date' || it.type == 'datetime' || it.type == 'daterange' || it.type == 'datetimerange'"
v-model="it.value"
align="right"
:format="it.type.startsWith('datetime') ? 'yyyy-MM-dd HH:mm:ss' : 'yyyy-MM-dd'"
:value-format="it.type.startsWith('datetime') ? 'yyyy-MM-dd HH:mm:ss' : 'yyyy-MM-dd'"
:type="it.type"
:start-placeholder="it.type.startsWith('datetime') ? 'yyyy-MM-dd HH:mm:ss' : 'yyyy-MM-dd'"
:end-placeholder="it.type.startsWith('datetime') ? 'yyyy-MM-dd HH:mm:ss' : 'yyyy-MM-dd'"
:placeholder="it.type.startsWith('datetime') ? 'yyyy-MM-dd HH:mm:ss' : 'yyyy-MM-dd'"
>
</el-date-picker>
<component v-else :is="it.type" v-model="it.value" v-bind="it.properties" />
</el-form-item>
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="search">
搜索
</el-button>
<el-button class="filter-item" icon="el-icon-delete" @click="reset">
清空
</el-button>
<slot name="btns" />
</el-form>
</div>
</template>
<script>
export default {
name: "MbSearch",
props: {
where: {
type: Object,
default: () => {}
},
notReset: {
type: String,
default: ''
}
},
data() {
return {
}
},
methods: {
input(input){
if(input){
this.$emit('search')
}
},
search(){
for(var key in this.where){
if(this.where[key] instanceof Object){
if(this.where[key].type.startsWith('date') && this.where[key].value instanceof Array){
this.where[key].value = this.where[key].value.join(',')
}
}
}
this.$nextTick(() => {
this.$emit('search')
for(var key in this.where){
if(this.where[key] instanceof Object){
if(this.where[key].type.startsWith('date')){
this.where[key].value = this.where[key].value.split(',')
}
}
}
})
},
reset() {
for(var key in this.where){
if(this.notReset.indexOf(key) == -1){
if(this.where[key] instanceof Object){
this.where[key].value = null
}else{
this.where[key] = null
}
}
}
this.$nextTick(() => this.$emit('search'))
}
}
}
</script>
<style scoped>
</style>
@@ -1,157 +0,0 @@
<template>
<div>
<el-select v-if="mbType === 'select'" v-model="selectValue" v-bind="el" :style="{ width }" :placeholder="placeholder || '请选择'" filterable clearable>
<el-option
v-for="item in selectList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-radio-group v-if="mbType === 'radio'" v-model="selectValue">
<el-radio v-for="item in selectList" :key="item.value" :label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</div>
</template>
<script>
export default {
name: 'MbSelect',
model: {
prop: 'value',
event: 'change'
},
props: {
data: {
type: Array,
default: () => []
},
type: {
type: String,
default: ''
},
// eslint-disable-next-line vue/require-prop-types
value: {
required: true
},
width: {
type: String,
default: '100%'
},
allOption: {
type: Boolean,
default: false
},
url: {
type: String,
default: ''
},
params: {
type: Object,
default: () => {}
},
labelField: {
type: String,
default: 'label'
},
valueField: {
type: String,
default: 'value'
},
mbType: {
type: String,
default: 'select'
},
el: {
type: Object,
default: () => {}
},
placeholder: {
type: String,
default: ''
}
},
data() {
return {
selectList: [],
selectValue: ''
}
},
watch: {
type(newVal) {
if (this.value instanceof Array || this.value.toString().indexOf(',') !== -1) {
this.selectValue = []
} else {
this.selectValue = ''
}
this.loadData()
},
value(value) {
this.loadData()
},
selectValue(value) {
if (this.el && this.el.multiple && value.length > 0) {
value = value.join(',')
}
this.$emit('update:value', value)
this.$emit('change', value)
}
},
mounted() {
this.loadData()
},
methods: {
async loadData() {
if (this.value || this.value == '') {
if ((!(this.value instanceof Array) && this.value.toString().indexOf(',') !== -1)) {
this.selectValue = this.value.split(',')
} else {
if (this.el && this.el.multiple && !(this.value instanceof Array)) {
this.selectValue = [this.value]
} else {
this.selectValue = this.value
}
}
} else {
if (this.el && this.el.multiple) {
this.selectValue = []
}
}
if (this.data && this.data.length > 0) {
this.listConcat(this.handlerData(this.data))
} else if (this.url) {
this.$get(this.url, this.params).then(res => {
this.listConcat(this.handlerData(res.data.list))
})
} else {
this.listConcat(this.$common.getDictType(this.type))
}
},
listConcat(dictData) {
if (this.allOption) {
this.selectList = [{
value: '',
label: '全部'
}]
this.selectList = this.selectList.concat(dictData)
} else {
this.selectList = dictData
}
},
handlerData(data) {
var newData = []
data.forEach(it => {
newData.push({
label: it[this.labelField],
value: it[this.valueField].toString()
})
})
return newData
}
}
}
</script>
@@ -1,57 +0,0 @@
<template>
<el-table-column
:key="col.field"
:label="col.title"
:prop="col.field"
:align="col.align || 'center'"
:width="col.width"
:fixed="col.fixed"
:sortable="col.sortable"
>
<template v-if="!col.cols" slot-scope="scope">
<span v-if="col.templet" v-html="col.templet(scope.row)" />
<span v-else-if="col.dictType">
{{ $common.getDictLabel(col.dictType, scope.row[col.field] + '') }}
</span>
<slot v-else-if="col.type == 'dynamic'" :name="col.field" :row="scope.row" :index="scope.$index" />
<el-switch
v-else-if="col.type == 'switch'"
v-model="scope.row[col.field]"
:active-value="col.activeValue || 1"
:inactive-value="col.inactiveValue || 0"
@change="col.change(scope.row)"
/>
<div v-else-if="col.type == 'btns'">
<template v-for="btn in col.btns">
<el-button v-if="btn.if === undefined ? true : btn.if(scope.row)" :icon="btn.icon" :key="btn.title" v-permission="btn.permission" :type="btn.type" :size="btn.size || 'mini'" :class="btn.class" @click="btn.click(scope.row, scope.$index)">
{{ btn.title }}
</el-button>
</template>
</div>
<el-image v-else-if="col.type === 'image'" :src="scope.row[col.field]" :preview-src-list="[scope.row[col.field]]" />
<span v-else-if="col.type === 'html'" v-html="scope.row[col.field]"></span>
<span v-else-if="col.click">
<a style="color: blue" @click="col.click(scope.row)">{{ scope.row[col.field] }}</a>
</span>
<span v-else-if="col.field">{{ scope.row[col.field] }}</span>
</template>
<mb-table-column v-for="(col2, j) in col.cols" :key="j" :col="col2">
<template v-for="(value, key) in $scopedSlots" #[key]="{ row, index }">
<slot :row="row" :index="index" :name="key" />
</template>
</mb-table-column>
</el-table-column>
</template>
<script>
export default {
name: 'MbTableColumn',
props: {
col: {
type: Object,
default: () => {}
}
}
}
</script>
@@ -1,236 +0,0 @@
<template>
<div>
<el-table
:key="tableKey"
v-loading="listLoading"
:data="list"
border
fit
highlight-current-row
v-bind="el"
style="width: 100%;"
@sort-change="sortChange"
@selection-change="selectionChange"
>
<el-table-column v-if="selection" align="center" type="selection" width="50" />
<el-table-column v-if="showNo" label="序号" prop="num" align="center" width="65">
<template slot-scope="row">
<span>{{ row.$index+1 }}</span>
</template>
</el-table-column>
<mb-table-column v-for="(col, i) in cols" :key="i" :col="col">
<template v-for="(value, key) in $scopedSlots" #[key]="{ row, index }">
<slot :row="row" :index="index" :name="key" />
</template>
</mb-table-column>
<el-empty :description="emptyText" slot="empty" />
</el-table>
<pagination v-show="total > 0 && page" :total="total || 0" :page.sync="listCurrent" :limit.sync="limit" @pagination="handlerPagination" />
</div>
</template>
<script>
import request from '@/scripts/request'
import Pagination from '@/components/Pagination'
import MbTableColumn from './mb-table-column.vue'
export default {
name: 'MbTable',
components: { Pagination, MbTableColumn },
props: {
el: {
type: Object,
default: () => {}
},
url: {
type: String,
default: ''
},
limit: {
type: Number,
default: 10
},
page: {
type: Boolean,
default: true
},
done: {
type: Function,
default: () => {}
},
where: {
type: Object,
default: () => {
return {}
}
},
showNo: {
type: Boolean,
default: true
},
selection: {
type: Boolean,
default: false
},
data: {
type: Array,
default: null
},
method: {
type: String,
default: 'get'
},
cols: {
type: Array,
default: () => {
return []
}
},
emptyText: {
type: String,
default: '暂无数据'
}
},
data() {
return {
listCurrent: 1,
total: 0,
list: [],
listLoading: false,
tableKey: 0,
newWhere: {}
}
},
watch: {
data() {
this.listCurrent = 1
this.handlerData()
},
where: {
handler(){
this.renderWhere()
},
deep: true
}
},
created() {
this.renderWhere()
},
mounted() {
this.keyup()
if (this.data) {
this.handlerData()
}
if (this.url) {
this.getList()
}
},
methods: {
renderWhere(){
this.newWhere = this.$common.renderWhere(this.where)
},
getList() {
this.renderWhere()
this.listLoading = true
if (this.page) {
this.newWhere.current = this.listCurrent
this.newWhere.size = this.limit
} else {
this.newWhere.size = 99999999
}
request({
url: this.url,
method: this.method,
params: this.newWhere
}).then(res => {
const { data } = res
this.total = data.total
this.list = data.list
this.listLoading = false
this.done()
})
},
sortChange(column) {
let order = column.order
if (order) {
order = order === 'descending' ? 'desc' : ''
order = column.prop + ' ' + order
} else {
order = null
}
this.newWhere.orderBy = order
this.reloadList()
},
selectionChange(columns) {
this.$emit('selection-change', columns)
},
reloadList() {
if (this.url) {
this.newWhere.current = 1
this.listCurrent = 1
this.getList()
}
},
handlerData() {
this.listLoading = true
this.total = this.data.length
var currPageData = []
this.data.forEach((it, i) => {
if (i >= ((this.listCurrent - 1) * this.limit) && i < (this.listCurrent * this.limit) && currPageData.length < this.limit) {
currPageData.push(it)
}
})
this.list = currPageData
this.done()
this.listLoading = false
},
handlerPagination() {
if (this.url) {
this.getList()
}
if (this.data) {
this.handlerData()
}
},
keyup(){
document.onkeyup = (e) => {
if(e.target.nodeName != 'INPUT'){
if (e && e.keyCode == 37) {
if(this.listCurrent != 1){
this.listCurrent -= 1
this.handlerPagination()
}
} else if (e && e.keyCode == 39) {
if(this.listCurrent != parseInt((this.total + this.limit - 1) / this.limit)){
this.listCurrent += 1
this.handlerPagination()
}
}
}
}
}
}
}
</script>
<style scoped>
.el-image >>> .el-image__inner {
max-height: 100px;
width: auto;
height: auto;
}
</style>
<style>
.el-table-column--selection .cell {
padding:0px 15px!important;
}
.el-table th {
background: #F5F7FA;
}
</style>
@@ -1,149 +0,0 @@
<template>
<div>
<div style="margin-bottom: 5px;" v-if="expand || checked">
<el-button v-if="expand" type="primary" size="mini" icon="el-icon-sort" plain @click="doExpand">展开/折叠</el-button>
<el-button v-if="checked" type="primary" size="mini" icon="el-icon-check" plain @click="() => { treeAllChecked = !treeAllChecked; checkedAll(searchData, treeAllChecked) }">全选/全不选</el-button>
</div>
<div style="margin-bottom: 5px;" v-if="search">
<el-input v-model="searchValue" placeholder="输入关键字进行过滤" @input="searchTree" :style="{ width: searchWidth }" />
</div>
<el-tree
v-if="refreshTree"
ref="tree"
:data="searchData"
v-bind="el"
node-key="id"
:default-expand-all="defaultExpandAll"
:default-checked-keys="checkedIds"
@check-change="checkChange"
@node-click="nodeClick"
:props="defaultProps"
:style="{ 'max-height': maxHeight ? maxHeight : '100%' }"
style="overflow: auto"
/>
</div>
</template>
<script>
export default {
name: 'MbTree',
props: {
url: {
type: String,
default: ''
},
params: {
type: Object,
default: () => {}
},
selectValues: {
type: String,
default: ''
},
maxHeight: {
type: String,
default: ''
},
el: {
type: Object,
default: () => {}
},
expand: {
type: Boolean,
default: true
},
checked: {
type: Boolean,
default: true
},
search: {
type: Boolean,
default: false
},
searchWidth: {
type: String,
default: '230px'
},
checkedIds: {
type: Array,
default: () => []
}
},
watch: {
async selectValues() {
await this.loadTreeData()
this.checkedAll(this.searchData, false)
var values = this.selectValues.split(',');
for(var i in values){
this.$refs.tree.setChecked(values[i], true, false)
}
}
},
data() {
return {
treeData: [],
searchData: [],
defaultProps: {
children: 'children',
label: 'name'
},
defaultExpandAll: true,
refreshTree: true,
treeAllChecked: false,
searchValue: ''
}
},
async created() {
await this.loadTreeData()
},
methods: {
searchTree() {
if(this.searchValue){
this.searchData = this.$treeTable.recursionSearch(['name'], this.$common.copyNew(this.treeData), this.searchValue, false)
}else{
this.searchData = this.treeData
}
},
doExpand() {
this.refreshTree = false
this.defaultExpandAll = !this.defaultExpandAll
this.$nextTick(() => this.refreshTree = true)
},
async loadTreeData() {
if(this.treeData.length == 0){
await this.$get(this.url, this.params).then((res) => {
this.treeData = res.data.list
this.searchData = this.treeData
})
}
},
getTree() {
return this.$refs.tree
},
checkChange(node) {
var selectMenus = []
var checkedNodes = this.$refs.tree.getCheckedNodes(false, true)
for (var i = 0; i < checkedNodes.length; i++) {
selectMenus.push(checkedNodes[i].id)
}
this.$emit('update:select-values', selectMenus.join(','))
this.$emit('check-change', selectMenus.join(','))
},
nodeClick(param1, param2, param3){
this.$emit('node-click', param1, param2, param3)
},
checkedAll(children, checked) {
if (this.$refs.tree) {
for (var i in children) {
var id = children[i].id
if(children[i].children && children[i].children.length > 0){
this.checkedAll(children[i].children, checked)
}
this.$refs.tree.setChecked(id, checked, true)
}
}
}
}
}
</script>
@@ -1,49 +0,0 @@
<template>
<vue-ueditor-wrap v-model="content" :config="editorConfig" editor-id="mb-ueditor" />
</template>
<script>
import VueUeditorWrap from 'vue-ueditor-wrap'
export default {
name: 'MbUeditor',
components: {
VueUeditorWrap
},
model: {
prop: 'value',
event: 'change'
},
props: {
value: {
type: String,
default: ''
},
config: {
type: Object,
default: () => {}
}
},
data() {
return {
content: '',
editorConfig: {}
}
},
watch: {
content(value) {
this.$emit('change', value)
},
value(value) {
this.content = value
}
},
created() {
this.content = this.value
this.editorConfig = this.config || {}
this.editorConfig.UEDITOR_HOME_URL = this.editorConfig.UEDITOR_HOME_URL || '/UEditor/'
this.editorConfig.serverUrl = this.editorConfig.serverUrl || process.env.VUE_APP_BASE_API + 'ueditor/main'
}
}
</script>
@@ -1,230 +0,0 @@
<template>
<el-upload
:id="uploadDomId"
class="upload-demo"
:action="action"
:headers="headers"
:on-preview="handlePreview"
:on-remove="handleRemove"
:before-remove="beforeRemove"
:multiple="multiple"
:limit="limit"
:on-exceed="handleExceed"
:file-list="fileList"
:before-upload="beforeAvatarUpload"
:on-success="handleAvatarSuccess"
>
<el-button size="small" type="primary" :disabled="!multiple && fileList.length == 1">点击上传</el-button>
<div slot="tip" class="el-upload__tip">支持上传{{ getSettingSuffixs().replaceAll(',', '') }}文件且不超过{{ maxFileSize }}MB</div>
</el-upload>
</template>
<script>
import { getToken } from '@/scripts/auth'
export default {
name: 'MbUploadFile',
model: {
prop: 'value',
event: 'change'
},
props: {
value: {
required: false
},
multiple: {
type: Boolean,
default: false
},
limit: {
type: Number,
default: 20
},
maxFileSize: {
type: Number,
default: 200
},
accept: {
type: String,
default: ''
},
externalId: {
type: String,
default: ''
},
externalType: {
type: String,
default: ''
},
formats: {
type: String,
default: ''
}
},
data() {
return {
acceptList: {
image: 'png,jpg,gif,jpeg',
wps: 'pdf,pptx,xls,xlsx,csv,docx,doc',
compress: 'zip,rar,7z',
video: 'avi,flv,mp4,mpeg,mov'
},
imageUrl: '',
action: process.env.VUE_APP_BASE_API + 'file/upload',
headers: {
token: getToken()
},
urls: [],
uploadDomId: Math.random(),
fileList: []
}
},
watch: {
value(newValue) {
this.renderFile()
}
},
created() {
if (this.externalId) {
this.$get('file/files', { externalId: this.externalId, externalType: this.externalType }).then(res => {
const { data } = res
this.fileList = data
})
this.action = this.action + `?externalId=${this.externalId}&externalType=${this.externalType}`
} else {
this.renderFile()
}
},
methods: {
renderFile() {
if (this.value instanceof Array && this.value.length > 0) {
this.fileList = this.value.map(it => {
return {
name: it.substring(it.lastIndexOf('/') + 1),
response: {
data: {
url: it
}
}
}
})
} else {
if (this.value) {
this.fileList.push({
name: this.value.substring(this.value.lastIndexOf('/') + 1),
response: {
data: {
url: this.value
}
}
})
}
}
},
handleRemove(file, fileList) {
var url = file.response.data.url
this.urls.splice(this.urls.indexOf(url), 1)
this.fileList.forEach((it, i) => {
if (it && it.response.data.url.indexOf(url) !== -1) {
this.fileList.splice(i, 1)
}
})
if (this.multiple) {
this.$emit('update:value', this.urls)
this.$emit('change', this.urls)
} else {
document.getElementById(this.uploadDomId).getElementsByClassName('el-upload__input')[0].removeAttribute('disabled')
this.$emit('update:value', '')
this.$emit('change', '')
}
this.$get('file/delete', { url: encodeURI(url) })
},
handlePreview(file) {
window.open(this.$filePrefix + file.response.data.url)
},
handleExceed(files, fileList) {
this.$message.warning(`当前限制选择 ${this.limit} 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`)
},
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${file.name}`)
},
handleAvatarSuccess(res, file, fileList) {
if (res.data) {
if (this.multiple) {
this.urls.push(res.data.url)
this.$emit('update:value', this.urls)
this.$emit('change', this.urls)
} else {
document.getElementById(this.uploadDomId).getElementsByClassName('el-upload__input')[0].setAttribute('disabled', '')
this.$emit('update:value', res.data.url)
this.$emit('change', res.data.url)
}
}
},
getSettingSuffixs() {
if (this.formats) {
return this.formats
}
var suffixs = this.acceptList[this.accept]
if (!suffixs) {
suffixs = this.getAllSuffixs()
}
return suffixs
},
beforeAvatarUpload(file, fileList) {
var fileName = file.name
var accepts = this.accept.split(',')
if (accepts) {
for (var i = 0; i < accepts.length; i++) {
if (!this.validAccept(fileName, accepts[i])) {
this.$message.error('上传文件格式只能为:' + this.getSettingSuffixs().replaceAll(',', ''))
return false
}
}
} else {
if (!this.validAccept(fileName, 'null')) {
this.$message.error('上传文件格式只能为:' + this.getAllSuffixs().replaceAll(',', ''))
return false
}
}
const isLt2M = file.size / 1024 / 1024 < this.maxFileSize
if (!isLt2M) {
this.$message.error(`上传文件大小不能超过 ${this.maxFileSize}MB`)
return isLt2M
}
},
getAllSuffixs() {
var suffixs = ''
for (const key in this.acceptList) {
suffixs += this.acceptList[key] + ','
}
suffixs = suffixs.substring(0, suffixs.length - 1)
return suffixs
},
validAccept(fileName, accept) {
if (this.formats) {
return this.validEndsWith(fileName, this.formats)
}
if (accept && this.acceptList[accept]) {
return this.validEndsWith(fileName, this.acceptList[accept])
} else {
return this.validEndsWith(fileName, this.getAllSuffixs())
}
},
validEndsWith(fileName, suffixs) {
suffixs = suffixs.split(',')
for (var i = 0; i < suffixs.length; i++) {
const suffix = suffixs[i]
if (fileName.toLowerCase().endsWith('.' + suffix)) {
return true
}
}
return false
}
}
}
</script>
<style>
</style>
@@ -1,358 +0,0 @@
<template>
<div>
<vuedraggable
v-model="urls"
class="vue-draggable"
tag="div"
draggable=".draggable-item"
@end="onDragEnd"
>
<div
v-for="(url, index) in urls"
:key="index"
class="draggable-item"
:style="{ width: width.replace('px', '') + 'px', height: height.replace('px', '') + 'px' }"
>
<el-image
:src="$filePrefix + url"
:preview-src-list="[$filePrefix + url]"
/>
<div class="tools">
<div class="shadow" @click="handleRemove(url)">
<i class="el-icon-delete" />
</div>
<div class="shadow" @click="beforeCropper(url)">
<i class="el-icon-scissors" />
</div>
</div>
</div>
<el-upload
v-if="(!multiple && urls.length == 0) || (multiple && urls.length < limit)"
slot="footer"
ref="uploadRef"
class="uploadBox"
:style="{ width: width.replace('px', '') + 'px', height: height.replace('px', '') + 'px' }"
:action="action"
:file-list="fileList"
:headers="headers"
accept=".jpg,.jpeg,.png,.gif"
:show-file-list="false"
:multiple="multiple"
:limit="limit"
:on-success="handleAvatarSuccess"
:on-exceed="onExceed"
>
<i class="el-icon-plus uploadIcon">
<span v-show="isUploading" class="uploading">正在上传...</span>
<span
v-if="!isUploading && limit && limit!==99 && multiple"
class="limitTxt"
>最多{{ limit }}</span>
</i>
</el-upload>
</vuedraggable>
<mb-dialog ref="cropperDialog" @confirm-click="cropper">
<template #content>
<div class="cropper-content">
<div class="cropper" style="text-align:center">
<vue-cropper
ref="cropper"
v-bind="cropperOption"
:output-size="cropperOption.outputSize === undefined ? 0.8 : cropperOption.outputSize"
:output-type="cropperOption.outputType === undefined ? 'jpeg' : cropperOption.outputType"
:can-move="cropperOption.canMove === undefined ? true : cropperOption.canMove"
:can-move-box="cropperOption.canMoveBox === undefined ? true : cropperOption.canMoveBox"
:auto-crop="cropperOption.autoCrop === undefined ? true : cropperOption.autoCrop"
:center-box="cropperOption.centerBox === undefined ? true : cropperOption.centerBox"
/>
</div>
</div>
</template>
</mb-dialog>
</div>
</template>
<script>
import { VueCropper } from 'vue-cropper'
import vuedraggable from 'vuedraggable'
import { getToken } from '@/scripts/auth'
export default {
name: 'MbUploadImage',
components: { vuedraggable, VueCropper },
model: {
prop: 'value',
event: 'change'
},
props: {
value: {
required: false
},
externalId: {
type: String,
default: ''
},
externalType: {
type: String,
default: ''
},
multiple: {
type: Boolean,
default: false
},
limit: {
type: Number,
default: 2
},
cropperConfig: {
type: Object,
default: () => {}
},
width: {
type: String,
default: '100'
},
height: {
type: String,
default: '100'
}
},
data() {
return {
action: process.env.VUE_APP_BASE_API + 'file/upload',
headers: {
token: getToken()
},
dialogImageUrl: '',
dialogVisible: false,
disabled: false,
isUploading: false,
cropperOption: {},
urls: [],
fileList: []
}
},
watch: {
value(newValue) {
if (newValue instanceof Array) {
this.urls = newValue
this.fileList = this.urls.map(it => { return { response: { data: { url: it }}} })
} else {
if (newValue && this.urls.length === 0) {
this.urls.push(newValue)
}
}
}
},
created() {
this.cropperOption = this.cropperConfig || {}
this.cropperOption.img = ''
if (this.externalId) {
this.$get('file/files', { externalId: this.externalId, externalType: this.externalType }).then(res => {
this.urls = res.data
})
this.action = this.action + `?externalId=${this.externalId}&externalType=${this.externalType}`
} else {
if (this.value instanceof Array) {
this.urls = this.value
this.fileList = this.urls.map(it => { return { response: { data: { url: it }}} })
} else {
if (this.value) {
this.urls.push(this.value)
}
}
}
},
methods: {
handleRemove(url) {
this.urls.splice(this.urls.indexOf(url), 1)
this.fileList.forEach((it, i) => {
if (it && it.response.data.url.indexOf(url) !== -1) {
this.fileList.splice(i, 1)
}
})
this.$get('file/delete', { url: encodeURI(url) })
if (this.multiple) {
this.$emit('update:value', this.urls)
this.$emit('change', this.urls)
} else {
this.$emit('update:value', '')
this.$emit('change', '')
}
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url
this.dialogVisible = true
},
handleDownload(file) {
console.log(file)
},
handleAvatarSuccess(res, file, fileList) {
this.fileList = fileList
if (res.data) {
this.urls.push(res.data.url)
if (this.multiple) {
this.$emit('update:value', this.urls)
this.$emit('change', this.urls)
} else {
this.$emit('update:value', res.data.url)
this.$emit('change', res.data.url)
}
this.onDragEnd()
} else {
this.$message({ type: 'error', message: res.msg })
}
this.isUploading = false
},
onDragEnd() {
var newUrls = []
this.urls.forEach(url => {
newUrls.push(encodeURI(url))
})
this.$get('file/resort', { urls: newUrls.join(',') })
},
onExceed() {
this.$message({
type: 'warning',
message: `图片超限,最多可上传${this.limit}张图片`
})
},
beforeCropper(url) {
this.cropperOption.img = this.$filePrefix + url
this.cropperOption.relativeImg = url
this.$refs.cropperDialog.show()
},
cropper() {
this.$refs.cropper.getCropBlob((data) => {
var dataFile = new File([data], this.cropperOption.relativeImg.substring(this.cropperOption.relativeImg.lastIndexOf('/') + 1), { type: data.type, lastModified: Date.now() })
var formData = new FormData()
formData.append('file', dataFile)
formData.append('url', encodeURI(this.cropperOption.relativeImg))
this.$request({
url: 'file/cropper',
method: 'post',
data: formData
}).then(res => {
this.urls.forEach((it, i) => {
if (this.cropperOption.img.indexOf(it) !== -1) {
this.$set(this.urls, i, res.data.url)
this.$refs.cropperDialog.hide()
}
})
})
})
}
}
}
</script>
<style scoped>
.vue-draggable >>> .el-upload {
width: 100%;
height: 100%;
}
</style>
<style lang="scss" scoped>
// 上传按钮
.uploadIcon {
width: 100%;
height: 100%;
position: relative;
display: flex;
align-items: center;
justify-content: center;
border: 1px dashed #c0ccda;
background-color: #fbfdff;
border-radius: 6px;
font-size: 20px;
color: #999;
.limitTxt,
.uploading {
position: absolute;
bottom: 10%;
left: 0;
width: 100%;
font-size: 14px;
text-align: center;
}
}
// 拖拽
.vue-draggable {
display: flex;
flex-wrap: wrap;
.draggable-item {
margin-right: 5px;
margin-bottom: 5px;
border: 1px solid #ddd;
border-radius: 6px;
position: relative;
overflow: hidden;
.el-image {
width: 100%;
height: 100%;
}
.tools {
position: absolute;
top:0px;
width: 100%;
height: 20px;
}
.shadow {
display: inline-block;
background-color: rgba(0,0,0,.5);
opacity: 0;
transition: opacity .3s;
color: #fff;
font-size: 20px;
line-height: 20px;
padding: 2px;
cursor: pointer;
}
&:hover {
.shadow {
opacity: 1;
}
}
}
&.hideShadow {
.shadow {
display: none;
}
}
&.single {
overflow: hidden;
position: relative;
.draggable-item {
position: absolute;
left: 0;
top: 0;
z-index: 1;
}
}
&.maxHidden {
.uploadBox {
display: none;
}
}
}
// el-image
.el-image-viewer__wrapper {
.el-image-viewer__mask {
opacity: .8;
}
.el-icon-circle-close {
color: #fff;
}
}
.cropper-content {
.cropper {
width: auto;
height: 300px;
}
}
</style>
@@ -1,101 +0,0 @@
<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"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template>
<script>
import { scrollTo } from '@/scripts/scroll-to'
export default {
name: 'Pagination',
props: {
total: {
required: true,
type: Number
},
page: {
type: Number,
default: 1
},
limit: {
type: Number,
default: 10
},
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>
@@ -1,145 +0,0 @@
<template>
<div ref="rightPanel" :class="{show:show}" class="rightPanel-container">
<div class="rightPanel-background" />
<div class="rightPanel">
<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 '@/scripts'
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>
@@ -1,60 +0,0 @@
<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>
@@ -1,62 +0,0 @@
<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 :href="iconName" />
</svg>
</template>
<script>
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
import { isExternal } from '@/scripts/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>
@@ -1,175 +0,0 @@
<template>
<el-color-picker
v-model="theme"
:predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</template>
<script>
const version = require('element-ui/package.json').version // element-ui version from node_modules
const ORIGINAL_THEME = '#409EFF' // default color
export default {
data() {
return {
chalk: '', // content of theme-chalk css
theme: ''
}
},
computed: {
defaultTheme() {
return this.$store.state.settings.theme
}
},
watch: {
defaultTheme: {
handler: function(val, oldVal) {
this.theme = val
},
immediate: true
},
async theme(val) {
const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
if (typeof val !== 'string') return
const themeCluster = this.getThemeCluster(val.replace('#', ''))
const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
console.log(themeCluster, originalCluster)
const $message = this.$message({
message: ' Compiling the theme',
customClass: 'theme-message',
type: 'success',
duration: 0,
iconClass: 'el-icon-loading'
})
const getHandler = (variable, id) => {
return () => {
const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster)
let styleTag = document.getElementById(id)
if (!styleTag) {
styleTag = document.createElement('style')
styleTag.setAttribute('id', id)
document.head.appendChild(styleTag)
}
styleTag.innerText = newStyle
}
}
if (!this.chalk) {
const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
await this.getCSSString(url, 'chalk')
}
const chalkHandler = getHandler('chalk', 'chalk-style')
chalkHandler()
const styles = [].slice.call(document.querySelectorAll('style'))
.filter(style => {
const text = style.innerText
return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
})
styles.forEach(style => {
const { innerText } = style
if (typeof innerText !== 'string') return
style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
})
this.$emit('change', val)
$message.close()
}
},
methods: {
updateStyle(style, oldCluster, newCluster) {
let newStyle = style
oldCluster.forEach((color, index) => {
newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
})
return newStyle
},
getCSSString(url, variable) {
return new Promise(resolve => {
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
resolve()
}
}
xhr.open('GET', url)
xhr.send()
})
},
getThemeCluster(theme) {
const tintColor = (color, tint) => {
let red = parseInt(color.slice(0, 2), 16)
let green = parseInt(color.slice(2, 4), 16)
let blue = parseInt(color.slice(4, 6), 16)
if (tint === 0) { // when primary color is in its rgb space
return [red, green, blue].join(',')
} else {
red += Math.round(tint * (255 - red))
green += Math.round(tint * (255 - green))
blue += Math.round(tint * (255 - blue))
red = red.toString(16)
green = green.toString(16)
blue = blue.toString(16)
return `#${red}${green}${blue}`
}
}
const shadeColor = (color, shade) => {
let red = parseInt(color.slice(0, 2), 16)
let green = parseInt(color.slice(2, 4), 16)
let blue = parseInt(color.slice(4, 6), 16)
red = Math.round((1 - shade) * red)
green = Math.round((1 - shade) * green)
blue = Math.round((1 - shade) * blue)
red = red.toString(16)
green = green.toString(16)
blue = blue.toString(16)
return `#${red}${green}${blue}`
}
const clusters = [theme]
for (let i = 0; i <= 9; i++) {
clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
}
clusters.push(shadeColor(theme, 0.1))
return clusters
}
}
}
</script>
<style>
.theme-message,
.theme-picker-dropdown {
z-index: 99999 !important;
}
.theme-picker .el-color-picker__trigger {
height: 26px !important;
width: 26px !important;
padding: 2px;
}
.theme-picker-dropdown .el-color-dropdown__link-btn {
display: none;
}
</style>
@@ -1,77 +0,0 @@
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
}
}
}
}
@@ -1,13 +0,0 @@
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
@@ -1,13 +0,0 @@
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
@@ -1,26 +0,0 @@
.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;
}
@@ -1,72 +0,0 @@
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]
}
}
-9
View File
@@ -1,9 +0,0 @@
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)
-1
View File
@@ -1 +0,0 @@
<?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="1641017183540" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5317" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M259.2 0H896a64 64 0 0 1 64 64v748.608a64 64 0 0 1-64 64H259.2a64 64 0 0 1-64-64V64a64 64 0 0 1 64-64z m132.8 183.04V640h171.264c76.096 0 133.12-20.48 172.544-61.44 37.376-39.04 56.384-94.72 56.384-167.04 0-72.96-19.008-128.64-56.384-167.04-39.36-40.96-96.448-61.44-172.544-61.44H392z m76.8 64h80c58.432 0 101.056 12.8 128 39.04 26.24 25.6 39.296 67.84 39.296 125.44 0 56.32-13.12 97.92-39.36 124.8-26.88 26.24-69.504 39.68-127.936 39.68h-80V247.04zM64 384h75.968v568.512h580.096V1024H128a64 64 0 0 1-64-64V384z" p-id="5318"></path></svg>

Before

Width:  |  Height:  |  Size: 915 B

-1
View File
@@ -1 +0,0 @@
<?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="1641017365938" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6713" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M922.317764 0H101.64469A100.312307 100.312307 0 0 0 1.634036 100.010654V923.989346a100.312307 100.312307 0 0 0 100.010654 100.010654h820.673074a100.299739 100.299739 0 0 0 99.998085-100.010654V100.06093A100.299739 100.299739 0 0 0 922.317764 0zM427.933063 402.04107l-177.321894 103.064894 177.321894 97.094672v81.257871L179.684925 534.831388v-57.477532l248.248138-160.529857z m70.938812 364.661192h-53.970812l78.643542-509.303973h53.958243z m345.393085-231.845736L596.004253 683.445938v-81.257871l177.321894-97.094672-177.321894-103.064894v-85.217071l248.260707 160.542426z" p-id="6714"></path></svg>

Before

Width:  |  Height:  |  Size: 977 B

-1
View File
@@ -1 +0,0 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="128" height="128"><defs><style/></defs><path d="M512 128q69.675 0 135.51 21.163t115.498 54.997 93.483 74.837 73.685 82.006 51.67 74.837 32.17 54.827L1024 512q-2.347 4.992-6.315 13.483T998.87 560.17t-31.658 51.669-44.331 59.99-56.832 64.34-69.504 60.16-82.347 51.5-94.848 34.687T512 896q-69.675 0-135.51-21.163t-115.498-54.826-93.483-74.326-73.685-81.493-51.67-74.496-32.17-54.997L0 513.707q2.347-4.992 6.315-13.483t18.816-34.816 31.658-51.84 44.331-60.33 56.832-64.683 69.504-60.331 82.347-51.84 94.848-34.816T512 128.085zm0 85.333q-46.677 0-91.648 12.331t-81.152 31.83-70.656 47.146-59.648 54.485-48.853 57.686-37.675 52.821-26.325 43.99q12.33 21.674 26.325 43.52t37.675 52.351 48.853 57.003 59.648 53.845T339.2 767.02t81.152 31.488T512 810.667t91.648-12.331 81.152-31.659 70.656-46.848 59.648-54.186 48.853-57.344 37.675-52.651T927.957 512q-12.33-21.675-26.325-43.648t-37.675-52.65-48.853-57.345-59.648-54.186-70.656-46.848-81.152-31.659T512 213.334zm0 128q70.656 0 120.661 50.006T682.667 512 632.66 632.661 512 682.667 391.339 632.66 341.333 512t50.006-120.661T512 341.333zm0 85.334q-35.328 0-60.33 25.002T426.666 512t25.002 60.33T512 597.334t60.33-25.002T597.334 512t-25.002-60.33T512 426.666z"/></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

-1
View File
@@ -1 +0,0 @@
<svg width="128" height="64" xmlns="http://www.w3.org/2000/svg"><path d="M127.072 7.994c1.37-2.208.914-5.152-.914-6.87-2.056-1.717-4.797-1.226-6.396.982-.229.245-25.586 32.382-55.74 32.382-29.24 0-55.74-32.382-55.968-32.627-1.6-1.963-4.57-2.208-6.397-.49C-.17 3.086-.399 6.275 1.2 8.238c.457.736 5.94 7.36 14.62 14.72L4.17 35.96c-1.828 1.963-1.6 5.152.228 6.87.457.98 1.6 1.471 2.742 1.471s2.284-.49 3.198-1.472l12.564-13.983c5.94 4.416 13.021 8.587 20.788 11.53l-4.797 17.418c-.685 2.699.686 5.397 3.198 6.133h1.37c2.057 0 3.884-1.472 4.341-3.68L52.6 42.83c3.655.736 7.538 1.227 11.422 1.227 3.883 0 7.767-.49 11.422-1.227l4.797 17.173c.457 2.208 2.513 3.68 4.34 3.68.457 0 .914 0 1.143-.246 2.513-.736 3.883-3.434 3.198-6.133l-4.797-17.172c7.767-2.944 14.848-7.114 20.788-11.53l12.336 13.738c.913.981 2.056 1.472 3.198 1.472s2.284-.49 3.198-1.472c1.828-1.963 1.828-4.906.228-6.87l-11.65-13.001c9.366-7.36 14.849-14.474 14.849-14.474z"/></svg>

Before

Width:  |  Height:  |  Size: 944 B

@@ -1 +0,0 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M38.47 52L52 38.462l-23.648-23.67L43.209 0H.035L0 43.137l14.757-14.865L38.47 52zm74.773 47.726L89.526 76 76 89.536l23.648 23.672L84.795 128h43.174L128 84.863l-14.757 14.863zM89.538 52l23.668-23.648L128 43.207V.038L84.866 0 99.73 14.76 76 38.472 89.538 52zM38.46 76L14.792 99.651 0 84.794v43.173l43.137.033-14.865-14.757L52 89.53 38.46 76z"/></svg>

Before

Width:  |  Height:  |  Size: 421 B

-1
View File
@@ -1 +0,0 @@
<?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="1641017648725" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="19289" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M555.541333 117.994667l312.874667 224.565333A117.333333 117.333333 0 0 1 917.333333 437.866667V800c0 64.8-52.533333 117.333333-117.333333 117.333333H640V746.666667c0-70.688-57.312-128-128-128s-128 57.312-128 128v170.666666H224c-64.8 0-117.333333-52.533333-117.333333-117.333333V437.877333a117.333333 117.333333 0 0 1 48.917333-95.317333l312.874667-224.565333a74.666667 74.666667 0 0 1 87.082666 0z" p-id="19290"></path></svg>

Before

Width:  |  Height:  |  Size: 803 B

-1
View File
@@ -1 +0,0 @@
<?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="1641017024921" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2935" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M892.928 128q28.672 0 48.64 19.968t19.968 48.64l0 52.224q0 28.672-19.968 48.64t-48.64 19.968l-759.808 0q-28.672 0-48.64-19.968t-19.968-48.64l0-52.224q0-28.672 19.968-48.64t48.64-19.968l759.808 0zM892.928 448.512q28.672 0 48.64 19.968t19.968 48.64l0 52.224q0 28.672-19.968 48.64t-48.64 19.968l-759.808 0q-28.672 0-48.64-19.968t-19.968-48.64l0-52.224q0-28.672 19.968-48.64t48.64-19.968l759.808 0zM892.928 769.024q28.672 0 48.64 19.968t19.968 48.64l0 52.224q0 28.672-19.968 48.64t-48.64 19.968l-759.808 0q-28.672 0-48.64-19.968t-19.968-48.64l0-52.224q0-28.672 19.968-48.64t48.64-19.968l759.808 0z" p-id="2936"></path></svg>

Before

Width:  |  Height:  |  Size: 997 B

-1
View File
@@ -1 +0,0 @@
<?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="1641720023979" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15481" width="240" height="240" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M960 1024h-320v-384h128V576H256v64h128v384H0v-384h128V448h320V384H320V0h384v384H576v64h320v192h128v384h-64zM128 896h128v-128H128v128zM576 128H448v128h128V128z m320 640h-128v128h128v-128z" p-id="15482"></path></svg>

Before

Width:  |  Height:  |  Size: 592 B

-1
View File
@@ -1 +0,0 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M108.8 44.322H89.6v-5.36c0-9.04-3.308-24.163-25.6-24.163-23.145 0-25.6 16.881-25.6 24.162v5.361H19.2v-5.36C19.2 15.281 36.798 0 64 0c27.202 0 44.8 15.281 44.8 38.961v5.361zm-32 39.356c0-5.44-5.763-9.832-12.8-9.832-7.037 0-12.8 4.392-12.8 9.832 0 3.682 2.567 6.808 6.407 8.477v11.205c0 2.718 2.875 4.962 6.4 4.962 3.524 0 6.4-2.244 6.4-4.962V92.155c3.833-1.669 6.393-4.795 6.393-8.477zM128 64v49.201c0 8.158-8.645 14.799-19.2 14.799H19.2C8.651 128 0 121.359 0 113.201V64c0-8.153 8.645-14.799 19.2-14.799h89.6c10.555 0 19.2 6.646 19.2 14.799z"/></svg>

Before

Width:  |  Height:  |  Size: 623 B

-1
View File
@@ -1 +0,0 @@
<?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="1641017706517" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="20110" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M792.703177 534.452774c-49.288352 33.217439-108.257215 52.515189-171.718341 52.515189-63.271312 0-122.050361-19.171208-171.1489-52.135561-132.996298 65.042909-224.866244 203.290726-224.866244 363.303875 0 169.314031 793.232441 166.972993 793.232441 0C1018.138862 737.7435 926.079103 599.305869 792.703177 534.452774L792.703177 534.452774 792.703177 534.452774zM354.359526 270.99103c0-149.636653 119.329695-270.99103 266.62531-270.99103 147.295615 0 266.62531 121.291105 266.62531 270.99103 0 149.636653-119.329695 270.864488-266.62531 270.864488C473.68922 541.855518 354.359526 420.627684 354.359526 270.99103L354.359526 270.99103 354.359526 270.99103 354.359526 270.99103zM177.959107 912.182508c0 6.200589 0.94907 12.084821 2.783938 17.905781C80.584558 913.827562 5.797867 881.749007 5.797867 833.409724c0-138.500902 79.468768-258.146954 194.622556-314.458422 40.177283 27.01685 88.010395 43.340849 139.576515 45.049174C241.040605 646.696082 177.959107 771.97328 177.959107 912.182508L177.959107 912.182508 177.959107 912.182508zM310.006336 270.99103c0-68.775916 21.638789-132.426856 58.399421-184.309332C361.952083 86.112256 355.561681 85.859171 349.108007 85.859171c-121.227834 0-219.488182 99.842131-219.488182 223.031376s98.197077 223.031376 219.424911 223.031376c27.269936 0 53.400988-5.061705 77.444086-14.362588C355.498409 459.666083 310.006336 370.76989 310.006336 270.99103L310.006336 270.99103zM310.006336 270.99103" p-id="20111"></path></svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

-1
View File
@@ -1 +0,0 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M124.884 109.812L94.256 79.166c-.357-.357-.757-.629-1.129-.914a50.366 50.366 0 0 0 8.186-27.59C101.327 22.689 78.656 0 50.67 0 22.685 0 0 22.688 0 50.663c0 27.989 22.685 50.663 50.656 50.663 10.186 0 19.643-3.03 27.6-8.201.286.385.557.771.9 1.114l30.628 30.632a10.633 10.633 0 0 0 7.543 3.129c2.728 0 5.457-1.043 7.543-3.115 4.171-4.157 4.171-10.915.014-15.073M50.671 85.338C31.557 85.338 16 69.78 16 50.663c0-19.102 15.557-34.661 34.67-34.661 19.115 0 34.657 15.559 34.657 34.675 0 19.102-15.557 34.661-34.656 34.661"/></svg>

Before

Width:  |  Height:  |  Size: 600 B

-1
View File
@@ -1 +0,0 @@
<?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="1641015979047" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2139" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M519.9 647.4c-44.8 7.4-90.4-6.9-122.5-38.3-32.1-31.4-46.6-76.2-39-120 9.4-56.8 56.2-102.7 114.2-112.1 44.9-7.6 90.7 6.7 122.9 38.2 32.2 31.6 46.7 76.5 38.9 120.4-9.7 56.9-56.5 102.6-114.5 111.8M848.4 559l66-40.4c10.5-6.4 15.6-18.6 12.9-30.4L895 349.3c-2.7-11.8-12.8-20.6-25.1-21.9l-77.5-8.4c-7.7-0.8-14.7-4.6-19.5-10.5l-13-16c-4.8-5.9-7-13.5-6.1-21l8.9-75.7c1.4-12-5.1-23.6-16.2-28.9l-131-61.8c-11.1-5.2-24.4-3-33.2 5.5l-55 54c-5.4 5.3-12.8 8.4-20.6 8.4H486c-7.7 0-15.1-3-20.6-8.4l-55-54c-8.7-8.6-22-10.8-33.2-5.5l-130.9 61.8c-11.1 5.3-17.6 16.8-16.2 28.9l8.9 75.8c0.9 7.5-1.3 15-6.1 21L220 308.4c-4.8 5.9-11.8 9.7-19.5 10.5l-77.5 8.5c-12.3 1.3-22.3 10.1-25.1 21.9L65.5 488.1c-2.7 11.8 2.4 24 12.9 30.4l66 40.5c6.5 4 11.2 10.4 12.9 17.8l4.6 19.9c1.7 7.4 0.4 15.1-3.7 21.5l-41.6 64.5c-6.6 10.2-5.8 23.4 1.9 32.9l90.7 111.3c7.7 9.5 20.7 13.1 32.3 9.1l73.5-25.3c7.3-2.5 15.3-2.1 22.2 1.2l18.7 8.8c7 3.3 12.3 9.1 14.8 16.3l25.6 72c4.1 11.4 15.1 19.1 27.4 19.1H569c12.4 0 23.4-7.7 27.4-19.1l25.6-72c2.5-7.1 7.9-13 14.8-16.3l18.7-8.8c6.9-3.3 14.9-3.7 22.2-1.2l73.5 25.3c11.7 4 24.6 0.4 32.3-9.1l90.7-111.3c7.7-9.5 8.4-22.7 1.9-32.9l-41.6-64.5c-4.1-6.4-5.5-14.1-3.8-21.5l4.6-19.8c1.9-7.5 6.5-13.9 13.1-17.9" fill="" p-id="2140"></path></svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

-1
View File
@@ -1 +0,0 @@
<svg width="130" height="130" xmlns="http://www.w3.org/2000/svg"><path d="M63.444 64.996c20.633 0 37.359-14.308 37.359-31.953 0-17.649-16.726-31.952-37.359-31.952-20.631 0-37.36 14.303-37.358 31.952 0 17.645 16.727 31.953 37.359 31.953zM80.57 75.65H49.434c-26.652 0-48.26 18.477-48.26 41.27v2.664c0 9.316 21.608 9.325 48.26 9.325H80.57c26.649 0 48.256-.344 48.256-9.325v-2.663c0-22.794-21.605-41.271-48.256-41.271z" stroke="#979797"/></svg>

Before

Width:  |  Height:  |  Size: 440 B

-22
View File
@@ -1,22 +0,0 @@
# 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'
-51
View File
@@ -1,51 +0,0 @@
[{
"id": 1,
"name": "1",
"pid": 0,
"level": 0
}, {
"id": 2,
"name": "2",
"pid": 0,
"level": 0
}, {
"id": 3,
"name": "1-1",
"pid": 1,
"level": 1
}, {
"id": 4,
"name": "1-2",
"pid": 1,
"level": 1
}, {
"id": 5,
"name": "2-1",
"pid": 2,
"level": 1
}, {
"id": 6,
"name": "2-2",
"pid": 2,
"level": 1
}, {
"id": 7,
"name": "1-1-3-1",
"pid": 3,
"level": 2
}, {
"id": 8,
"name": "1-1-3-2",
"pid": 3,
"level": 2
}, {
"id": 9,
"name": "1-2-3-1",
"pid": 4,
"level": 2
}, {
"id": 10,
"name": "1-2-3-2",
"pid": 4,
"level": 2
}]
@@ -1,55 +0,0 @@
<template>
<section class="app-main">
<keep-alive>
<router-view v-if="$route.meta.keepAlive" :key="key" />
</keep-alive>
<router-view v-if="!$route.meta.keepAlive" :key="key" />
</section>
</template>
<script>
export default {
name: 'AppMain',
computed: {
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: auto;
background: #F0F2F5;
}
.fixed-header+.app-main {
padding-top: 50px;
}
.hasTagsView {
.app-main {
/* 84 = navbar + tags-view = 50 + 34 */
min-height: calc(100vh - 84px);
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>
@@ -1,154 +0,0 @@
<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" />
</template>
<el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
<div class="avatar-wrapper">
<img :src="$store.getters.userInfo.headPortrait ? $filePrefix + $store.getters.userInfo.headPortrait : require('@/assets/magic-boot.png')" style="width: 28px; height: 28px" class="user-avatar">
<span style="font-size: 14px">{{ $store.getters.username }}({{ $store.getters.name }})</span>
<i class="el-icon-caret-bottom" />
</div>
<el-dropdown-menu slot="dropdown">
<router-link to="/">
<el-dropdown-item>首页</el-dropdown-item>
</router-link>
<router-link to="/user-center">
<el-dropdown-item>个人中心</el-dropdown-item>
</router-link>
<el-dropdown-item divided @click.native="logout">
<span style="display:block;">退出</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'
import Screenfull from '@/components/Screenfull'
import Search from '@/components/HeaderSearch'
export default {
components: {
Breadcrumb,
Hamburger,
ErrorLog,
Screenfull,
Search
},
computed: {
...mapGetters([
'sidebar',
'avatar',
'device'
])
},
methods: {
toggleSideBar() {
this.$store.dispatch('app/toggleSideBar')
},
async logout() {
await this.$store.dispatch('user/logout')
location.reload()
}
}
}
</script>
<style lang="scss" scoped>
.navbar {
height: 50px;
overflow: hidden;
position: relative;
background: #fff;
box-shadow: 0 1px 4px rgba(0,21,41,.08);
.hamburger-container {
line-height: 46px;
height: 100%;
float: left;
cursor: pointer;
transition: background .3s;
-webkit-tap-highlight-color:transparent;
&:hover {
background: rgba(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 .3s;
&:hover {
background: rgba(0, 0, 0, .025)
}
}
}
.avatar-container {
margin-right: 30px;
.avatar-wrapper {
position: relative;
.user-avatar {
cursor: pointer;
border-radius: 10px;
vertical-align: middle;
}
.el-icon-caret-bottom {
cursor: pointer;
position: absolute;
right: -20px;
top: 25px;
font-size: 12px;
}
}
}
}
}
</style>
@@ -1,108 +0,0 @@
<template>
<div class="drawer-container">
<div>
<h3 class="drawer-title">Page style setting</h3>
<div class="drawer-item">
<span>Theme Color</span>
<theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
</div>
<div class="drawer-item">
<span>Open Tags-View</span>
<el-switch v-model="tagsView" class="drawer-switch" />
</div>
<div class="drawer-item">
<span>Fixed Header</span>
<el-switch v-model="fixedHeader" class="drawer-switch" />
</div>
<div class="drawer-item">
<span>Sidebar Logo</span>
<el-switch v-model="sidebarLogo" class="drawer-switch" />
</div>
</div>
</div>
</template>
<script>
import ThemePicker from '@/components/ThemePicker'
export default {
components: { ThemePicker },
data() {
return {}
},
computed: {
fixedHeader: {
get() {
return this.$store.state.settings.fixedHeader
},
set(val) {
this.$store.dispatch('settings/changeSetting', {
key: 'fixedHeader',
value: val
})
}
},
tagsView: {
get() {
return this.$store.state.settings.tagsView
},
set(val) {
this.$store.dispatch('settings/changeSetting', {
key: 'tagsView',
value: val
})
}
},
sidebarLogo: {
get() {
return this.$store.state.settings.sidebarLogo
},
set(val) {
this.$store.dispatch('settings/changeSetting', {
key: 'sidebarLogo',
value: val
})
}
}
},
methods: {
themeChange(val) {
this.$store.dispatch('settings/changeSetting', {
key: 'theme',
value: val
})
}
}
}
</script>
<style lang="scss" scoped>
.drawer-container {
padding: 24px;
font-size: 14px;
line-height: 1.5;
word-wrap: break-word;
.drawer-title {
margin-bottom: 12px;
color: rgba(0, 0, 0, .85);
font-size: 14px;
line-height: 22px;
}
.drawer-item {
color: rgba(0, 0, 0, .65);
font-size: 14px;
padding: 12px 0;
}
.drawer-switch {
float: right
}
}
</style>
@@ -1,26 +0,0 @@
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)
}
}
}
}
}
@@ -1,29 +0,0 @@
<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>
@@ -1,36 +0,0 @@
<template>
<!-- eslint-disable vue/require-component-is -->
<component v-bind="linkProps(to)">
<slot />
</component>
</template>
<script>
import { isExternal } from '@/scripts/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>
@@ -1,82 +0,0 @@
<template>
<div class="sidebar-logo-container" :class="{'collapse':collapse}">
<transition name="sidebarLogoFade">
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
<img v-if="logo" :src="logo" class="sidebar-logo">
<h1 v-else class="sidebar-title">{{ title }} </h1>
</router-link>
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
<img v-if="logo" :src="logo" class="sidebar-logo">
<h1 class="sidebar-title">{{ title }} </h1>
</router-link>
</transition>
</div>
</template>
<script>
export default {
name: 'SidebarLogo',
props: {
collapse: {
type: Boolean,
required: true
}
},
data() {
return {
title: 'magic-booot',
logo: 'https://wpimg.wallstcn.com/69a1c46c-eb1c-4b46-8bd4-e9e686ef5251.png'
}
}
}
</script>
<style lang="scss" scoped>
.sidebarLogoFade-enter-active {
transition: opacity 1.5s;
}
.sidebarLogoFade-enter,
.sidebarLogoFade-leave-to {
opacity: 0;
}
.sidebar-logo-container {
position: relative;
width: 100%;
height: 50px;
line-height: 50px;
background: #2b2f3a;
text-align: center;
overflow: hidden;
& .sidebar-logo-link {
height: 100%;
width: 100%;
& .sidebar-logo {
width: 32px;
height: 32px;
vertical-align: middle;
margin-right: 12px;
}
& .sidebar-title {
display: inline-block;
margin: 0;
color: #fff;
font-weight: 600;
line-height: 50px;
font-size: 14px;
font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
vertical-align: middle;
}
}
&.collapse {
.sidebar-logo {
margin-right: 0px;
}
}
}
</style>
@@ -1,95 +0,0 @@
<template>
<div v-if="!item.hidden">
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
<item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" />
</el-menu-item>
</app-link>
</template>
<el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
<template slot="title">
<item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
</template>
<sidebar-item
v-for="child in item.children"
:key="child.path"
:is-nest="true"
:item="child"
:base-path="resolvePath(child.path)"
class="nest-menu"
/>
</el-submenu>
</div>
</template>
<script>
import path from 'path'
import { isExternal } from '@/scripts/validate'
import Item from './Item'
import AppLink from './Link'
import FixiOSBug from './FixiOSBug'
export default {
name: 'SidebarItem',
components: { Item, AppLink },
mixins: [FixiOSBug],
props: {
// route object
item: {
type: Object,
required: true
},
isNest: {
type: Boolean,
default: false
},
basePath: {
type: String,
default: ''
}
},
data() {
// To fix https://github.com/PanJiaChen/vue-admin-template/issues/237
// TODO: refactor with render function
this.onlyOneChild = null
return {}
},
methods: {
hasOneShowingChild(children = [], parent) {
const showingChildren = children.filter(item => {
if (item.hidden) {
return false
} else {
// Temp set(will be used if only has one showing child)
this.onlyOneChild = item
return true
}
})
// When there is only one child router, the child router is displayed by default
if (showingChildren.length === 1) {
return true
}
// Show parent if there are no child router to display
if (showingChildren.length === 0) {
this.onlyOneChild = { ... parent, path: '', noShowingChildren: true }
return true
}
return false
},
resolvePath(routePath) {
if (isExternal(routePath)) {
return routePath
}
if (isExternal(this.basePath)) {
return this.basePath
}
return path.resolve(this.basePath, routePath)
}
}
}
</script>
@@ -1,84 +0,0 @@
<template>
<div :class="{'has-logo':showLogo}">
<div class="logo-title">
<div v-if="!isCollapse" style="color: white">
Magic-Boot
</div>
<img v-if="isCollapse" src="@/assets/magic-boot.png" style="vertical-align: middle; width: 28px">
</div>
<logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
:default-active="activeMenu"
:collapse="isCollapse"
:background-color="variables.menuBg"
:text-color="variables.menuText"
:unique-opened="false"
:active-text-color="variables.menuActiveText"
:collapse-transition="false"
mode="vertical"
>
<sidebar-item v-for="(route,index) in permission_routes" :key="route.path + index" :item="route" :base-path="route.path" />
</el-menu>
</el-scrollbar>
</div>
</template>
<style scoped>
.el-scrollbar >>> .el-scrollbar__wrap{
height: calc(100% - 60px)
}
.logo-title {
color:white;
height: 60px;
font-size: 24px;
line-height: 60px;
text-align: center;
font-weight: 300;
box-shadow: 0px -1px 5px 0px #000;
z-index: 1;
position: relative;
font-family: PoetsenOne;
}
</style>
<script>
import { mapGetters } from 'vuex'
import Logo from './Logo'
import SidebarItem from './SidebarItem'
import variables from '@/styles/variables.scss'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
export default {
components: { SidebarItem, Logo },
computed: {
...mapGetters([
'permission_routes',
'sidebar'
]),
activeMenu() {
const route = this.$route
const { meta, path } = route
// if set path, the sidebar will highlight the path you set
if (meta.activeMenu) {
return meta.activeMenu
}
return path
},
showLogo() {
return this.$store.state.settings.sidebarLogo
},
variables() {
return variables
},
isCollapse() {
return !this.sidebar.opened
}
},
data() {
return {
menuTree: []
}
}
}
</script>
@@ -1,94 +0,0 @@
<template>
<el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.native.prevent="handleScroll">
<slot />
</el-scrollbar>
</template>
<script>
const tagAndTagSpacing = 4 // tagAndTagSpacing
export default {
name: 'ScrollPane',
data() {
return {
left: 0
}
},
computed: {
scrollWrapper() {
return this.$refs.scrollContainer.$refs.wrap
}
},
mounted() {
this.scrollWrapper.addEventListener('scroll', this.emitScroll, true)
},
beforeDestroy() {
this.scrollWrapper.removeEventListener('scroll', this.emitScroll)
},
methods: {
handleScroll(e) {
const eventDelta = e.wheelDelta || -e.deltaY * 40
const $scrollWrapper = this.scrollWrapper
$scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
},
emitScroll() {
this.$emit('scroll')
},
moveToTarget(currentTag) {
const $container = this.$refs.scrollContainer.$el
const $containerWidth = $container.offsetWidth
const $scrollWrapper = this.scrollWrapper
const tagList = this.$parent.$refs.tag
let firstTag = null
let lastTag = null
// find first tag and last tag
if (tagList.length > 0) {
firstTag = tagList[0]
lastTag = tagList[tagList.length - 1]
}
if (firstTag === currentTag) {
$scrollWrapper.scrollLeft = 0
} else if (lastTag === currentTag) {
$scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth
} else {
// find preTag and nextTag
const currentIndex = tagList.findIndex(item => item === currentTag)
const prevTag = tagList[currentIndex - 1]
const nextTag = tagList[currentIndex + 1]
// the tag's offsetLeft after of nextTag
const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing
// the tag's offsetLeft before of prevTag
const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing
if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
$scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
} else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
$scrollWrapper.scrollLeft = beforePrevTagOffsetLeft
}
}
}
}
}
</script>
<style lang="scss" scoped>
.scroll-container {
white-space: nowrap;
position: relative;
overflow: hidden;
width: 100%;
::v-deep {
.el-scrollbar__bar {
bottom: 0px;
}
.el-scrollbar__wrap {
height: 49px;
}
}
}
</style>
@@ -1,292 +0,0 @@
<template>
<div id="tags-view-container" class="tags-view-container">
<scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll">
<router-link
v-for="tag in visitedViews"
ref="tag"
:key="tag.path"
:class="isActive(tag)?'active':''"
:to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
tag="span"
class="tags-view-item"
@click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
@contextmenu.prevent.native="openMenu(tag,$event)"
>
{{ tag.title }}
<span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
</router-link>
</scroll-pane>
<ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
<li @click="refreshSelectedTag(selectedTag)">刷新</li>
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">关闭</li>
<li @click="closeOthersTags">关闭其他</li>
<li @click="closeAllTags(selectedTag)">关闭全部</li>
</ul>
</div>
</template>
<script>
import ScrollPane from './ScrollPane'
import path from 'path'
export default {
components: { ScrollPane },
data() {
return {
visible: false,
top: 0,
left: 0,
selectedTag: {},
affixTags: []
}
},
computed: {
visitedViews() {
return this.$store.state.tagsView.visitedViews
},
routes() {
return this.$store.state.permission.routes
}
},
watch: {
$route() {
this.addTags()
this.moveToCurrentTag()
},
visible(value) {
if (value) {
document.body.addEventListener('click', this.closeMenu)
} else {
document.body.removeEventListener('click', this.closeMenu)
}
}
},
mounted() {
this.initTags()
this.addTags()
},
methods: {
isActive(route) {
return route.path === this.$route.path
},
isAffix(tag) {
return tag.meta && tag.meta.affix
},
filterAffixTags(routes, basePath = '/') {
let tags = []
routes.forEach(route => {
if (route.meta && route.meta.affix) {
const tagPath = path.resolve(basePath, route.path)
tags.push({
fullPath: tagPath,
path: tagPath,
name: route.name,
meta: { ...route.meta }
})
}
if (route.children) {
const tempTags = this.filterAffixTags(route.children, route.path)
if (tempTags.length >= 1) {
tags = [...tags, ...tempTags]
}
}
})
return tags
},
initTags() {
const affixTags = this.affixTags = this.filterAffixTags(this.routes)
for (const tag of affixTags) {
// Must have tag name
if (tag.name) {
this.$store.dispatch('tagsView/addVisitedView', tag)
}
}
},
addTags() {
const { name } = this.$route
if (name) {
this.$store.dispatch('tagsView/addView', this.$route)
}
return false
},
moveToCurrentTag() {
const tags = this.$refs.tag
this.$nextTick(() => {
for (const tag of tags) {
if (tag.to.path === this.$route.path) {
this.$refs.scrollPane.moveToTarget(tag)
// when query is different then update
if (tag.to.fullPath !== this.$route.fullPath) {
this.$store.dispatch('tagsView/updateVisitedView', this.$route)
}
break
}
}
})
},
refreshSelectedTag(view) {
this.$store.dispatch('tagsView/delCachedView', view).then(() => {
const { fullPath } = view
this.$nextTick(() => {
this.$router.replace({
path: '/redirect' + fullPath
})
})
})
},
closeSelectedTag(view) {
this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => {
if (this.isActive(view)) {
this.toLastView(visitedViews, view)
}
})
},
closeOthersTags() {
this.$router.push(this.selectedTag)
this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {
this.moveToCurrentTag()
})
},
closeAllTags(view) {
this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => {
if (this.affixTags.some(tag => tag.path === view.path)) {
return
}
this.toLastView(visitedViews, view)
})
},
toLastView(visitedViews, view) {
const latestView = visitedViews.slice(-1)[0]
if (latestView) {
this.$router.push(latestView.fullPath)
} else {
// now the default is to redirect to the home page if there is no tags-view,
// you can adjust it according to your needs.
if (view.name === 'Dashboard') {
// to reload home page
this.$router.replace({ path: '/redirect' + view.fullPath })
} else {
this.$router.push('/')
}
}
},
openMenu(tag, e) {
const menuMinWidth = 105
const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
const offsetWidth = this.$el.offsetWidth // container width
const maxLeft = offsetWidth - menuMinWidth // left boundary
const left = e.clientX - offsetLeft + 15 // 15: margin right
if (left > maxLeft) {
this.left = maxLeft
} else {
this.left = left
}
this.top = e.clientY
this.visible = true
this.selectedTag = tag
},
closeMenu() {
this.visible = false
},
handleScroll() {
this.closeMenu()
}
}
}
</script>
<style lang="scss" scoped>
.tags-view-container {
height: 34px;
width: 100%;
background: #fff;
border-bottom: 1px solid #d8dce5;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);
.tags-view-wrapper {
.tags-view-item {
display: inline-block;
position: relative;
cursor: pointer;
height: 26px;
line-height: 26px;
border: 1px solid #d8dce5;
color: #495060;
background: #fff;
padding: 0 8px;
font-size: 12px;
margin-left: 5px;
margin-top: 4px;
&:first-of-type {
margin-left: 15px;
}
&:last-of-type {
margin-right: 15px;
}
&.active {
background-color: #42b983;
color: #fff;
border-color: #42b983;
&::before {
content: '';
background: #fff;
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
position: relative;
margin-right: 2px;
}
}
}
}
.contextmenu {
margin: 0;
background: #fff;
z-index: 3000;
position: absolute;
list-style-type: none;
padding: 5px 0;
border-radius: 4px;
font-size: 12px;
font-weight: 400;
color: #333;
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
li {
margin: 0;
padding: 7px 16px;
cursor: pointer;
&:hover {
background: #eee;
}
}
}
}
</style>
<style lang="scss">
//reset element css of el-icon-close
.tags-view-wrapper {
.tags-view-item {
.el-icon-close {
width: 16px;
height: 16px;
vertical-align: 2px;
border-radius: 50%;
text-align: center;
transition: all .3s cubic-bezier(.645, .045, .355, 1);
transform-origin: 100% 50%;
&:before {
transform: scale(.6);
display: inline-block;
vertical-align: -3px;
}
&:hover {
background-color: #b4bccc;
color: #fff;
}
}
}
}
</style>
@@ -1,5 +0,0 @@
export { default as Navbar } from './Navbar'
export { default as Sidebar } from './Sidebar'
export { default as AppMain } from './AppMain'
export { default as TagsView } from './TagsView/index.vue'
export { default as Settings } from './Settings'
-102
View File
@@ -1,102 +0,0 @@
<template>
<div :class="classObj" class="app-wrapper">
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
<sidebar class="sidebar-container" />
<div :class="{hasTagsView:needTagsView}" class="main-container">
<div :class="{'fixed-header':fixedHeader}">
<navbar />
<tags-view v-if="needTagsView" />
</div>
<app-main />
<right-panel v-if="showSettings">
<settings />
</right-panel>
</div>
</div>
</template>
<script>
import RightPanel from '@/components/RightPanel'
import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
import ResizeMixin from './mixin/ResizeHandler'
import { mapState } from 'vuex'
export default {
name: 'Layout',
components: {
AppMain,
Navbar,
RightPanel,
Settings,
Sidebar,
TagsView
},
mixins: [ResizeMixin],
computed: {
...mapState({
sidebar: state => state.app.sidebar,
device: state => state.app.device,
showSettings: state => state.settings.showSettings,
needTagsView: state => state.settings.tagsView,
fixedHeader: state => state.settings.fixedHeader
}),
classObj() {
return {
hideSidebar: !this.sidebar.opened,
openSidebar: this.sidebar.opened,
withoutAnimation: this.sidebar.withoutAnimation,
mobile: this.device === 'mobile'
}
}
},
methods: {
handleClickOutside() {
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
}
}
}
</script>
<style lang="scss" scoped>
@import "~@/styles/mixin.scss";
@import "~@/styles/variables.scss";
.app-wrapper {
@include clearfix;
position: relative;
height: 100%;
width: 100%;
&.mobile.openSidebar {
position: fixed;
top: 0;
}
}
.drawer-bg {
background: #000;
opacity: 0.3;
width: 100%;
top: 0;
height: 100%;
position: absolute;
z-index: 999;
}
.fixed-header {
position: fixed;
top: 0;
right: 0;
z-index: 9;
width: calc(100% - #{$sideBarWidth});
transition: width 0.28s;
}
.hideSidebar .fixed-header {
width: calc(100% - 54px)
}
.mobile .fixed-header {
width: 100%;
}
</style>
@@ -1,45 +0,0 @@
import store from '@/store'
const { body } = document
const WIDTH = 992 // refer to Bootstrap's responsive design
export default {
watch: {
$route(route) {
if (this.device === 'mobile' && this.sidebar.opened) {
store.dispatch('app/closeSideBar', { withoutAnimation: false })
}
}
},
beforeMount() {
window.addEventListener('resize', this.$_resizeHandler)
},
beforeDestroy() {
window.removeEventListener('resize', this.$_resizeHandler)
},
mounted() {
const isMobile = this.$_isMobile()
if (isMobile) {
store.dispatch('app/toggleDevice', 'mobile')
store.dispatch('app/closeSideBar', { withoutAnimation: true })
}
},
methods: {
// use $_ for mixins properties
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
$_isMobile() {
const rect = body.getBoundingClientRect()
return rect.width - 1 < WIDTH
},
$_resizeHandler() {
if (!document.hidden) {
const isMobile = this.$_isMobile()
store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop')
if (isMobile) {
store.dispatch('app/closeSideBar', { withoutAnimation: true })
}
}
}
}
}
-19
View File
@@ -1,19 +0,0 @@
<template>
<div>
<keep-alive>
<router-view v-if="$route.meta.keepAlive" :key="key" />
</keep-alive>
<router-view v-if="!$route.meta.keepAlive" :key="key" />
</div>
</template>
<script>
export default {
name: 'None',
computed: {
key() {
return this.$route.path
}
}
}
</script>
-94
View File
@@ -1,94 +0,0 @@
import Vue from 'vue'
import 'normalize.css/normalize.css' // A modern alternative to CSS resets
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import '@/styles/index.scss' // global css
import '@/styles/common.css'
import App from './App'
import store from './store'
import router from './router'
import '@/icons' // icon
import '@/permission' // permission control
import './scripts/error-log' // error log
import elDragDialog from '@/directive/el-drag-dialog' // base on element-ui
Vue.use(elDragDialog)
import common from '@/scripts/common'
Vue.prototype.$common = common
import treeTable from '@/scripts/treeTable'
Vue.prototype.$treeTable = treeTable
import request from '@/scripts/request'
Vue.prototype.$request = request
Vue.prototype.$post = (url, data) => request.post(url, data, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
transformRequest: [data => Object.keys(data).map(it => encodeURIComponent(it) + '=' + encodeURIComponent(data[it] === null || data[it] === undefined ? '' : data[it])).join('&')]
})
Vue.prototype.$postJson = (url, data) => request.post(url, JSON.stringify(data), {
headers: {
'Content-Type': 'application/json'
}
})
Vue.prototype.$get = (url, data) => request({ url, params: data })
import hasPermission from '@/scripts/hasPermission'
Vue.use(hasPermission)
import vuedraggable from 'vuedraggable'
Vue.component('vuedraggable', vuedraggable)
const requireComponent = require.context(
// 其组件目录的相对路径
'@/components/MagicBoot/',
// 是否查询其子目录
true,
// 匹配基础组件文件名的正则表达式
/\.vue$/
)
requireComponent.keys().forEach(fileName => {
// 获取组件配置
const componentConfig = requireComponent(fileName)
// 全局注册组件
Vue.component(
// 此处的name,是组件属性定义的name
fileName.substring(fileName.lastIndexOf('/') + 1).replace('.vue', ''),
// componentConfig.default.name,
// 如果这个组件选项是通过 `export default` 导出的,
// 那么就会优先使用 `.default`
// 否则回退到使用模块的根。
componentConfig.default
)
})
Vue.prototype.$bus = new Vue()
// set ElementUI lang to EN
// Vue.use(ElementUI, { locale })
// 如果想要中文版 element-ui,按如下方式声明
Vue.use(ElementUI, {
size: 'small'
})
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
store,
render: h => h(App)
})
document.body.addEventListener('keydown', e => {
if (e.altKey && e.ctrlKey && e.shiftKey && e.key === 'A') {
router.push('/magic/magic-api')
}
})
-75
View File
@@ -1,75 +0,0 @@
import Vue from 'vue'
import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { getToken } from '@/scripts/auth' // get token from cookie
import getPageTitle from '@/scripts/get-page-title'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['/login'] // no redirect whitelist
router.beforeEach(async(to, from, next) => {
// start progress bar
NProgress.start()
// set page title
document.title = getPageTitle(to.meta.title)
// determine whether the user has logged in
const hasToken = getToken()
if (hasToken) {
if (to.path === '/login') {
// if is logged in, redirect to the home page
next({ path: '/' })
NProgress.done()
} else {
// determine whether the user has obtained his permission roles through getInfo
if (Vue.prototype.$authorities) {
next()
} else {
try {
// get user info
// note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
await store.dispatch('user/getUserInfo')
await Vue.prototype.$common.getDictData()
await Vue.prototype.$common.loadConfig()
// generate accessible routes map based on roles
const accessRoutes = await store.dispatch('permission/generateRoutes')
// dynamically add accessible routes
router.addRoutes(accessRoutes)
// hack method to ensure that addRoutes is complete
// set the replace: true, so the navigation will not leave a history record
next({ ...to, replace: true })
} catch (error) {
console.log(error)
// remove token and go to login page to re-login
await store.dispatch('user/resetToken')
Message.error(error.data || 'Has Error')
next(`/login`)
NProgress.done()
}
}
}
} else {
/* has no token*/
if (whiteList.indexOf(to.path) !== -1) {
// in the free login whitelist, go directly
next()
} else {
// other pages that do not have permission to access are redirected to the login page.
next(`/login`)
NProgress.done()
}
}
})
router.afterEach(() => {
// finish progress bar
NProgress.done()
})
-80
View File
@@ -1,80 +0,0 @@
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
/* Layout */
import Layout from '@/layout'
export const constantRoutes = [
{
path: '/redirect',
component: Layout,
hidden: true,
children: [
{
path: '/redirect/:path(.*)',
component: () => import('@/views/redirect/index')
}
]
},
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [{
path: 'dashboard',
name: '首页',
component: () => import('@/views/dashboard/index'),
meta: { title: '首页', icon: 'home', noCache: false, affix: true }
}]
},
{
path: '/user-center',
redirect: '/system/user/user-center',
component: Layout,
hidden: true,
children: [{
path: '/system/user/user-center',
name: '个人中心',
component: () => import('@/views/system/user/user-center'),
meta: { title: '个人中心' }
}]
},
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/404'),
hidden: true
}
]
export const asyncRoutes = [
// 404 page must be placed at the end !!!
{ path: '*', redirect: '/404', hidden: true }
]
const createRouter = () => new Router({
// mode: 'history', // require service support
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes
})
const router = createRouter()
// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher // reset router
}
export default router
-15
View File
@@ -1,15 +0,0 @@
import Cookies from 'js-cookie'
const TokenKey = 'vue_admin_template_token'
export function getToken() {
return Cookies.get(TokenKey)
}
export function setToken(token) {
return Cookies.set(TokenKey, token)
}
export function removeToken() {
return Cookies.remove(TokenKey)
}
-167
View File
@@ -1,167 +0,0 @@
import request from '@/scripts/request'
import Vue from 'vue'
import { v4 as uuidv4 } from 'uuid'
const common = {}
let dictData = []
common.getDictData = async function() {
await Vue.prototype.$request({
url: 'dict/items/all',
method: 'get'
}).then((response) => {
const { data } = response
dictData = data
})
}
common.getDictType = (type) => {
return dictData.filter(it => it.type === type)
}
common.getDictLabel = (type, value) => {
var values = []
value.split(',').forEach(v => {
const list = dictData.filter(it => it.type === type && it.value === v + '')
values.push(list && list[0] && list[0].label || '')
})
return values.join(',')
}
common.handleDelete = (options) => {
const url = options.url
const id = options.id
Vue.prototype.$confirm('此操作将永久删除该数据, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
request({
url: url,
method: 'post',
params: {
id: id
}
}).then(() => {
Vue.prototype.$notify({
title: '成功',
message: '删除成功',
type: 'success',
duration: 2000
})
options && options.done()
})
})
}
const formatJson = (list, filterVal) => {
return list.map(v => filterVal.map(j => {
return v[j]
}))
}
common.renderWhere = (where) => {
var newWhere = {}
for(var key in where) {
if(where[key] instanceof Object){
newWhere[key] = where[key].value
}else{
newWhere[key] = where[key]
}
}
return newWhere
}
common.exportExcel = (options) => {
var where = options.where || {}
where = common.renderWhere(where)
where.current = 1
where.size = 99999999
const url = options.url
const headers = options.headers
const columns = options.columns
request({
url: url,
method: 'post',
params: where
}).then(res => {
import('@/vendor/Export2Excel').then(excel => {
const data = formatJson(res.data, columns)
excel.export_json_to_excel({
header: headers,
data,
filename: 'table-list'
})
})
})
}
common.handlerTreeData = (data, id, pid, sort, pidVal) => {
var treeData = []
var addChildren = (it) => {
var children = data.filter(d => d[pid] === it[id])
if (children && children.length > 0) {
children.sort((a, b) => {
return a[sort] - b[sort]
})
it.children = children
children.forEach(chi => {
addChildren(chi)
})
}
}
data.sort((a, b) => {
return a[sort] - b[sort]
})
data.filter(it => it[pid] === pidVal).forEach(it => {
addChildren(it)
treeData.push(it)
})
return treeData
}
common.uuid = () => {
return uuidv4().replace(/-/g, '')
}
common.objAssign = (obj1, obj2, exclude) => {
exclude = exclude || ''
for (var o1 in obj1) {
for (var o2 in obj2) {
if (o1 === o2) {
if(exclude.indexOf(o1) == -1){
obj1[o1] = obj2[o2]
}
}
}
}
}
common.copyNew = (obj) => {
return JSON.parse(JSON.stringify(obj))
}
common.getParam = (data) => {
let url = ''
for (var k in data) {
const value = data[k] !== undefined ? data[k] : ''
url += `&${k}=${encodeURIComponent(value)}`
}
return url ? url.substring(1) : ''
}
common.getUrl = (url, data) => {
url += (url.indexOf('?') < 0 ? '?' : '') + common.getParam(data)
return url
}
common.loadConfig = async() => {
await request({
url: 'config/list'
}).then(res => {
const { data } = res
Vue.prototype.$filePrefix = data.filePrefix
})
}
export default common
-35
View File
@@ -1,35 +0,0 @@
import Vue from 'vue'
import store from '@/store'
import { isString, isArray } from '@/scripts/validate'
import settings from '@/settings'
// you can set in settings.js
// errorLog:'production' | ['production', 'development']
const { errorLog: needErrorLog } = settings
function checkNeed() {
const env = process.env.NODE_ENV
if (isString(needErrorLog)) {
return env === needErrorLog
}
if (isArray(needErrorLog)) {
return needErrorLog.includes(env)
}
return false
}
if (checkNeed()) {
Vue.config.errorHandler = function(err, vm, info, a) {
// Don't ask me why I use Vue.nextTick, it just a hack.
// detail see https://forum.vuejs.org/t/dispatch-in-vue-config-errorhandler-has-some-problem/23500
Vue.nextTick(() => {
store.dispatch('errorLog/addErrorLog', {
err,
vm,
info,
url: window.location.href
})
console.error(err, info)
})
}
}
@@ -1,10 +0,0 @@
import defaultSettings from '@/settings'
const title = defaultSettings.title
export default function getPageTitle(pageTitle) {
if (pageTitle) {
return `${pageTitle} - ${title}`
}
return `${title}`
}
@@ -1,17 +0,0 @@
const hasPermission = {
install(Vue, options) {
Vue.directive('permission', {
bind(el, binding, vnode) {
if (binding.value) {
const permissionList = Vue.prototype.$authorities
if (permissionList && permissionList.length && !permissionList.includes(binding.value) && process.env.NODE_ENV != 'preview') {
el.style.display = 'none'
}
}
}
})
}
}
export default hasPermission
-355
View File
@@ -1,355 +0,0 @@
/**
* Created by PanJiaChen on 16/11/18.
*/
/**
* Parse the time to string
* @param {(Object|string|number)} time
* @param {string} cFormat
* @returns {string | null}
*/
export function parseTime(time, cFormat) {
if (arguments.length === 0 || !time) {
return null
}
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
let date
if (typeof time === 'object') {
date = time
} else {
if ((typeof time === 'string')) {
if ((/^[0-9]+$/.test(time))) {
// support "1548221490638"
time = parseInt(time)
} else {
// support safari
// https://stackoverflow.com/questions/4310953/invalid-date-in-safari
time = time.replace(new RegExp(/-/gm), '/')
}
}
if ((typeof time === 'number') && (time.toString().length === 10)) {
time = time * 1000
}
date = new Date(time)
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
}
const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
const value = formatObj[key]
// Note: getDay() returns 0 on Sunday
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }
return value.toString().padStart(2, '0')
})
return time_str
}
/**
* @param {number} time
* @param {string} option
* @returns {string}
*/
export function formatTime(time, option) {
if (('' + time).length === 10) {
time = parseInt(time) * 1000
} else {
time = +time
}
const d = new Date(time)
const now = Date.now()
const diff = (now - d) / 1000
if (diff < 30) {
return '刚刚'
} else if (diff < 3600) {
// less 1 hour
return Math.ceil(diff / 60) + '分钟前'
} else if (diff < 3600 * 24) {
return Math.ceil(diff / 3600) + '小时前'
} else if (diff < 3600 * 24 * 2) {
return '1天前'
}
if (option) {
return parseTime(time, option)
} else {
return (
d.getMonth() +
1 +
'月' +
d.getDate() +
'日' +
d.getHours() +
'时' +
d.getMinutes() +
'分'
)
}
}
/**
* @param {string} url
* @returns {Object}
*/
export function getQueryObject(url) {
url = url == null ? window.location.href : url
const search = url.substring(url.lastIndexOf('?') + 1)
const obj = {}
const reg = /([^?&=]+)=([^?&=]*)/g
search.replace(reg, (rs, $1, $2) => {
const name = decodeURIComponent($1)
let val = decodeURIComponent($2)
val = String(val)
obj[name] = val
return rs
})
return obj
}
/**
* @param {string} input value
* @returns {number} output value
*/
export function byteLength(str) {
// returns the byte length of an utf8 string
let s = str.length
for (var i = str.length - 1; i >= 0; i--) {
const code = str.charCodeAt(i)
if (code > 0x7f && code <= 0x7ff) s++
else if (code > 0x7ff && code <= 0xffff) s += 2
if (code >= 0xDC00 && code <= 0xDFFF) i--
}
return s
}
/**
* @param {Array} actual
* @returns {Array}
*/
export function cleanArray(actual) {
const newArray = []
for (let i = 0; i < actual.length; i++) {
if (actual[i]) {
newArray.push(actual[i])
}
}
return newArray
}
/**
* @param {Object} json
* @returns {Array}
*/
export function param(json) {
if (!json) return ''
return cleanArray(
Object.keys(json).map(key => {
if (json[key] === undefined) return ''
return encodeURIComponent(key) + '=' + encodeURIComponent(json[key])
})
).join('&')
}
/**
* @param {string} url
* @returns {Object}
*/
export function param2Obj(url) {
const search = url.split('?')[1]
if (!search) {
return {}
}
return JSON.parse(
'{"' +
decodeURIComponent(search)
.replace(/"/g, '\\"')
.replace(/&/g, '","')
.replace(/=/g, '":"')
.replace(/\+/g, ' ') +
'"}'
)
}
/**
* @param {string} val
* @returns {string}
*/
export function html2Text(val) {
const div = document.createElement('div')
div.innerHTML = val
return div.textContent || div.innerText
}
/**
* Merges two objects, giving the last one precedence
* @param {Object} target
* @param {(Object|Array)} source
* @returns {Object}
*/
export function objectMerge(target, source) {
if (typeof target !== 'object') {
target = {}
}
if (Array.isArray(source)) {
return source.slice()
}
Object.keys(source).forEach(property => {
const sourceProperty = source[property]
if (typeof sourceProperty === 'object') {
target[property] = objectMerge(target[property], sourceProperty)
} else {
target[property] = sourceProperty
}
})
return target
}
/**
* @param {HTMLElement} element
* @param {string} className
*/
export function toggleClass(element, className) {
if (!element || !className) {
return
}
let classString = element.className
const nameIndex = classString.indexOf(className)
if (nameIndex === -1) {
classString += '' + className
} else {
classString =
classString.substr(0, nameIndex) +
classString.substr(nameIndex + className.length)
}
element.className = classString
}
/**
* @param {string} type
* @returns {Date}
*/
export function getTime(type) {
if (type === 'start') {
return new Date().getTime() - 3600 * 1000 * 24 * 90
} else {
return new Date(new Date().toDateString())
}
}
/**
* @param {Function} func
* @param {number} wait
* @param {boolean} immediate
* @return {*}
*/
export function debounce(func, wait, immediate) {
let timeout, args, context, timestamp, result
const later = function() {
// 据上一次触发时间间隔
const last = +new Date() - timestamp
// 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last)
} else {
timeout = null
// 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
if (!immediate) {
result = func.apply(context, args)
if (!timeout) context = args = null
}
}
}
return function(...args) {
context = this
timestamp = +new Date()
const callNow = immediate && !timeout
// 如果延时不存在,重新设定延时
if (!timeout) timeout = setTimeout(later, wait)
if (callNow) {
result = func.apply(context, args)
context = args = null
}
return result
}
}
/**
* This is just a simple version of deep copy
* Has a lot of edge cases bug
* If you want to use a perfect deep copy, use lodash's _.cloneDeep
* @param {Object} source
* @returns {Object}
*/
export function deepClone(source) {
if (!source && typeof source !== 'object') {
throw new Error('error arguments', 'deepClone')
}
const targetObj = source.constructor === Array ? [] : {}
Object.keys(source).forEach(keys => {
if (source[keys] && typeof source[keys] === 'object') {
targetObj[keys] = deepClone(source[keys])
} else {
targetObj[keys] = source[keys]
}
})
return targetObj
}
/**
* @param {Array} arr
* @returns {Array}
*/
export function uniqueArr(arr) {
return Array.from(new Set(arr))
}
/**
* @returns {string}
*/
export function createUniqueString() {
const timestamp = +new Date() + ''
const randomNum = parseInt((1 + Math.random()) * 65536) + ''
return (+(randomNum + timestamp)).toString(32)
}
/**
* Check if an element has a class
* @param {HTMLElement} elm
* @param {string} cls
* @returns {boolean}
*/
export function hasClass(ele, cls) {
return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
}
/**
* Add class to element
* @param {HTMLElement} elm
* @param {string} cls
*/
export function addClass(ele, cls) {
if (!hasClass(ele, cls)) ele.className += ' ' + cls
}
/**
* Remove class from element
* @param {HTMLElement} elm
* @param {string} cls
*/
export function removeClass(ele, cls) {
if (hasClass(ele, cls)) {
const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
ele.className = ele.className.replace(reg, ' ')
}
}
-118
View File
@@ -1,118 +0,0 @@
import axios from 'axios'
import { Message, MessageBox } from 'element-ui'
import store from '@/store'
import { getToken } from '@/scripts/auth'
// create an axios instance
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
// withCredentials: true, // send cookies when cross-domain requests
timeout: 1000 * 60 // request timeout
})
// request interceptor
service.interceptors.request.use(
config => {
// do something before request is sent
if (store.getters.token) {
// let each request carry token
// ['X-Token'] is a custom headers key
// please modify it according to the actual situation
config.headers['token'] = getToken()
}
return config
},
error => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)
var currentMessage
// response interceptor
service.interceptors.response.use(
/**
* If you want to get http information such as headers or status
* Please return response => response
*/
/**
* Determine the request status by custom code
* Here is just an example
* You can also judge the status by HTTP Status Code
*/
response => {
if (response.config.url.indexOf('user/info') !== -1 && response.data.code === 402) {
store.dispatch('user/logout').then(() => {
location.reload()
})
}
return new Promise((reslove, reject) => {
const res = response.data
if (res.code !== 200) {
var duration = 5
if (res.code === 402) {
duration = 1
MessageBox.prompt(`当前账号:${store.getters.username}凭证已过期,请输入密码重新登录`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '退出',
inputType: 'password',
closeOnClickModal: false,
beforeClose: (action, instance, done) => {
if (action === 'confirm') {
store.dispatch('user/login', {
username: store.getters.username,
password: instance.inputValue
}).then((res) => {
if (res) {
done()
service(response.config).then(ret => reslove(ret))
}
})
} else if (action === 'cancel') {
store.dispatch('user/logout').then(() => {
location.reload()
})
} else {
done()
}
}
})
}
if (res.code !== 402) {
if(currentMessage){
currentMessage.close()
}
if(res.code == 403 && process.env.NODE_ENV == 'preview'){
res.message = '演示模式,不允许操作!'
}
currentMessage = Message({
message: res.message || 'Error',
type: 'error',
duration: duration * 1000,
showClose: true
})
reject(res)
}
} else {
reslove(res)
}
})
},
error => {
// console.log('err' + error) // for debug
if(currentMessage){
currentMessage.close()
}
currentMessage = Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
export default service
-58
View File
@@ -1,58 +0,0 @@
Math.easeInOutQuad = function(t, b, c, d) {
t /= d / 2
if (t < 1) {
return c / 2 * t * t + b
}
t--
return -c / 2 * (t * (t - 2) - 1) + b
}
// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts
var requestAnimFrame = (function() {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) }
})()
/**
* Because it's so fucking difficult to detect the scrolling element, just move them all
* @param {number} amount
*/
function move(amount) {
document.documentElement.scrollTop = amount
document.body.parentNode.scrollTop = amount
document.body.scrollTop = amount
}
function position() {
return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop
}
/**
* @param {number} to
* @param {number} duration
* @param {Function} callback
*/
export function scrollTo(to, duration, callback) {
const start = position()
const change = to - start
const increment = 20
let currentTime = 0
duration = (typeof (duration) === 'undefined') ? 500 : duration
var animateScroll = function() {
// increment the time
currentTime += increment
// find the value with the quadratic in-out easing function
var val = Math.easeInOutQuad(currentTime, start, change, duration)
// move the document.body
move(val)
// do the animation unless its over
if (currentTime < duration) {
requestAnimFrame(animateScroll)
} else {
if (callback && typeof (callback) === 'function') {
// the animation is done so lets callback
callback()
}
}
}
animateScroll()
}
-10
View File
@@ -1,10 +0,0 @@
const req = require.context('../icons/svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys()
const re = /\.\/(.*)\.svg/
const svgIcons = requireAll(req).map(i => {
return i.match(re)[1]
})
export default svgIcons
-96
View File
@@ -1,96 +0,0 @@
import common from "@/scripts/common";
const treeTable = {}
treeTable.isChildren = (children, id) => {
var result = false
for(var i in children) {
var chi = children[i]
if(chi.id == id){
result = true
}
if(chi.children && children.length > 0){
if(treeTable.isChildren(chi.children, id)){
result = true
}
}
}
return result
}
treeTable.queryChildren = (children, id) => {
var result = []
for(var i in children){
var chi = children[i]
if(chi.id == id){
if(chi.children && chi.children.length > 0){
result = chi.children
}
}else{
var qc = treeTable.queryChildren(chi.children, id)
if(qc.length > 0){
result = qc
}
}
}
return result
}
treeTable.genTree = (children) => {
var treeData = []
for(var i in children){
var chi = {}
chi.label = children[i].name
chi.id = children[i].id
if(children[i].children && children[i].children.length > 0){
chi.children = treeTable.genTree(children[i].children)
}
treeData.push(chi)
}
return treeData
}
treeTable.deleteEmptyChildren = (children) => {
for(var i in children){
var chi = children[i]
if(chi.children && chi.children.length == 0){
delete chi.children
}else{
treeTable.deleteEmptyChildren(chi.children)
}
}
}
treeTable.recursionSearch = (fields, data, text, html) => {
html = html != undefined ? html : true
var searchData = []
for(var i in data){
var treeNode = data[i]
var children = treeNode.children
if(children && children.length > 0){
var childrenSearch = treeTable.recursionSearch(fields, children, text, html)
treeNode.children = childrenSearch && childrenSearch.length > 0 ? childrenSearch : treeNode.children
treeTable.treeNodeReplace(fields, searchData, treeNode, text, childrenSearch, html)
}else{
treeTable.treeNodeReplace(fields, searchData, treeNode, text, null, html)
}
}
return searchData
}
treeTable.treeNodeReplace = (fields, searchData, treeNode, text, childrenSearch, html) => {
var exist = false
fields.forEach((f) => {
if(treeNode[f] && treeNode[f].indexOf(text) != -1){
if(html){
treeNode[f] = treeNode[f].replace(text, `<font color="#FAA353">${text}</font>`)
}
exist = true
}
})
if(exist || (childrenSearch && childrenSearch.length > 0)){
searchData.push(treeNode)
}
}
export default treeTable
-87
View File
@@ -1,87 +0,0 @@
/**
* Created by PanJiaChen on 16/11/18.
*/
/**
* @param {string} path
* @returns {Boolean}
*/
export function isExternal(path) {
return /^(https?:|mailto:|tel:)/.test(path)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function validUsername(str) {
const valid_map = ['admin', 'editor']
return valid_map.indexOf(str.trim()) >= 0
}
/**
* @param {string} url
* @returns {Boolean}
*/
export function validURL(url) {
const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
return reg.test(url)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function validLowerCase(str) {
const reg = /^[a-z]+$/
return reg.test(str)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function validUpperCase(str) {
const reg = /^[A-Z]+$/
return reg.test(str)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function validAlphabets(str) {
const reg = /^[A-Za-z]+$/
return reg.test(str)
}
/**
* @param {string} email
* @returns {Boolean}
*/
export function validEmail(email) {
const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
return reg.test(email)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function isString(str) {
if (typeof str === 'string' || str instanceof String) {
return true
}
return false
}
/**
* @param {Array} arg
* @returns {Boolean}
*/
export function isArray(arg) {
if (typeof Array.isArray === 'undefined') {
return Object.prototype.toString.call(arg) === '[object Array]'
}
return Array.isArray(arg)
}
-30
View File
@@ -1,30 +0,0 @@
module.exports = {
title: 'magic-boot',
/**
* @type {boolean} true | false
* @description Whether need tagsView
*/
tagsView: true,
/**
* @type {boolean} true | false
* @description Whether fix the header
*/
fixedHeader: false,
/**
* @type {boolean} true | false
* @description Whether show the logo in sidebar
*/
sidebarLogo: false,
/**
* @type {string | array} 'production' | ['production', 'development']
* @description Need show err logs component.
* The default is only used in the production env
* If you want to also use it in dev, you can pass ['production', 'development']
*/
errorLog: 'production'
}
-15
View File
@@ -1,15 +0,0 @@
const getters = {
sidebar: state => state.app.sidebar,
device: state => state.app.device,
visitedViews: state => state.tagsView.visitedViews,
cachedViews: state => state.tagsView.cachedViews,
token: state => state.user.token,
avatar: state => state.user.avatar,
name: state => state.user.name,
username: state => state.user.username,
userInfo: state => state.user.info,
roles: state => state.user.roles,
permission_routes: state => state.permission.routes,
errorLogs: state => state.errorLog.logs
}
export default getters
-25
View File
@@ -1,25 +0,0 @@
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
Vue.use(Vuex)
// https://webpack.js.org/guides/dependency-management/#requirecontext
const modulesFiles = require.context('./modules', true, /\.js$/)
// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
// set './app.js' => 'app'
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
const value = modulesFiles(modulePath)
modules[moduleName] = value.default
return modules
}, {})
const store = new Vuex.Store({
modules,
getters
})
export default store
-48
View File
@@ -1,48 +0,0 @@
import Cookies from 'js-cookie'
const state = {
sidebar: {
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
withoutAnimation: false
},
device: 'desktop'
}
const mutations = {
TOGGLE_SIDEBAR: state => {
state.sidebar.opened = !state.sidebar.opened
state.sidebar.withoutAnimation = false
if (state.sidebar.opened) {
Cookies.set('sidebarStatus', 1)
} else {
Cookies.set('sidebarStatus', 0)
}
},
CLOSE_SIDEBAR: (state, withoutAnimation) => {
Cookies.set('sidebarStatus', 0)
state.sidebar.opened = false
state.sidebar.withoutAnimation = withoutAnimation
},
TOGGLE_DEVICE: (state, device) => {
state.device = device
}
}
const actions = {
toggleSideBar({ commit }) {
commit('TOGGLE_SIDEBAR')
},
closeSideBar({ commit }, { withoutAnimation }) {
commit('CLOSE_SIDEBAR', withoutAnimation)
},
toggleDevice({ commit }, device) {
commit('TOGGLE_DEVICE', device)
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
@@ -1,28 +0,0 @@
const state = {
logs: []
}
const mutations = {
ADD_ERROR_LOG: (state, log) => {
state.logs.push(log)
},
CLEAR_ERROR_LOG: (state) => {
state.logs.splice(0)
}
}
const actions = {
addErrorLog({ commit }, log) {
commit('ADD_ERROR_LOG', log)
},
clearErrorLog({ commit }) {
commit('CLEAR_ERROR_LOG')
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
@@ -1,74 +0,0 @@
import { constantRoutes } from '@/router'
import { getCurrentUserMenu } from '@/api/menu'
import common from '@/scripts/common'
const state = {
routes: [],
addRoutes: []
}
const mutations = {
SET_ROUTES: (state, routes) => {
state.addRoutes = routes
state.routes = constantRoutes.concat(routes)
}
}
export const filterAsyncRouter = (routers, level) => {
level = level || 0
const accessedRouters = routers.filter(router => {
if (router.isShow === 1) {
if (router.isListConfig === 0 && router.listConfig) {
router.component = loadView(`/common/list`)
router.listConfig = JSON.parse(router.listConfig)
if (router.formConfig) {
router.listConfig.formConfig = JSON.parse(router.formConfig)
}
router.props = router.listConfig
} else if (router.component) {
const component = router.component
if (component === 'Layout') {
router.path = common.uuid()
router.component = level > 0 ? (resolve) => require([`@/layout/none.vue`], resolve) : loadLayoutView(component)
} else {
router.component = loadView(component)
}
}
if (router.children && router.children.length) {
router.children = filterAsyncRouter(router.children, level + 1)
}
return true
}
return false
})
return accessedRouters
}
export const loadLayoutView = (view) => {
return (resolve) => require([`@/layout/index`], resolve)
}
export const loadView = (view) => {
view = view.substring(0, 1) === '/' ? view : '/' + view
return (resolve) => require([`@/views${view}`], resolve)
}
const actions = {
generateRoutes({ commit }) {
return new Promise((resolve, reject) => {
getCurrentUserMenu().then(response => {
const { data } = response
const asyncRouter = filterAsyncRouter(data)
commit('SET_ROUTES', asyncRouter)
resolve(asyncRouter)
})
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
@@ -1,32 +0,0 @@
import defaultSettings from '@/settings'
const { showSettings, tagsView, fixedHeader, sidebarLogo } = defaultSettings
const state = {
showSettings: showSettings,
fixedHeader: fixedHeader,
sidebarLogo: sidebarLogo,
tagsView: tagsView
}
const mutations = {
CHANGE_SETTING: (state, { key, value }) => {
if (state.hasOwnProperty(key)) {
state[key] = value
}
}
}
const actions = {
changeSetting({ commit }, data) {
commit('CHANGE_SETTING', data)
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
-160
View File
@@ -1,160 +0,0 @@
const state = {
visitedViews: [],
cachedViews: []
}
const mutations = {
ADD_VISITED_VIEW: (state, view) => {
if (state.visitedViews.some(v => v.path === view.path)) return
state.visitedViews.push(
Object.assign({}, view, {
title: view.meta.title || 'no-name'
})
)
},
ADD_CACHED_VIEW: (state, view) => {
if (state.cachedViews.includes(view.name)) return
if (!view.meta.noCache) {
state.cachedViews.push(view.name)
}
},
DEL_VISITED_VIEW: (state, view) => {
for (const [i, v] of state.visitedViews.entries()) {
if (v.path === view.path) {
state.visitedViews.splice(i, 1)
break
}
}
},
DEL_CACHED_VIEW: (state, view) => {
const index = state.cachedViews.indexOf(view.name)
index > -1 && state.cachedViews.splice(index, 1)
},
DEL_OTHERS_VISITED_VIEWS: (state, view) => {
state.visitedViews = state.visitedViews.filter(v => {
return v.meta.affix || v.path === view.path
})
},
DEL_OTHERS_CACHED_VIEWS: (state, view) => {
const index = state.cachedViews.indexOf(view.name)
if (index > -1) {
state.cachedViews = state.cachedViews.slice(index, index + 1)
} else {
// if index = -1, there is no cached tags
state.cachedViews = []
}
},
DEL_ALL_VISITED_VIEWS: state => {
// keep affix tags
const affixTags = state.visitedViews.filter(tag => tag.meta.affix)
state.visitedViews = affixTags
},
DEL_ALL_CACHED_VIEWS: state => {
state.cachedViews = []
},
UPDATE_VISITED_VIEW: (state, view) => {
for (let v of state.visitedViews) {
if (v.path === view.path) {
v = Object.assign(v, view)
break
}
}
}
}
const actions = {
addView({ dispatch }, view) {
dispatch('addVisitedView', view)
dispatch('addCachedView', view)
},
addVisitedView({ commit }, view) {
commit('ADD_VISITED_VIEW', view)
},
addCachedView({ commit }, view) {
commit('ADD_CACHED_VIEW', view)
},
delView({ dispatch, state }, view) {
return new Promise(resolve => {
dispatch('delVisitedView', view)
dispatch('delCachedView', view)
resolve({
visitedViews: [...state.visitedViews],
cachedViews: [...state.cachedViews]
})
})
},
delVisitedView({ commit, state }, view) {
return new Promise(resolve => {
commit('DEL_VISITED_VIEW', view)
resolve([...state.visitedViews])
})
},
delCachedView({ commit, state }, view) {
return new Promise(resolve => {
commit('DEL_CACHED_VIEW', view)
resolve([...state.cachedViews])
})
},
delOthersViews({ dispatch, state }, view) {
return new Promise(resolve => {
dispatch('delOthersVisitedViews', view)
dispatch('delOthersCachedViews', view)
resolve({
visitedViews: [...state.visitedViews],
cachedViews: [...state.cachedViews]
})
})
},
delOthersVisitedViews({ commit, state }, view) {
return new Promise(resolve => {
commit('DEL_OTHERS_VISITED_VIEWS', view)
resolve([...state.visitedViews])
})
},
delOthersCachedViews({ commit, state }, view) {
return new Promise(resolve => {
commit('DEL_OTHERS_CACHED_VIEWS', view)
resolve([...state.cachedViews])
})
},
delAllViews({ dispatch, state }, view) {
return new Promise(resolve => {
dispatch('delAllVisitedViews', view)
dispatch('delAllCachedViews', view)
resolve({
visitedViews: [...state.visitedViews],
cachedViews: [...state.cachedViews]
})
})
},
delAllVisitedViews({ commit, state }) {
return new Promise(resolve => {
commit('DEL_ALL_VISITED_VIEWS')
resolve([...state.visitedViews])
})
},
delAllCachedViews({ commit, state }) {
return new Promise(resolve => {
commit('DEL_ALL_CACHED_VIEWS')
resolve([...state.cachedViews])
})
},
updateVisitedView({ commit }, view) {
commit('UPDATE_VISITED_VIEW', view)
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
-104
View File
@@ -1,104 +0,0 @@
import Vue from 'vue'
import { login, logout, getInfo } from '@/api/user'
import { getToken, setToken, removeToken } from '@/scripts/auth'
import { resetRouter } from '@/router'
const getDefaultState = () => {
return {
token: getToken(),
name: '',
username: ''
}
}
const state = getDefaultState()
const mutations = {
RESET_STATE: (state) => {
Object.assign(state, getDefaultState())
},
SET_TOKEN: (state, token) => {
state.token = token
},
SET_NAME: (state, name) => {
state.name = name
},
SET_USERNAME: (state, username) => {
state.username = username
},
SET_INFO: (state, info) => {
state.info = info
}
}
const actions = {
// user login
login({ commit }, userInfo) {
const { username, password } = userInfo
return new Promise((resolve, reject) => {
login({ username: username.trim(), password: password }).then(response => {
const { data } = response
commit('SET_TOKEN', data)
setToken(data)
resolve(data)
}).catch(error => {
reject(error)
})
})
},
// get user info
getUserInfo({ commit, state }) {
return new Promise((resolve, reject) => {
getInfo(state.token).then(response => {
const { data } = response
if (!data) {
reject('Verification failed, please Login again.')
}
const authorities_ = []
for (var i = 0; i < data.authorities.length; i++) {
authorities_.push(data.authorities[i])
}
Vue.prototype.$authorities = authorities_
commit('SET_INFO', data)
commit('SET_NAME', data.name)
commit('SET_USERNAME', data.username)
resolve()
}).catch(error => {
reject(error)
})
})
},
// user logout
logout({ commit, state, dispatch }) {
return new Promise((resolve, reject) => {
logout(state.token).then(() => {
removeToken() // must remove token first
resetRouter()
dispatch('tagsView/delAllViews', null, { root: true })
commit('RESET_STATE')
resolve()
}).catch(error => {
reject(error)
})
})
},
// remove token
resetToken({ commit }) {
return new Promise(resolve => {
removeToken() // must remove token first
commit('RESET_STATE')
resolve()
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
-22
View File
@@ -1,22 +0,0 @@
@font-face {
font-family: PoetsenOne;
src: url(../assets/fonts/PoetsenOne.woff2) format('woff2');
font-weight: 100;
font-style: normal;
}
body {
--el-dialog__wrapper-bottom: 15vh;
--el-dialog__wrapper-top: 15vh;
--el-dialog__body-max-height: 60vh;
}
.app-container hr {
border: none;
height: 1px;
background: #F3F3F3;
}
.toolbar-container{
margin-bottom: 10px
}
.clear{
clear: both;
}
-49
View File
@@ -1,49 +0,0 @@
// cover some element-ui styles
.el-breadcrumb__inner,
.el-breadcrumb__inner a {
font-weight: 400 !important;
}
.el-upload {
input[type="file"] {
display: none !important;
}
}
.el-upload__input {
display: none;
}
// to fixed https://github.com/ElemeFE/element/issues/2461
.el-dialog {
transform: none;
left: 0;
position: relative;
margin: 0 auto;
}
// refine element ui upload
.upload-container {
.el-upload {
width: 100%;
.el-upload-dragger {
width: 100%;
height: 200px;
}
}
}
// dropdown
.el-dropdown-menu {
a {
display: block
}
}
// to fix el-date-picker css style
.el-range-separator {
box-sizing: content-box;
}
-72
View File
@@ -1,72 +0,0 @@
@import './variables.scss';
@import './mixin.scss';
@import './transition.scss';
@import './element-ui.scss';
@import './sidebar.scss';
body {
height: 100%;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
}
label {
font-weight: 700;
}
html {
height: 100%;
box-sizing: border-box;
}
#app {
height: 100%;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
a:focus,
a:active {
outline: none;
}
a,
a:focus,
a:hover {
cursor: pointer;
color: inherit;
text-decoration: none;
}
div:focus {
outline: none;
}
.clearfix {
&:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
}
// main-container global css
.app-container {
padding: 20px;
margin: 10px;
background: #fff;
border-radius: 5px;
}
.filter-container {
margin-bottom: 6px;
}
-28
View File
@@ -1,28 +0,0 @@
@mixin clearfix {
&:after {
content: "";
display: table;
clear: both;
}
}
@mixin scrollBar {
&::-webkit-scrollbar-track-piece {
background: #d3dce6;
}
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
background: #99a9bf;
border-radius: 20px;
}
}
@mixin relative {
position: relative;
width: 100%;
height: 100%;
}
-209
View File
@@ -1,209 +0,0 @@
#app {
.main-container {
min-height: 100%;
transition: margin-left .28s;
margin-left: $sideBarWidth;
position: relative;
}
.sidebar-container {
transition: width 0.28s;
width: $sideBarWidth !important;
background-color: $menuBg;
height: 100%;
position: fixed;
font-size: 0px;
top: 0;
bottom: 0;
left: 0;
z-index: 1001;
overflow: hidden;
// reset element-ui css
.horizontal-collapse-transition {
transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
}
.scrollbar-wrapper {
overflow-x: hidden !important;
}
.el-scrollbar__bar.is-vertical {
right: 0px;
}
.el-scrollbar {
height: 100%;
}
&.has-logo {
.el-scrollbar {
height: calc(100% - 50px);
}
}
.is-horizontal {
display: none;
}
a {
display: inline-block;
width: 100%;
overflow: hidden;
}
.svg-icon {
margin-right: 16px;
}
.el-menu {
border: none;
height: 100%;
width: 100% !important;
}
// menu hover
.submenu-title-noDropdown,
.el-submenu__title {
&:hover {
background-color: $menuHover !important;
}
}
.is-active>.el-submenu__title {
color: $subMenuActiveText !important;
}
& .nest-menu .el-submenu>.el-submenu__title,
& .el-submenu .el-menu-item {
min-width: $sideBarWidth !important;
background-color: $subMenuBg !important;
&:hover {
background-color: $subMenuHover !important;
}
}
}
.hideSidebar {
.sidebar-container {
width: 54px !important;
}
.main-container {
margin-left: 54px;
}
.submenu-title-noDropdown {
padding: 0 !important;
position: relative;
.el-tooltip {
padding: 0 !important;
.svg-icon {
margin-left: 20px;
}
}
}
.el-submenu {
overflow: hidden;
&>.el-submenu__title {
padding: 0 !important;
.svg-icon {
margin-left: 20px;
}
.el-submenu__icon-arrow {
display: none;
}
}
}
.el-menu--collapse {
.el-submenu {
&>.el-submenu__title {
&>span {
height: 0;
width: 0;
overflow: hidden;
visibility: hidden;
display: inline-block;
}
}
}
}
}
.el-menu--collapse .el-menu .el-submenu {
min-width: $sideBarWidth !important;
}
// mobile responsive
.mobile {
.main-container {
margin-left: 0px;
}
.sidebar-container {
transition: transform .28s;
width: $sideBarWidth !important;
}
&.hideSidebar {
.sidebar-container {
pointer-events: none;
transition-duration: 0.3s;
transform: translate3d(-$sideBarWidth, 0, 0);
}
}
}
.withoutAnimation {
.main-container,
.sidebar-container {
transition: none;
}
}
}
// when menu collapsed
.el-menu--vertical {
&>.el-menu {
.svg-icon {
margin-right: 16px;
}
}
.nest-menu .el-submenu>.el-submenu__title,
.el-menu-item {
&:hover {
// you can use $subMenuHover
background-color: $menuHover !important;
}
}
// the scroll bar appears when the subMenu is too long
>.el-menu--popup {
max-height: 100vh;
overflow-y: auto;
&::-webkit-scrollbar-track-piece {
background: #d3dce6;
}
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
background: #99a9bf;
border-radius: 20px;
}
}
}
-48
View File
@@ -1,48 +0,0 @@
// global transition css
/* fade */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.28s;
}
.fade-enter,
.fade-leave-active {
opacity: 0;
}
/* fade-transform */
.fade-transform-leave-active,
.fade-transform-enter-active {
transition: all .5s;
}
.fade-transform-enter {
opacity: 0;
transform: translateX(-30px);
}
.fade-transform-leave-to {
opacity: 0;
transform: translateX(30px);
}
/* breadcrumb transition */
.breadcrumb-enter-active,
.breadcrumb-leave-active {
transition: all .5s;
}
.breadcrumb-enter,
.breadcrumb-leave-active {
opacity: 0;
transform: translateX(20px);
}
.breadcrumb-move {
transition: all .5s;
}
.breadcrumb-leave-active {
position: absolute;
}
-25
View File
@@ -1,25 +0,0 @@
// sidebar
$menuText:#bfcbd9;
$menuActiveText:#409EFF;
$subMenuActiveText:#f4f4f5; //https://github.com/ElemeFE/element/issues/12951
$menuBg:#304156;
$menuHover:#263445;
$subMenuBg:#1f2d3d;
$subMenuHover:#001528;
$sideBarWidth: 210px;
// the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
:export {
menuText: $menuText;
menuActiveText: $menuActiveText;
subMenuActiveText: $subMenuActiveText;
menuBg: $menuBg;
menuHover: $menuHover;
subMenuBg: $subMenuBg;
subMenuHover: $subMenuHover;
sideBarWidth: $sideBarWidth;
}
-220
View File
@@ -1,220 +0,0 @@
/* eslint-disable */
import { saveAs } from 'file-saver'
import XLSX from 'xlsx'
function generateArray(table) {
var out = [];
var rows = table.querySelectorAll('tr');
var ranges = [];
for (var R = 0; R < rows.length; ++R) {
var outRow = [];
var row = rows[R];
var columns = row.querySelectorAll('td');
for (var C = 0; C < columns.length; ++C) {
var cell = columns[C];
var colspan = cell.getAttribute('colspan');
var rowspan = cell.getAttribute('rowspan');
var cellValue = cell.innerText;
if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue;
//Skip ranges
ranges.forEach(function (range) {
if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) {
for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null);
}
});
//Handle Row Span
if (rowspan || colspan) {
rowspan = rowspan || 1;
colspan = colspan || 1;
ranges.push({
s: {
r: R,
c: outRow.length
},
e: {
r: R + rowspan - 1,
c: outRow.length + colspan - 1
}
});
};
//Handle Value
outRow.push(cellValue !== "" ? cellValue : null);
//Handle Colspan
if (colspan)
for (var k = 0; k < colspan - 1; ++k) outRow.push(null);
}
out.push(outRow);
}
return [out, ranges];
};
function datenum(v, date1904) {
if (date1904) v += 1462;
var epoch = Date.parse(v);
return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
}
function sheet_from_array_of_arrays(data, opts) {
var ws = {};
var range = {
s: {
c: 10000000,
r: 10000000
},
e: {
c: 0,
r: 0
}
};
for (var R = 0; R != data.length; ++R) {
for (var C = 0; C != data[R].length; ++C) {
if (range.s.r > R) range.s.r = R;
if (range.s.c > C) range.s.c = C;
if (range.e.r < R) range.e.r = R;
if (range.e.c < C) range.e.c = C;
var cell = {
v: data[R][C]
};
if (cell.v == null) continue;
var cell_ref = XLSX.utils.encode_cell({
c: C,
r: R
});
if (typeof cell.v === 'number') cell.t = 'n';
else if (typeof cell.v === 'boolean') cell.t = 'b';
else if (cell.v instanceof Date) {
cell.t = 'n';
cell.z = XLSX.SSF._table[14];
cell.v = datenum(cell.v);
} else cell.t = 's';
ws[cell_ref] = cell;
}
}
if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range);
return ws;
}
function Workbook() {
if (!(this instanceof Workbook)) return new Workbook();
this.SheetNames = [];
this.Sheets = {};
}
function s2ab(s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
return buf;
}
export function export_table_to_excel(id) {
var theTable = document.getElementById(id);
var oo = generateArray(theTable);
var ranges = oo[1];
/* original data */
var data = oo[0];
var ws_name = "SheetJS";
var wb = new Workbook(),
ws = sheet_from_array_of_arrays(data);
/* add ranges to worksheet */
// ws['!cols'] = ['apple', 'banan'];
ws['!merges'] = ranges;
/* add worksheet to workbook */
wb.SheetNames.push(ws_name);
wb.Sheets[ws_name] = ws;
var wbout = XLSX.write(wb, {
bookType: 'xlsx',
bookSST: false,
type: 'binary'
});
saveAs(new Blob([s2ab(wbout)], {
type: "application/octet-stream"
}), "test.xlsx")
}
export function export_json_to_excel({
multiHeader = [],
header,
data,
filename,
merges = [],
autoWidth = true,
bookType = 'xlsx'
} = {}) {
/* original data */
filename = filename || 'excel-list'
data = [...data]
data.unshift(header);
for (let i = multiHeader.length - 1; i > -1; i--) {
data.unshift(multiHeader[i])
}
var ws_name = "SheetJS";
var wb = new Workbook(),
ws = sheet_from_array_of_arrays(data);
if (merges.length > 0) {
if (!ws['!merges']) ws['!merges'] = [];
merges.forEach(item => {
ws['!merges'].push(XLSX.utils.decode_range(item))
})
}
if (autoWidth) {
/*设置worksheet每列的最大宽度*/
const colWidth = data.map(row => row.map(val => {
/*先判断是否为null/undefined*/
if (val == null) {
return {
'wch': 10
};
}
/*再判断是否为中文*/
else if (val.toString().charCodeAt(0) > 255) {
return {
'wch': val.toString().length * 2
};
} else {
return {
'wch': val.toString().length
};
}
}))
/*以第一行为初始值*/
let result = colWidth[0];
for (let i = 1; i < colWidth.length; i++) {
for (let j = 0; j < colWidth[i].length; j++) {
if (result[j]['wch'] < colWidth[i][j]['wch']) {
result[j]['wch'] = colWidth[i][j]['wch'];
}
}
}
ws['!cols'] = result;
}
/* add worksheet to workbook */
wb.SheetNames.push(ws_name);
wb.Sheets[ws_name] = ws;
var wbout = XLSX.write(wb, {
bookType: bookType,
bookSST: false,
type: 'binary'
});
saveAs(new Blob([s2ab(wbout)], {
type: "application/octet-stream"
}), `${filename}.${bookType}`);
}
-24
View File
@@ -1,24 +0,0 @@
/* eslint-disable */
import { saveAs } from 'file-saver'
import JSZip from 'jszip'
export function export_txt_to_zip(th, jsonData, txtName, zipName) {
const zip = new JSZip()
const txt_name = txtName || 'file'
const zip_name = zipName || 'file'
const data = jsonData
let txtData = `${th}\r\n`
data.forEach((row) => {
let tempStr = ''
tempStr = row.toString()
txtData += `${tempStr}\r\n`
})
zip.file(`${txt_name}.txt`, txtData)
zip.generateAsync({
type: "blob"
}).then((blob) => {
saveAs(blob, `${zip_name}.zip`)
}, (err) => {
alert('导出失败')
})
}

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