This commit is contained in:
zhang zhuo 2025-12-12 10:17:38 +08:00
parent d91c90a685
commit 1121cb1664
7 changed files with 65 additions and 71 deletions

View File

@ -49,7 +49,7 @@ const value = computed({
}
})
function remove(element, index) {
function remove(index) {
value.value.splice(index, 1)
}

View File

@ -20,10 +20,10 @@
<component :is="'pi-icon-json'"/>
</el-icon>
</section>
<el-scrollbar style="height: calc(100% - 20px);" :class="{mobile: data.config.isMobile}">
<el-scrollbar style="height: calc(100% - 30px);" :class="{mobile: data.config.isMobile}">
<el-form class="h100 pad10" :label-position="data.config.labelPosition"
:label-width="data.config.labelWidth" :size="data.config.size" :disabled="data.config.disabled">
<drag :data="data" name="page"/>
<drag :data="data" name="page" :field="field"/>
</el-form>
</el-scrollbar>
</section>
@ -39,7 +39,8 @@ import FormBuild from "./formBuild"
import api from "@/api/index.js";
const props = defineProps({
data: {type: FormBuild, default: []}
data: {type: FormBuild, default: []},
field: {type: Object, default: {}}
})
const {t} = useI18n()
const {proxy} = getCurrentInstance()
@ -58,7 +59,10 @@ function empty() {
ElMessageBox.confirm("确定要清空所有表单数据吗", t('system.warning'), {
confirmButtonText: t('system.ok'), cancelButtonText: t('system.cancel'), type: 'warning'
}).then(() => {
tools.data.remove("FORM-FIELDS")
tools.data.remove("FORM-CONFIG")
props.data.restData()
proxy.$message.success("清空成功")
}).catch(() => {
})
}

View File

@ -57,6 +57,7 @@ export const fieldEditors = {
{key: 'props.placeholder', label: '占位提示', type: 'input'},
{key: 'props.multiple', label: '是否多选', type: 'switch'},
{key: 'props.filterable', label: '能否筛选', type: 'switch'},
{key: 'props.clearable', label: '能否清空', type: 'switch'},
{key: 'props.disabled', label: '是否禁用', type: 'switch'},
],
cascader: [
@ -175,7 +176,6 @@ export const fieldEditors = {
],
time: [
{key: 'props.editable', label: '可输入', type: 'switch'},
{key: 'props.rangeSeparator', label: '分隔符', type: 'input'},
{key: 'props.clearable', label: '能否清空', type: 'switch'},
{key: 'props.readonly', label: '是否只读', type: 'switch'},
{key: 'props.disabled', label: '是否禁用', type: 'switch'},

View File

@ -4,15 +4,14 @@
ghostClass="ghostClass" :class="{empty: data.fields.length === 0, layout: isRow}">
<template #item="{ element, index }">
<el-col :span="element.span || 24" class="col">
<el-row v-if="element.name === 'layout'" class="item row" :class="{'active': field.id===element.id}"
<el-row v-if="element.name === 'layout'" class="item row" :class="{'active': field.element.id===element.id}"
@click.stop="clickComp(element)" v-bind="element.props">
<span class="name">{{ element.field_name }}</span>
<drag :fields="element.children" :config="data.config" :data
:name="element.field_name" :is-row="true"/>
<drag :data="getChildrenData(element.children)" :field="field" :name="element.field_name" :is-row="true"/>
</el-row>
<item v-else class="item" :class="{'active': field.id===element.id}" :field="element"
<item v-else class="item" :class="{'active': field.element.id===element.id}" :field="element"
@click.stop="clickComp(element)"/>
<div v-if="field.id===element.id" class="tools-box">
<div v-if="field.element.id===element.id" class="tools-box">
<el-icon size="22" class="icon-box remove" @click.stop="delComp(index)">
<component :is="'pi-icon-shan-chu'"/>
</el-icon>
@ -27,7 +26,7 @@
<script setup>
import draggable from 'vuedraggable'
import {computed, nextTick} from "vue"
import {nextTick, reactive} from "vue"
import item from "./item.vue"
import drag from "./drag.vue"
import tools from "@/utils/tools"
@ -35,21 +34,19 @@ import FormBuild from "./formBuild"
const props = defineProps({
data: {type: FormBuild, default: {}},
field: {type: Object, default: {}},
curKey: {type: String, default: ''},
isRow: {type: Boolean, default: false},
name: {type: String, default: 'page'}
})
const group = {name: props.name, pull: true, put: true}
const field = computed(() => {
return props.data.activeField || {}
})
//
function sortComp(e) {
let element = props.data.fields[e.newIndex]
if (element) {
props.data.setActiveField(element)
props.field.element = element
}
}
@ -59,15 +56,15 @@ function addComp(e) {
if (props.isRow) {
element.span = 12
}
props.data.setActiveField(element)
props.field.element = element
}
//
function clickComp(element) {
if (field.value.id === element.id) {
if (props.field.element.id === element.id) {
return;
}
props.data.setActiveField(element)
props.field.element = element
}
//
@ -86,8 +83,7 @@ function delComp(index) {
i = index
}
}
let element = props.data.fields[i] || {}
props.data.setActiveField(element)
props.field.element = props.data.fields[i] || {}
})
}
@ -101,8 +97,7 @@ function copyComp(index) {
props.data.fields.push(tmp)
//
tools.array.zIndexTo(props.data.fields, props.data.fields.length - 1, index + 1)
let element = props.data.fields[index + 1]
props.data.setActiveField(element)
props.field.element = props.data.fields[index + 1]
})
}
@ -111,6 +106,12 @@ function increaseNum(str) {
return props.data.config.counter.toString();
});
}
function getChildrenData(_data) {
const _form = reactive(new FormBuild())
_form.initData(props.data.config, _data)
return _form
}
</script>
<style lang="scss" scoped>

