修改表单构建

master
夜笙歌 2 months ago
parent 501c24448a
commit e1e17234b9

@ -42,6 +42,7 @@
"nprogress": "0.2.0",
"pinia": "2.1.7",
"screenfull": "6.0.2",
"uuid": "^11.0.5",
"vform3-builds": "^3.0.10",
"vue": "3.4.34",
"vue-cropper": "1.1.1",

@ -1,19 +0,0 @@
<template>
<div class="element-mini">
</div>
</template>
<script lang="ts" setup>
defineOptions({
name: 'el-input'
});
const props = defineProps({
options: Array
})
const { options } = toRefs(props);
</script>
<style scoped lang="less">
</style>

@ -0,0 +1,69 @@
<script lang="ts">
import hwInput from './hw-input.vue';
import tool from './tool.vue';
export default {
name: 'hw-form',
components: {
hwInput,
tool
}
};
</script>
<template>
<div class="hw-form" @click.stop="formClick"
:style="`background-color: ${(selectUuid === options.uuid) ? '#0001':'#0000'};border-color: ${(selectUuid === options.uuid) ? '#00afff':'#ccc'}`">
<tool v-if="selectUuid === options.uuid" :options="options" />
<span>{{ options.name }}</span>
<el-form :model="formData[options.key || ('form-'+options.uuid)]">
<draggable style="min-height: 10px;" :list="tasks" :group="{ name: 'list' }" itemKey="id">
<template #item="{ element }">
<div>
<component :is="element.type" :options="element.options" :tasks="element.tasks"
:formData="formData[options.key || ('form-'+options.uuid)]" />
</div>
</template>
</draggable>
</el-form>
</div>
</template>
<script lang="ts" setup>
import draggable from 'vuedraggable';
import nestedDraggable from '@/views/tool/draggable/nest.vue';
const props = defineProps({
options: Object,
tasks: Array,
formData: Object
});
const { options, tasks, formData } = toRefs(props);
console.log('formData', formData);
formData.value[options.value.key || ('form-' + options.value.uuid)] = {};
const selectUuid = inject('selectUuid');
const getSelectUuid = inject('getSelectUuid');
const formClick = () => {
getSelectUuid(options.value.uuid);
};
</script>
<style scoped lang="less">
.hw-form {
min-height: 20px;
border: 1px dashed #ccc;
margin: 2px;
padding: 2px;
position: relative;
&:hover {
background-color: #0001;
border-color: #00afff;
}
}
</style>

@ -0,0 +1,47 @@
<template>
<div class="hw-input" @click.stop="inputClick"
:style="`background-color: ${(selectUuid === options.uuid) ? '#0001':'#0000'};border-color: ${(selectUuid === options.uuid) ? '#00afff':'#0000'}`">
<tool v-if="selectUuid === options.uuid" :options="options" />
<el-form-item :label="options.name">
<el-input v-model="formData[options.key || ('input-'+options.uuid)]" />
</el-form-item>
</div>
</template>
<script lang="ts" setup>
import tool from './tool.vue';
import { inject } from 'vue';
defineOptions({
name: 'hw-input'
});
const props = defineProps({
options: Object,
formData: Object
});
const { options, formData } = toRefs(props);
const getOptions = inject('getOptions');
const selectUuid = inject('selectUuid');
const getSelectUuid = inject('getSelectUuid');
const inputClick = () => {
getOptions(options.value);
getSelectUuid(options.value.uuid);
};
</script>
<style scoped lang="less">
.hw-input {
margin: 2px;
border: 1px solid #0000;
position: relative;
padding: 12px 2px 2px;
&:hover {
background-color: #0001;
border: 1px solid #00afff;
}
}
</style>

@ -0,0 +1,49 @@
<template>
<div class="tool">
<div class="items">
<div class="item" @click.stop="delElement">
<el-icon style="font-size: 14px">
<Delete />
</el-icon>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
const props = defineProps({
options: Object
});
import { inject } from 'vue';
const { options } = toRefs(props);
const delFormListItem = inject('delFormListItem');
const delElement = () => {
delFormListItem(options.value.uuid);
};
</script>
<style scoped lang="less">
.tool {
position: absolute;
top: 0;
transform: translateY(-50%);
z-index: 999;
right: 20px;
.items {
.item {
width: 24px;
height: 24px;
text-align: center;
line-height: 22px;
border: #F56C6C solid 1px;
border-radius: 50%;
color: #F56C6C;
}
}
}
</style>

