You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
239 lines
5.3 KiB
239 lines
5.3 KiB
<template>
|
|
<div style="padding: 0 10px 20px 10px">
|
|
<el-row :gutter="4">
|
|
<el-col :span="4">
|
|
<Card style="height: 100%;" :style="{'opacity':isDrag ? '0.4' : '1' }">
|
|
<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)"
|
|
@dragstart="isDrag = true"
|
|
@dragend="dragEnd(item, $event)"
|
|
>
|
|
<i class="el-icon-folder-remove"></i>
|
|
<span>{{ item.name }}</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 :class="{'drag-body':isDrag}">
|
|
<template v-slot:title>
|
|
<div style="display: flex;justify-content: space-between;align-items: center;">
|
|
<p>布局</p>
|
|
<Button type="primary" style="float: right;margin-right: 10px;" @click="sync">同步</Button>
|
|
<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 { save } from "@/api/system/expand"
|
|
|
|
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);
|
|
});
|
|
let layout = cpns.map((item) => {
|
|
return {
|
|
...item.layout,
|
|
component: item,
|
|
};
|
|
});
|
|
export default {
|
|
components: {
|
|
"GridLayout": VueGridLayout.GridLayout,
|
|
"GridItem": VueGridLayout.GridItem
|
|
},
|
|
data() {
|
|
return {
|
|
layout,
|
|
layoutList: [],
|
|
isDrag: false,
|
|
|
|
grid: {
|
|
x: 0,
|
|
y: 0,
|
|
},
|
|
};
|
|
},
|
|
methods: {
|
|
dragEnd(item, e) {
|
|
this.isDrag = false
|
|
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);
|
|
},
|
|
|
|
async sync() {
|
|
await this.$store.dispatch("app/setLayout")
|
|
|
|
this.$store.dispatch('app/getLayout').then(res => {
|
|
this.layoutList = res.map(item => {
|
|
layout.forEach(lay => {
|
|
lay.i === item.i ? item.component = lay.component : ''
|
|
})
|
|
return item
|
|
})
|
|
})
|
|
},
|
|
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.dispatch('app/saveLayout',layout)
|
|
}
|
|
},
|
|
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.$store.dispatch('app/getLayout').then(res => {
|
|
this.layoutList = res.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);
|
|
}
|
|
}
|
|
.drag-body{
|
|
transition: all .4s;
|
|
background: rgba(32, 160, 255, 0.3);
|
|
opacity: .7;
|
|
}
|
|
|
|
|
|
.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>
|