View File

@ -15,8 +15,6 @@ export default class FormBuild {
config: Config
// 字段信息
fields: Array<any>
// 激活字段
activeField: Object
constructor() {
this.config = {
@ -31,7 +29,6 @@ export default class FormBuild {
counter: 0
}
this.fields = []
this.activeField = null
}
restData() {
@ -53,8 +50,4 @@ export default class FormBuild {
this.config = config
this.fields = fields
}
setActiveField(field: Object) {
this.activeField = field
}
}

View File

@ -1,8 +1,8 @@
<template>
<el-container class="pi-panel">
<left-panel :data="formData"></left-panel>
<center-panel ref="centerRef" :data="formData"></center-panel>
<right-panel :data="formData" :fieldd="field"></right-panel>
<center-panel ref="centerRef" :data="formData" :field="field"></center-panel>
<right-panel :data="formData" :field="field"></right-panel>
</el-container>
</template>
@ -19,9 +19,8 @@ defineOptions({
})
const centerRef = ref(null)
let formData = reactive(new FormBuild())
let field = ref({})
let field = reactive({element: {}})
onMounted(() => {
const fields = tools.data.get("FORM-FIELDS")
@ -30,10 +29,6 @@ onMounted(() => {
formData.initData(config, fields)
}
})
function activeField(v) {
field.value = v
}
</script>
<style scoped>

View File

@ -3,80 +3,80 @@
<el-scrollbar>
<el-tabs v-model="activeName" stretch>
<el-tab-pane label="组件属性" name="field">
<el-form :model="field" label-width="90px">
<el-form-item v-if="field.name !== 'button' && field.name !== 'layout'" label="字段名"
<el-form :model="form" label-width="90px">
<el-form-item v-if="form.name !== 'button' && form.name !== 'layout'" label="字段名"
prop="field_name">
<el-input v-model="field.field_name"></el-input>
<el-input v-model="form.field_name"></el-input>
</el-form-item>
<el-form-item v-if="field.name !== 'layout'" label="标题" prop="title">
<el-input v-model="field.title"></el-input>
<el-form-item v-if="form.name !== 'layout'" label="标题" prop="title">
<el-input v-model="form.title"></el-input>
</el-form-item>
<el-form-item v-if="field.name !== 'button' && field.name !== 'layout'" label="默认值"
<el-form-item v-if="form.name !== 'button' && form.name !== 'layout'" label="默认值"
prop="value">
<el-input v-model="field.value"></el-input>
<el-input v-model="form.value"></el-input>
</el-form-item>
<el-form-item v-if="field.span !== undefined" label="栅格列数" prop="span">
<el-slider v-model="field.span" :min="1" :max="24"/>
<el-form-item v-if="form.span !== undefined" label="栅格列数" prop="span">
<el-slider v-model="form.span" :min="1" :max="24"/>
</el-form-item>
<template v-for="item in fieldEditors[field.name] || []" :key="item.key">
<template v-for="item in fieldEditors[form.name] || []" :key="item.key">
<el-form-item :label="item.label">
<el-input
v-if="item.type === 'input'"
:model-value="getByPath(field, item.key)"
@input="val => setByPath(field, item.key, val)"
:model-value="getByPath(form, item.key)"
@input="val => setByPath(form, item.key, val)"
clearable
/>
<el-input
v-else-if="item.type === 'number'"
type="number"
:model-value="getByPath(field, item.key)"
@input="val => setByPath(field, item.key, Number(val))"
:model-value="getByPath(form, item.key)"
@input="val => setByPath(form, item.key, Number(val))"
/>
<el-switch
v-else-if="item.type === 'switch'"
:model-value="getByPath(field, item.key)"
@change="val => setByPath(field, item.key, val)"
:model-value="getByPath(form, item.key)"
@change="val => setByPath(form, item.key, val)"
/>
<el-color-picker v-else-if="item.type === 'color'" show-alpha
:model-value="getByPath(field, item.key)"
@change="val => setByPath(field, item.key, val)"/>
:model-value="getByPath(form, item.key)"
@change="val => setByPath(form, item.key, val)"/>
<el-radio-group v-else-if="item.type === 'radio'"
:model-value="getByPath(field, item.key)"
@change="val => setByPath(field, item.key, val)">
:model-value="getByPath(form, item.key)"
@change="val => setByPath(form, item.key, val)">
<el-radio-button v-for="op in item.options" :key="op.value"
:value="op.value">{{ op.label }}
</el-radio-button>
</el-radio-group>
<el-select v-else-if="item.type === 'select'" :model-value="getByPath(field, item.key)"
@change="val => setByPath(field, item.key, val)">
<el-select v-else-if="item.type === 'select'" :model-value="getByPath(form, item.key)"
@change="val => setByPath(form, item.key, val)">
<el-option v-for="op in item.options" :key="op.value" :value="op.value"
:label="op.label">
</el-option>
</el-select>
<pi-icon
v-else-if="item.type === 'icon'"
:model-value="getByPath(field, item.key)"
@update:modelValue="val => setByPath(field, item.key, val)"
:model-value="getByPath(form, item.key)"
@update:modelValue="val => setByPath(form, item.key, val)"
/>
</el-form-item>
</template>
<el-form-item label="是否必填" v-if="field.required !== undefined">
<el-switch v-model="field.required"/>
<el-form-item label="是否必填" v-if="form.required !== undefined">
<el-switch v-model="form.required"/>
</el-form-item>
<template v-if="field.options !== undefined">
<template v-if="form.options !== undefined">
<el-divider>选项</el-divider>
<pi-draggable v-model="field.options" item-key="label" :template="{label:'', value:''}">
<pi-draggable v-model="form.options" item-key="label" :template="{label:'', value:''}">
<template #default="scope">
<div style="display:flex;">
<div style="display:flex;gap: 5px;">
<el-input v-model="scope.element.label" placeholder="label"/>
<el-input v-model="scope.element.value" placeholder="value"/>
</div>
</template>
</pi-draggable>
</template>
<template v-if="field.name !== 'button' && field.name !== 'layout'">
<template v-if="form.name !== 'button' && form.name !== 'layout'">
<el-divider>正则校验</el-divider>
<pi-draggable v-model="field.rules" item-key="regex" :template="{regex:'',message:''}">
<pi-draggable v-model="form.rules" item-key="regex" :template="{regex:'',message:''}">
<template #default="scope">
<el-form-item label="表达式">
<el-input v-model="scope.element.regex"/>
@ -136,11 +136,12 @@ import FormBuild from "./formBuild";
const emit = defineEmits(['update:field'])
const props = defineProps({
data: {type: FormBuild, default: {}}
data: {type: FormBuild, default: {}},
field: {type: Object, default: {}}
})
let activeName = ref("field")
const field = computed(() => {
return props.data.activeField || {}
let form = computed(() => {
return props.field.element
})
</script>