删除magic-boot-ui(基于vue-element-admin vue2版本)
@@ -1,11 +0,0 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'App'
|
||||
}
|
||||
</script>
|
||||
@@ -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
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -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'
|
||||
})
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
})
|
||||
}
|
||||
|
Before Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
|
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 |
|
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]
|
||||
}
|
||||
}
|
||||
@@ -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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 |
@@ -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'
|
||||
@@ -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'
|
||||
@@ -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 })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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')
|
||||
}
|
||||
})
|
||||
@@ -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()
|
||||
})
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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, ' ')
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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'
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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%;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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}`);
|
||||
}
|
||||
@@ -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('导出失败')
|
||||
})
|
||||
}
|
||||