You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
294 lines
7.2 KiB
Vue
294 lines
7.2 KiB
Vue
<template>
|
|
<div>
|
|
<div class="left-box">
|
|
<div class="model" :style="`display:${isDrag?'inline-block':'none'}`">
|
|
</div>
|
|
<el-tabs v-model="activeName" class="demo-tabs" stretch>
|
|
<el-tab-pane label="组件列表" name="first">
|
|
<el-divider content-position="left">表单组件</el-divider>
|
|
<draggable :list="dragList" ghost-class="ghost" :force-fallback="true"
|
|
:group="{ name: 'list', pull: 'clone' }"
|
|
:sort="false" itemKey="id" @start="onStartLeft" :clone="onClone">
|
|
<template #item="{ element }">
|
|
<element-mini :option="element" @dblclick.stop="addElement(element)" />
|
|
</template>
|
|
</draggable>
|
|
<el-divider content-position="left">数据展示组件</el-divider>
|
|
<draggable :list="dragViewList" ghost-class="ghost" :force-fallback="true"
|
|
:group="{ name: 'list', pull: 'clone' }"
|
|
:sort="false" itemKey="id" @start="onStartLeft" :clone="onClone">
|
|
<template #item="{ element }">
|
|
<element-mini :option="element" @dblclick.stop="addElement(element)" />
|
|
</template>
|
|
</draggable>
|
|
</el-tab-pane>
|
|
<el-tab-pane label="模板列表" name="second">Config</el-tab-pane>
|
|
<el-tab-pane label="数据()" name="three">
|
|
<div class="dataBox">
|
|
<div>{{ dragList }}</div>
|
|
<div>-------</div>
|
|
<div>{{ formData }}</div>
|
|
</div>
|
|
</el-tab-pane>
|
|
</el-tabs>
|
|
|
|
</div>
|
|
<div class="right-box">
|
|
<div class="toolbar">
|
|
<el-button type="primary" :icon="View" @click="viewForm">预览</el-button>
|
|
<el-button type="primary" :icon="View" @click="exportFile">导出</el-button>
|
|
|
|
</div>
|
|
<nested-draggable :tasks="widgetList" style="height: 100%;" :formData="formData" />
|
|
</div>
|
|
<div class="option-box">
|
|
<div>
|
|
<option-from :formData="optionsData" />
|
|
{{ optionsData }}
|
|
</div>
|
|
<div class="dataBox">
|
|
<div>{{ widgetList }}</div>
|
|
</div>
|
|
</div>
|
|
<el-dialog
|
|
v-model="viewDialogVisible"
|
|
fullscreen
|
|
>
|
|
<form-board :widgetList="widgetList" />
|
|
<template #footer>
|
|
<div class="dialog-footer">
|
|
<el-button @click="viewDialogVisible = false">关闭</el-button>
|
|
</div>
|
|
</template>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
<script lang="ts" setup>
|
|
import { View } from '@element-plus/icons-vue';
|
|
import { reactive, ref, provide } from 'vue';
|
|
import draggable from 'vuedraggable';
|
|
import optionFrom from './option/optionForm.vue';
|
|
import { v4 as getUuid } from 'uuid';
|
|
import nestedDraggable from './nest.vue';
|
|
import elementMini from './element-mini.vue';
|
|
import formBoard from './formBoard.vue';
|
|
import { exportConfig } from '@/views/tool/draggable/exportConfig';
|
|
|
|
interface type {
|
|
name: string,
|
|
id: number
|
|
}
|
|
|
|
|
|
const optionsData = ref({});
|
|
const getOptions = (e) => {
|
|
optionsData.value = e;
|
|
};
|
|
provide('getOptions', getOptions);
|
|
const selectUuid = ref('');
|
|
const getSelectUuid = (e) => {
|
|
selectUuid.value = e;
|
|
};
|
|
provide('selectUuid', selectUuid);
|
|
provide('getSelectUuid', getSelectUuid);
|
|
|
|
|
|
const formData = ref({});
|
|
const activeName = ref('first');
|
|
const viewDialogVisible = ref(false);
|
|
const dragList = [
|
|
{
|
|
type: 'hw-form',
|
|
isContainer: true,
|
|
options: {
|
|
name: '表单',
|
|
labelWidth: '120px',
|
|
formData: {},
|
|
isInLine: false,
|
|
isReset: false,
|
|
isResetBottom: false,
|
|
isSubmitBottom: true,
|
|
submitBottomName: '提交',
|
|
resetBottomName: '重置',
|
|
isPagination: true,
|
|
total: 'total',
|
|
pageNum: 'pageNum',
|
|
pageSize: 'pageSize',
|
|
submitFunction: ''
|
|
},
|
|
tasks: [],
|
|
name: '表单',
|
|
id: 0
|
|
},
|
|
{
|
|
type: 'hw-input',
|
|
isContainer: false,
|
|
options: { name: '单行文本', type: 'text', key: '', disabled: false, required: false },
|
|
name: '单行文本',
|
|
id: 1
|
|
},
|
|
{
|
|
type: 'hw-input',
|
|
isContainer: false,
|
|
options: { name: '密码文本', type: 'password', key: '', disabled: false, required: false },
|
|
name: '密码文本',
|
|
id: 2
|
|
},
|
|
{
|
|
type: 'hw-input',
|
|
isContainer: false,
|
|
options: { name: '多行文本', type: 'textarea', key: '', disabled: false, required: false },
|
|
name: '多行文本',
|
|
id: 3
|
|
},
|
|
{
|
|
type: 'hw-input-number',
|
|
isContainer: false,
|
|
options: { name: '计数器', step: 1, disabled: false, min: -Infinity, max: Infinity, controlsPosition: false },
|
|
name: '计数器',
|
|
id: 4
|
|
},
|
|
{
|
|
type: 'hw-radio-group', isContainer: false,
|
|
options: { name: '单选框组', radioItems: [{ value: '1', label: '1' }, { value: '1', label: '1' }] },
|
|
name: '单选框组',
|
|
id: 5
|
|
},
|
|
{ type: 'hw-slider', isContainer: false, options: { name: '滑块', step: 2, showStops: true }, name: '滑块', id: 6 }
|
|
];
|
|
const dragViewList = [
|
|
{
|
|
type: 'hw-table',
|
|
isContainer: false,
|
|
options: {
|
|
name: '表格',
|
|
thTdMap: [
|
|
{
|
|
name: '字段name',
|
|
keyName: '字段key',
|
|
type: 'input',
|
|
isUpdate: true
|
|
}
|
|
],
|
|
dataKey: '',
|
|
isOperate: true,
|
|
updateFunction: '',
|
|
addFunction: '',
|
|
deleteFunction: '',
|
|
delField: ''
|
|
},
|
|
name: '表格',
|
|
id: 101
|
|
},
|
|
{
|
|
type: 'hw-chart',
|
|
isContainer: false,
|
|
options: {
|
|
name: '图表'
|
|
},
|
|
name: '图表',
|
|
id: 101
|
|
}
|
|
];
|
|
|
|
function removeItemByUuid(arr, uuid) {
|
|
arr.forEach((item, index) => {
|
|
if (item.options.uuid === uuid) {
|
|
arr.splice(index, 1);
|
|
} else if (item.tasks && item.tasks.length > 0) {
|
|
removeItemByUuid(item.tasks, uuid);
|
|
}
|
|
});
|
|
}
|
|
|
|
const widgetList = ref([]);
|
|
const delFormListItem = (uuid) => {
|
|
removeItemByUuid(widgetList.value, uuid);
|
|
};
|
|
|
|
provide('delFormListItem', delFormListItem);
|
|
|
|
const isDrag = ref(false);
|
|
const onClone = (e) => {
|
|
let item = JSON.parse(JSON.stringify(e));
|
|
item.id = Date.now();
|
|
item.options.uuid = getUuid().replaceAll('-', '_');
|
|
return item;
|
|
};
|
|
const onStartLeft = (e) => {
|
|
// console.log(e);
|
|
};
|
|
|
|
const addElement = (e) => {
|
|
let element = onClone(e);
|
|
widgetList.value.push(element);
|
|
};
|
|
const viewForm = () => {
|
|
viewDialogVisible.value = true;
|
|
};
|
|
const exportFile = () => {
|
|
let data = exportConfig(widgetList.value);
|
|
console.log(data);
|
|
};
|
|
|
|
</script>
|
|
<style scoped>
|
|
.model {
|
|
position: absolute;
|
|
width: 100%;
|
|
height: 100%;
|
|
top: 0;
|
|
left: 0;
|
|
}
|
|
|
|
.left-box {
|
|
width: 260px;
|
|
display: inline-block;
|
|
user-select: none;
|
|
vertical-align: top;
|
|
position: relative;
|
|
margin: 8px;
|
|
padding: 2px;
|
|
border: 1px solid #ccc;
|
|
}
|
|
|
|
.right-box {
|
|
width: calc(100% - 260px - 16px - 400px - 16px - 16px - 2px);
|
|
display: inline-block;
|
|
user-select: none;
|
|
vertical-align: top;
|
|
margin: 8px;
|
|
border: 1px solid #ccc;
|
|
height: 80vh;
|
|
overflow: auto;
|
|
padding-top: 12px;
|
|
|
|
&::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
|
|
.toolbar {
|
|
width: 100%;
|
|
margin-bottom: 8px;
|
|
}
|
|
}
|
|
|
|
.option-box {
|
|
width: 400px;
|
|
display: inline-block;
|
|
vertical-align: top;
|
|
margin: 8px;
|
|
border: 1px solid #ccc;
|
|
min-height: 100px;
|
|
}
|
|
|
|
//user-select: none;
|
|
.dataBox {
|
|
width: 100%;
|
|
display: inline-block;
|
|
vertical-align: top;
|
|
margin-right: 10px;
|
|
border: 1px solid #ccc;
|
|
}
|
|
</style>
|