@ -6,60 +6,118 @@
<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" />
<element-mini :option="element" @dblclick.stop="addElement(element)" />
</template>
</draggable>
<div class="dataBox">
<div>{{ dragList }}</div>
<div>----</div>
<div>{{ formData }}</div>
</div>
</div>
<div class="right-box">
<nested-draggable :tasks="widgetList" style="height: 100%;" />
<nested-draggable :tasks="widgetList" style="height: 100%;" :formData="formData" />
</div>
<div class="option-box">
</div>
<div class="dataBox">
<div>{{ dragList }}</div>
</div>
<div class="dataBox">
<div>{{ widgetList }}</div>
<div>
<option-from :formData="optionsData" />
{{ optionsData }}
</div>
<div class="dataBox">
<div>{{ widgetList }}</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { reactive, ref, provide } from 'vue';
import draggable from 'vuedraggable';
import optionFrom from './option/optionForm.vue';
import nestedDraggable from './nest.vue';
import elementMini from './element-mini.vue';
import { v4 as getUuid } from 'uuid';
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 dragList = [
{ type: 'el-input', options: { labelWidth: '120px' }, tasks: [], name: '表单', id: 0 },
{ type: 'el-input', options: { type: 'text' }, name: '单行文本', id: 1 },
{ type: 'el-input', options: { type: 'password' }, name: '密码文本', id: 2 },
{ type: 'el-input', options: { type: 'textarea' }, name: '多行文本', id: 3 },
{ type: 'el-input-number', options: { step: 2 }, name: '计数器', id: 4 },
{
type: 'el-radio-group',
options: { items: [{ value: '1', label: '1' }, { value: '1', label: '1' }] },
type: 'hw-form',
isContainer: true,
options: { name: '表单', labelWidth: '120px', formData: {} },
tasks: [],
name: '表单',
id: 0
},
{
type: 'hw-input',
isContainer: false,
options: { name: '单行文本', type: 'text', key: '' },
name: '单行文本',
id: 1
},
{ type: 'hw-input', isContainer: false, options: { name: '密码文本', type: 'password' }, name: '密码文本', id: 2 },
{ type: 'hw-input', isContainer: false, options: { name: '多行文本', type: 'textarea' }, name: '多行文本', id: 3 },
{ type: 'hw-input-number', isContainer: false, options: { name: '计数器', step: 2 }, name: '计数器', id: 4 },
{
type: 'hw-radio-group', isContainer: false,
options: { name: '单选框组', items: [{ value: '1', label: '1' }, { value: '1', label: '1' }] },
name: '单选框组',
id: 5
},
{ type: 'el-slider', options: { step: 2, showStops: true }, name: '滑块', id: 6 }
{ type: 'hw-slider', isContainer: false, options: { name: '滑块', step: 2, showStops: true }, name: '滑块', id: 6 }
];
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 = reactive<type[]>([]);
const delFormListItem = (uuid) => {
removeItemByUuid(widgetList, uuid);
};
provide('delFormListItem', delFormListItem);
const isDrag = ref(false);
const onClone = (e) => {
console.log(JSON.parse(JSON.stringify(e)));
return JSON.parse(JSON.stringify(e));
let item = JSON.parse(JSON.stringify(e));
item.id = Date.now();
item.options.uuid = getUuid();
return item;
};
const onStartLeft = (e) => {
// console.log(e);
};
const addElement = (e) => {
let element = onClone(e);
widgetList.push(element);
};
</script>
<style scoped>
.model {
@ -82,13 +140,19 @@ const onStartLeft = (e) => {
}
.right-box {
width: 400px;
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;
}
}
.option-box {
@ -102,11 +166,10 @@ const onStartLeft = (e) => {
}
.dataBox {
width: 200px;
width: 100%;
display: inline-block;
vertical-align: top;
margin-right: 10px;
border: 1px solid #ccc;
}
</style>

@ -1,3 +1,15 @@
<script lang="ts">
import hwInput from './elements/hw-input.vue';
import hwForm from './elements/hw-form.vue';
export default {
name: 'nested-draggable',
components: {
hwInput,
hwForm
}
};
</script>
<template>
<draggable
class="dragArea"
@ -10,27 +22,25 @@
>
<template #item="{ element }">
<div style="margin-bottom: 10px;">
<div>{{ element.name }}</div>
<nested-draggable :tasks="element.tasks" v-if="element.tasks" />
<component :is="element.type" :options="element.options" v-else />
<component :is="element.type" :options="element.options" :tasks="element.tasks" :formData="formData" />
</div>
</template>
</draggable>
</template>
<script lang="ts" setup>
defineOptions({
name: 'nested-draggable'
});
import draggable from 'vuedraggable';
const props = defineProps({
tasks: Array
tasks: Array,
formData: Object
});
const { tasks } = toRefs(props);
const { tasks, formData } = toRefs(props);
const changeCB = (e) => {
console.log('changeCB', e);
// console.log('changeCB', tasks.value[e.added.newIndex]);
// tasks.value[e.added.newIndex].id = Date.now();
if (e.added) {
tasks.value[e.added.newIndex].id = Date.now();
}
@ -43,10 +53,4 @@ const onMove = (e) => {
};
</script>
<style scoped>
.dragArea {
min-height: 50px;
outline: 1px dashed;
margin-bottom: 5px;
overflow: hidden;
}
</style>

@ -0,0 +1,21 @@
<template>
<div class="tool">
</div>
</template>
<script lang="ts" setup>
import { watch } from 'vue';
const props = defineProps({
formData: Object
});
const { formData } = toRefs(props);
watch(formData, e => {
console.log(formData.value);
});
</script>
<style scoped lang="less">
</style>
Loading…
Cancel
Save