gdoo/resources/js/components/GdooFormDesigner.vue

270 lines
7.5 KiB
Vue

<template>
<draggable chosenClass="af-chosen" ghostClass="af-ghost" :move="onMove" @change="onChange" class="af-draggable" :list="items" item-key="item_id" group="gdooComponent">
<template #item="{element, index}">
<div @click.stop="nodeShow(element)" :class="'af-item af-item-' + element.type + (activeItem.item_id == element.item_id ? ' af-item-active' : '')" :item-id="element.item_id" :item-table="element.table" :key="element.item_id" :style="'width:' + (element.table_id > 0 ? element.width : 'calc(' + (element.grid / 12 * 100) + '% - 5px)')">
<div :class="'af-panel af-panel-' + element.type">
<a @click.stop="nodeDelete(index)"><i class="remove fa fa-trash" title="删除"></i></a>
<div v-if="element.type == 'component'">
{{ element.name }}
</div>
<div v-else class="af-item-content">
<label class="af-item-label" :style="(element.label_width ? 'width:'+ element.label_width : '')" v-show="element.hide_name == 0">{{ element.name }}</label>
<div class="af-item-control" :style="'margin-left:' + (element.hide_name == 0 ? element.label_width : '0px')">
<input class="form-control input-sm" v-model="element.value" :style="(element.field_width ? 'width:' + element.field_width : '')">
</div>
</div>
</div>
<div :class="'af-component fa-group-' + element.type + (element.table == 1 ? ' af-table-component af-over-x' : '')" v-if="element.type == 'component'">
<gdoo-form-designer :table="element.table == 1" :parent_id="element.item_id" :items="element.children" />
</div>
</div>
</template>
</draggable>
</template>
<script>
import draggable from 'vuedraggable';
import { watch, defineComponent, inject, reactive, provide, toRaw} from 'vue'
export default defineComponent({
name: 'gdoo-form-designer',
props: ['items', 'parent_id', 'table'],
setup(props) {
let activeItem = inject('activeItem');
watch(activeItem, (oldItem, newItem) => {
props.items.forEach(item => {
if (item.item_id == newItem.item_id) {
for (var key in newItem) {
item[key] = newItem[key];
}
}
});
})
return {activeItem};
},
components: {
'draggable': draggable,
},
methods: {
onMove(item) {
let me = this;
let oldItem = item.draggedContext.element;
let newItem = item.relatedContext.element;
// 获取容器dom
let node = item.to.offsetParent;
// 子表节点不能拖出子表容器
if (oldItem.table_id > 0) {
// 不能把子表节点拖入其他容器
if (newItem == undefined) {
return false;
}
if (oldItem.table_id == newItem.table_id) {
return true;
} else {
return false;
}
} else {
// 新容器为空
if (newItem == undefined) {
var item_table = node.getAttribute('item-table');
// 不允许把普通节点拖入子表
if (item_table == 1) {
return false;
}
return true;
} else {
// 不允许普通节点拖入子表
if (newItem.table_id) {
return false;
} else {
return true;
}
}
}
},
onChange(item) {
let me = this;
if (item.added) {
var row = item.added.element;
row.parent_id = me.parent_id;
// 已经设置了id
if (row.item_id > 0) {
return;
}
row.item_id = getItemMaxId();
if (row.type == 'component') {
} else {
row.field = getFieldMaxId();
if (me.table) {
row.table_id = row.parent_id;
row.width = '200px';
delete row.grid;
} else {
row.table_id = 0;
}
}
for (var key in me.activeItem) {
delete me.activeItem[key];
}
for (var key in row) {
me.activeItem[key] = row[key];
}
}
},
nodeShow(item) {
for (var key in this.activeItem) {
delete this.activeItem[key];
}
for (var key in item) {
if (key == 'children') {
continue;
}
this.activeItem[key] = item[key];
}
},
nodeDelete(index) {
this.items.splice(index, 1);
}
}
});
</script>
<style>
.af-draggable {
min-height: 40px;
padding: 0;
float: left;
width: 100%;
}
.af-component {
padding: 5px;
padding-bottom: 0;
padding-right: 0;
}
.af-item-component {
border: 1px dashed #ccc;
margin-bottom: 5px;
cursor: move;
float: left;
position: relative;
}
.af-item {
float: left;
margin-right: 5px;
}
.af-panel-component {
color: #aaa;
padding: 5px;
padding-bottom: 0;
}
.af-item:not(.af-item-component) {
padding-bottom: 5px;
}
.af-panel:not(.af-panel-component) {
position: relative;
padding: 5px;
padding-right: 5px;
background-color: #eee;
border: 1px solid transparent;
cursor: move;
}
.af-item-component.af-item-active {
border: 1px dashed #409eff;
}
.af-item-active:not(.af-item-component) .af-panel {
background: #f6f7ff;
border: 1px dashed #409eff;
color: #409eff;
}
.af-item-label {
width: 150px;
text-align: right;
float: left;
line-height: 28px;
vertical-align: middle;
padding: 0 10px 0 0;
font-weight: normal;
}
.af-item-control {
margin-left: 150px;
}
.af-panel .fa {
display: none;
text-align: center;
border: 1px solid #409eff;
background: #fff;
z-index: 999;
}
.af-item-active > .af-panel .fa {
display: inline-block;
position: absolute;
top: -5px;
right: 5px;
color: #409eff;
padding: 3px 5px;
}
.af-item-active .fa:hover {
background: #409eff;
color: #fff;
}
.af-left-group-item.af-ghost,
.af-panel-component.af-ghost .af-panel {
border: 1px dashed #409eff;
color: #409eff;
}
.af-left-group-item.af-ghost {
float: left;
margin: 0;
margin-bottom: 5px;
width:calc(100% - 5px);
}
.af-table-component {
overflow: hidden;
overflow-x: auto;
white-space: nowrap;
}
.af-table-component .af-item {
float: none;
display: inline-block;
}
.af-table-component .af-item-label {
width: auto;
float: none;
text-align: left;
line-height: inherit;
}
.af-table-component .af-item-control {
margin-left: 0;
}
.af-table-component .af-ghost {
width: 200px;
}
</style>