master
xy 3 years ago
parent 3a7d717fae
commit 595e1a06ed

@ -17,6 +17,7 @@
"axios": "0.18.1",
"core-js": "3.6.5",
"echarts": "^4.9.0",
"element-resize-detector": "^1.2.4",
"element-ui": "2.13.2",
"html2canvas": "^1.4.1",
"js-cookie": "2.2.0",
@ -28,8 +29,10 @@
"print-js": "^1.6.0",
"view-design": "^4.7.0",
"vue": "2.6.10",
"vue-grid-layout": "^2.4.0",
"vue-router": "3.0.6",
"vuex": "3.1.0",
"vuex-persistedstate": "^4.1.0",
"wangeditor": "^4.7.12"
},
"devDependencies": {

@ -1,365 +1,88 @@
<template>
<div class="worker-container">
<div class="card">
<el-card class="box-card" shadow="hover">
<div slot="header">
<span style="border-left: 3px solid #338DE3FF;padding-left: 6px;">待办事项4</span>
<i class="el-icon-more" style="float: right;font-size: 20px;"></i>
</div>
<div v-for="o in 4" :key="o">
{{'待办事项 ' + o }}
</div>
</el-card>
</div>
<div class="card">
<el-card class="box-card" shadow="hover">
<div slot="header">
<span style="border-left: 3px solid #338DE3FF;padding-left: 6px;">图表1</span>
<i class="el-icon-more" style="float: right;font-size: 20px;"></i>
</div>
<div id="line-chart" style="width: 500px;height: 260px;">
</div>
</el-card>
</div>
<div class="card">
<el-card class="box-card" shadow="hover">
<div slot="header">
<span style="border-left: 3px solid #338DE3FF;padding-left: 6px;">图表2</span>
<i class="el-icon-more" style="float: right;font-size: 20px;"></i>
</div>
<div id="bar-chart" style="width: 600px;height: 260px;">
</div>
</el-card>
</div>
<div class="card">
<el-card class="box-card" shadow="hover">
<div slot="header">
<span style="border-left: 3px solid #338DE3FF;padding-left: 6px;">图表3</span>
<i class="el-icon-more" style="float: right;font-size: 20px;"></i>
</div>
<div id="doughnut-chart" style="width: 300px;height: 310px;">
</div>
</el-card>
</div>
<div class="card">
<el-card class="box-card" shadow="hover">
<div slot="header">
<span style="border-left: 3px solid #338DE3FF;padding-left: 6px;">图表4</span>
<i class="el-icon-more" style="float: right;font-size: 20px;"></i>
</div>
<div id="sankey-chart" style="width: 750px;height: 310px;">
</div>
</el-card>
</div>
<div class="card">
<el-card class="box-card" shadow="hover">
<div slot="header">
<span style="border-left: 3px solid #338DE3FF;padding-left: 6px;">进度</span>
<i class="el-icon-more" style="float: right;font-size: 20px;"></i>
</div>
<div>
<el-progress type="circle" :percentage="25"></el-progress>
<el-progress type="circle" :percentage="100" status="success"></el-progress>
</div>
<div>
<el-progress type="circle" :percentage="70" status="warning"></el-progress>
<el-progress type="circle" :percentage="50" status="exception"></el-progress>
</div>
</el-card>
</div>
<div class="card">
<el-card class="box-card" shadow="hover">
<div slot="header">
<span style="border-left: 3px solid #338DE3FF;padding-left: 6px;">卡片名称</span>
<i class="el-icon-more" style="float: right;font-size: 20px;"></i>
</div>
<div>
<el-progress :percentage="50"></el-progress>
<el-progress :percentage="100" status="success"></el-progress>
<el-progress :percentage="100" status="warning"></el-progress>
<el-progress :percentage="50" status="exception"></el-progress>
</div>
</el-card>
</div>
<div>
<grid-layout
id="grid-card"
class="gird-card"
:layout.sync="layoutList"
:col-num="12"
:row-height="40"
:is-draggable="false"
:is-resizable="false"
:is-mirrored="false"
:vertical-compact="true"
:margin="[10, 10]"
:autoSize="true"
:use-css-transforms="true"
>
<grid-item
v-for="item in layoutList"
:x="item.x"
:y="item.y"
:w="item.w"
:h="item.h"
:i="item.i"
:key="item.i"
style="touch-action: none"
>
<component
style="position: absolute; inset: 0 0 0 0"
:is="item.component"
></component>
</grid-item>
</grid-layout>
</div>
</template>
<script>
import echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
const animationDuration = 6000
import VueGridLayout from "vue-grid-layout";
import path from "path";
const files = require.context(
"@/views/system/workerComponents",
false,
/.vue$/
);
let cpns = files.keys().map((key) => {
return files(key).default || files(key);
});
const componentsRegister = () => {
let obj = {};
cpns.forEach((cpn) => {
Object.defineProperty(obj, cpn.name, {
value: cpn,
enumerable: true,
writable: true,
configurable: true,
});
});
obj["GridLayout"] = VueGridLayout.GridLayout;
obj["GridItem"] = VueGridLayout.GridItem;
return obj;
};
let layout = cpns.map((item) => {
return {
...item.layout,
component: item,
};
});
export default {
components: componentsRegister(),
data() {
return {
lineChartOption: {
tooltip: {
trigger: 'axis'
},
legend: {},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value',
axisLabel: {
formatter: '{value} °C'
}
},
series: [
{
name: 'Highest',
type: 'line',
data: [10, 11, 13, 11, 12, 12, 9],
markPoint: {
data: [
{type: 'max', name: 'Max'},
{type: 'min', name: 'Min'}
]
},
markLine: {
data: [{type: 'average', name: 'Avg'}]
}
},
{
name: 'Lowest',
type: 'line',
data: [1, -2, 2, 5, 3, 2, 0],
markPoint: {
data: [{name: '周最低', value: -2, xAxis: 1, yAxis: -1.5}]
},
markLine: {
data: [
{type: 'average', name: 'Avg'},
[
{
symbol: 'none',
x: '90%',
yAxis: 'max'
},
{
symbol: 'circle',
label: {
position: 'start',
formatter: 'Max'
},
type: 'max',
name: '最高点'
}
]
]
}
}
]
},
chart2Option:{
title: {
text: 'Waterfall Chart',
subtext: 'Living Expenses in Shenzhen'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: function (params) {
let tar = params[1];
return tar.name + '<br/>' + tar.seriesName + ' : ' + tar.value;
}
},
grid: {
left: '3%',
right: '3%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
splitLine: { show: false },
data: ['Total', 'Rent', 'Utilities', 'Transportation', 'Meals', 'Other']
},
yAxis: {
type: 'value'
},
series: [
{
name: 'Placeholder',
type: 'bar',
stack: 'Total',
itemStyle: {
borderColor: 'transparent',
color: 'transparent'
},
emphasis: {
itemStyle: {
borderColor: 'transparent',
color: 'transparent'
}
},
data: [0, 1700, 1400, 1200, 300, 0]
},
{
name: 'Life Cost',
type: 'bar',
stack: 'Total',
label: {
show: true,
position: 'inside'
},
data: [2900, 1200, 300, 200, 900, 300]
}
]
},
chart3Option:{
tooltip: {
trigger: 'item'
},
legend: {
top: '0%',
left: 'center',
padding:[4, 0, 20, 0]
},
series: [
{
name: 'Access From',
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: 40,
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: [
{ value: 1048, name: 'Search Engine' },
{ value: 735, name: 'Direct' },
{ value: 580, name: 'Email' },
{ value: 484, name: 'Union Ads' },
{ value: 300, name: 'Video Ads' }
]
}
]
},
chart4Option:{
series: {
type: 'sankey',
layout: 'none',
emphasis: {
focus: 'adjacency'
},
data: [
{
name: 'a'
},
{
name: 'b'
},
{
name: 'a1'
},
{
name: 'a2'
},
{
name: 'b1'
},
{
name: 'c'
}
],
links: [
{
source: 'a',
target: 'a1',
value: 5
},
{
source: 'a',
target: 'a2',
value: 3
},
{
source: 'b',
target: 'b1',
value: 8
},
{
source: 'a',
target: 'b1',
value: 3
},
{
source: 'b1',
target: 'a1',
value: 1
},
{
source: 'b1',
target: 'c',
value: 2
}
]
}
}
}
},
methods: {
initChart(id,options){
echarts.init(document.getElementById(id),"macarons").setOption(options)
layoutList:[]
}
},
methods: {},
computed: {},
mounted() {
this.initChart('line-chart',this.lineChartOption)
this.initChart('bar-chart',this.chart2Option)
this.initChart('doughnut-chart',this.chart3Option)
this.initChart('sankey-chart',this.chart4Option)
created() {
this.layoutList = this.$store.state.app.workerLayout.map(item => {
layout.forEach(lay => {
lay.i === item.i ? item.component = lay.component : ''
})
return item
})
}
}
</script>
<style scoped lang="scss">
.worker-container{
display: flex;
align-content: flex-start;
flex-wrap: wrap;
justify-content: space-between;
padding: 10px 0 10px 10px;
.card{
flex-shrink: 0;
flex-grow: 1;
//min-width: 25vw;
margin-right: 10px;
margin-bottom: 10px;
.box-card{
background: linear-gradient(to bottom, rgba(133, 182, 231, 0.96),#fff 30%);
}
}
}
</style>

@ -2,7 +2,7 @@
<div :class="classObj" class="app-wrapper">
<div class="top-head-bar">
<div class="top-head-bar__logo">
<img style="height: 20px;" src="../assets/logo.png"></img>
<img style="height: 20px;" src="../assets/logo.png" alt="logo">
</div>
<ul>
@ -59,7 +59,7 @@
AppMain
} from './components'
import ResizeMixin from './mixin/ResizeHandler'
import worker from "./components/worker"
import worker from "./components/worker/index.vue"
export default {
name: 'Layout',
components: {

@ -5,6 +5,7 @@ import app from './modules/app'
import permission from './modules/permission'
import settings from './modules/settings'
import user from './modules/user'
import createPersistedState from 'vuex-persistedstate'
Vue.use(Vuex)
@ -15,7 +16,14 @@ const store = new Vuex.Store({
settings,
user
},
getters
getters,
plugins:[
createPersistedState({
storage:window.localStorage,
key:'worker-layout',
paths:['app.workerLayout']
})
]
})
export default store

@ -5,7 +5,8 @@ const state = {
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
withoutAnimation: false
},
device: 'desktop'
device: 'desktop',
workerLayout:[],
}
const mutations = {
@ -25,6 +26,9 @@ const mutations = {
},
TOGGLE_DEVICE: (state, device) => {
state.device = device
},
SET_LAYOUT:(state,layout) => {
state.workerLayout = layout
}
}

@ -0,0 +1,230 @@
<template>
<div style="padding: 0 10px 20px 10px">
<el-row :gutter="4">
<el-col :span="4">
<Card style="height: 100%">
<template v-slot:title>
<p>组件</p>
</template>
<div
class="cpn-name__item"
:class="{ 'cpn-name__item--disable': statusFormat(item.i) }"
v-for="item in layout"
:draggable="!statusFormat(item.i)"
@dragend="dragEnd(item, $event)"
>
<i class="el-icon-folder-remove"></i>
<span>{{ item.i }}</span>
<Button
v-show="statusFormat(item.i)"
type="error"
size="small"
ghost
@click="removeLayout(item.i)"
>移除</Button
>
</div>
</Card>
</el-col>
<el-col :span="20">
<Card>
<template v-slot:title>
<div style="display: flex;justify-content: space-between;align-items: center;">
<p>布局</p>
<Button type="primary" style="float: right;" @click="save"></Button>
</div>
</template>
<grid-layout
id="grid-card"
class="gird-card"
:layout.sync="layoutList"
:col-num="12"
:row-height="40"
:is-draggable="true"
:is-resizable="true"
:is-mirrored="false"
:vertical-compact="true"
:margin="[10, 10]"
:autoSize="true"
:use-css-transforms="true"
>
<grid-item
v-for="item in layoutList"
:x="item.x"
:y="item.y"
:w="item.w"
:h="item.h"
:i="item.i"
:key="item.i"
style="touch-action: none"
>
<component
style="position: absolute; inset: 0 0 0 0"
:is="item.component"
></component>
</grid-item>
</grid-layout>
</Card>
</el-col>
</el-row>
</div>
</template>
<script>
import VueGridLayout from "vue-grid-layout";
import path from "path";
const files = require.context(
"@/views/system/workerComponents",
false,
/.vue$/
);
let cpns = files.keys().map((key) => {
return files(key).default || files(key);
});
const componentsRegister = () => {
let obj = {};
cpns.forEach((cpn) => {
Object.defineProperty(obj, cpn.name, {
value: cpn,
enumerable: true,
writable: true,
configurable: true,
});
});
obj["GridLayout"] = VueGridLayout.GridLayout;
obj["GridItem"] = VueGridLayout.GridItem;
return obj;
};
let layout = cpns.map((item) => {
return {
...item.layout,
component: item,
};
});
export default {
components: componentsRegister(),
data() {
return {
layout,
layoutList: [],
isDragEnter: false,
grid: {
x: 0,
y: 0,
},
};
},
methods: {
dragEnd(item, e) {
if (e.clientX >= this.grid.x && e.clientY >= this.grid.y) {
this.layoutList.push(item);
}
},
removeLayout(i) {
let temp = -1;
this.layoutList.forEach((item, index) => {
if (i === item.i) {
temp = index;
}
});
this.layoutList.splice(temp, 1);
},
save(){
let layout = this.layoutList.map(item => {
return {
x:item.x,
y:item.y,
w:item.w,
h:item.h,
i:item.i
}
})
this.$store.commit('app/SET_LAYOUT',layout)
console.log(layout)
this.$message({
type:'success',
message:'保存成功',
offset:60
})
}
},
computed: {
statusFormat() {
return function (i) {
let iArr = this.layoutList.map((item) => item.i);
return iArr.indexOf(i) !== -1;
};
},
},
mounted() {
this.grid = document.getElementById("grid-card").getBoundingClientRect();
},
created() {
this.layoutList = this.$store.state.app.workerLayout.map(item => {
layout.forEach(lay => {
lay.i === item.i ? item.component = lay.component : ''
})
return item
})
}
};
</script>
<style scoped lang="scss">
.gird-card {
min-height: 200px;
}
.cpn-name__item {
display: flex;
align-items: center;
justify-content: space-between;
color: rgb(100, 100, 100);
border-radius: 4px;
background-color: rgba(94, 181, 218, 0.3);
cursor: move;
padding: 6px 6px;
& > i {
padding-right: 6px;
}
& > span {
flex: 1;
}
& + div {
margin-top: 10px;
}
&--disable {
cursor: no-drop;
background-color: rgba(218, 94, 98, 0.3);
}
}
.fade-in {
animation: fade-in 800ms cubic-bezier(0.39, 0.575, 0.565, 1) both;
}
@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.fade-out {
animation: fade-out 600ms ease-out both;
}
@keyframes fade-out {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
</style>

@ -0,0 +1,40 @@
<template>
<el-card class="box-card" shadow="hover">
<div slot="header">
<span style="border-left: 3px solid #338DE3FF;padding-left: 6px;">进度</span>
<i class="el-icon-more" style="float: right;font-size: 20px;"></i>
</div>
<div>
<el-progress type="circle" :percentage="25"></el-progress>
<el-progress type="circle" :percentage="100" status="success"></el-progress>
</div>
<div>
<el-progress type="circle" :percentage="70" status="warning"></el-progress>
<el-progress type="circle" :percentage="50" status="exception"></el-progress>
</div>
</el-card>
</template>
<script>
export default {
name:"card1",
layout:{
x:0,
y:0,
w:4,
h:5,
i:"card1"
},
data() {
return {
}
},
methods: {},
computed: {},
}
</script>
<style scoped lang="scss">
</style>

@ -0,0 +1,37 @@
<template>
<el-card class="box-card" shadow="hover">
<div slot="header">
<span style="border-left: 3px solid #338DE3FF;padding-left: 6px;">卡片名称</span>
<i class="el-icon-more" style="float: right;font-size: 20px;"></i>
</div>
<div>
<el-progress :percentage="50"></el-progress>
<el-progress :percentage="100" status="success"></el-progress>
<el-progress :percentage="100" status="warning"></el-progress>
<el-progress :percentage="50" status="exception"></el-progress>
</div>
</el-card>
</template>
<script>
export default {
name:'card2',
layout:{
x:4,
y:0,
w:6,
h:4,
i:"card2"
},
data() {
return {
}
},
methods: {},
computed: {},
}
</script>
<style scoped lang="scss">
</style>

@ -0,0 +1,33 @@
<template>
<el-card class="box-card" shadow="hover">
<div slot="header">
<span style="border-left: 3px solid #338DE3FF;padding-left: 6px;">待办事项4</span>
<i class="el-icon-more" style="float: right;font-size: 20px;"></i>
</div>
<div v-for="o in 4" :key="o">
{{'待办事项 ' + o }}
</div>
</el-card>
</template>
<script>
export default {
name:'card3',
layout:{
x:0,
y:5,
w:6,
h:4,
i:"card3"
},
data() {
return {}
},
methods: {},
computed: {},
}
</script>
<style scoped lang="scss">
</style>

@ -0,0 +1,114 @@
<template>
<el-card class="box-card" shadow="hover">
<div slot="header">
<span style="border-left: 3px solid #338DE3FF;padding-left: 6px;">图表1</span>
<i class="el-icon-more" style="float: right;font-size: 20px;"></i>
</div>
<div id="line-chart" style="width: 100%;height: 200px;">
</div>
</el-card>
</template>
<script>
import echarts from 'echarts'
import ElementResize from "element-resize-detector";
require('echarts/theme/macarons') // echarts theme
const animationDuration = 6000
export default {
name:'card4',
layout:{
x:6,
y:5,
w:6,
h:4,
i:"card4"
},
data() {
return {
lineChartOption: {
tooltip: {
trigger: 'axis'
},
legend: {},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value',
axisLabel: {
formatter: '{value} °C'
}
},
series: [
{
name: 'Highest',
type: 'line',
data: [10, 11, 13, 11, 12, 12, 9],
markPoint: {
data: [
{type: 'max', name: 'Max'},
{type: 'min', name: 'Min'}
]
},
markLine: {
data: [{type: 'average', name: 'Avg'}]
}
},
{
name: 'Lowest',
type: 'line',
data: [1, -2, 2, 5, 3, 2, 0],
markPoint: {
data: [{name: '周最低', value: -2, xAxis: 1, yAxis: -1.5}]
},
markLine: {
data: [
{type: 'average', name: 'Avg'},
[
{
symbol: 'none',
x: '90%',
yAxis: 'max'
},
{
symbol: 'circle',
label: {
position: 'start',
formatter: 'Max'
},
type: 'max',
name: '最高点'
}
]
]
}
}
]
}
}
},
methods: {
initChart(id,options){
let dom = document.getElementById(id)
echarts.init(dom,"macarons").setOption(options)
const elementResize = ElementResize({
strategy:'scroll'
})
elementResize.listenTo(dom,ele => {
echarts.init(dom).resize();
})
}
},
computed: {},
mounted() {
this.initChart('line-chart',this.lineChartOption)
}
}
</script>
<style scoped lang="scss">
</style>
Loading…
Cancel
Save