This commit is contained in:
parent
4037ebe090
commit
a06da14463
|
|
@ -29,5 +29,10 @@ export default {
|
|||
show: async function (data = {}) {
|
||||
return await http.get("gen_table/show", data);
|
||||
},
|
||||
},
|
||||
form: {
|
||||
build: async function (data = {}) {
|
||||
return await http.post("form/build", data);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<svg t="1765353827346" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5302" width="256" height="256"><path d="M216.4 107.1h50.2c5.7 0 10.4 4.7 10.4 10.4V156c0 5.7-4.7 10.4-10.4 10.4h-45.8c-5.7 0-13.4 4.6-13.4 10.4l-1 246.6c-1.3 35.2-25.1 90-58.6 91.4 23.2-1 59.6 39.5 59.6 89.4l-1 242.4c0 5.8 4.7 19.6 10.6 19.6h49.3c5.9 0 10.8 6.8 10.8 12.8v30.9c0 5.9-4.8 10.8-10.8 10.8h-49.8c-32.4-12.2-60.6-40.7-60.6-90.4v-181c0-49.9-27.1-90.4-60.6-90.4H77.1c-6.8 0-12.2-5.5-12.2-12.2v-65.9c0-6.8 5.5-12.2 12.2-12.2h18.1c33.5 0 60.6-40.5 60.6-90.4V197.4c0-49.9 27.1-90.3 60.6-90.3M808.6 107.1c33.5 0 60.6 40.4 60.6 90.3v180.8c0 49.9 27.1 90.4 60.6 90.4h18.1c6.7 0 12.2 5.4 12.2 12.2v65.9c0 6.7-5.4 12.2-12.2 12.2h-18.2c-33.5 0-60.6 40.5-60.6 90.4v181c0 49.7-28.2 78.2-60.6 90.4h-49.8c-6 0-10.8-4.9-10.8-10.8V879c0-6 4.9-12.8 10.8-12.8H808c5.9 0 10.6-13.8 10.6-19.6l-1-242.4c0-49.9 36.4-90.4 59.6-89.4-33.5-1.4-57.3-56.2-58.6-91.4l-1-246.6c0-5.8-7.7-10.4-13.4-10.4h-45.8c-5.7 0-10.4-4.7-10.4-10.4v-38.5c0-5.7 4.7-10.4 10.4-10.4h50.2M508.4 667.8c16.8 0 30.4 13.6 30.4 30.4 0 16.8-13.6 30.4-30.4 30.4-16.8 0-30.4-13.6-30.4-30.4 0-16.8 13.6-30.4 30.4-30.4M386.8 667.8c16.8 0 30.4 13.6 30.4 30.4 0 16.8-13.6 30.4-30.4 30.4-16.8 0-30.4-13.6-30.4-30.4 0-16.8 13.6-30.4 30.4-30.4M630 667.8c16.8 0 30.4 13.6 30.4 30.4 0 16.8-13.6 30.4-30.4 30.4-16.8 0-30.4-13.6-30.4-30.4 0-16.8 13.6-30.4 30.4-30.4z" p-id="5303"></path></svg>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<svg t="1765332605221" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11956" width="256" height="256"><path d="M929.6896 425.7792c50.0736 0 91.4432 39.1168 94.208 89.088l0.1024 5.2224v323.3792c0 50.0736-39.1168 91.392-89.1392 94.208l-5.1712 0.1024h-215.552a40.448 40.448 0 0 1-3.8912-80.64l3.84-0.2048h215.552c6.5536 0 12.1344-4.608 13.312-11.0592l0.2048-2.4064v-323.3792a13.4656 13.4656 0 0 0-11.0592-13.312l-2.4064-0.1536h-215.552a40.448 40.448 0 0 1-3.8912-80.6912l3.84-0.1536h215.552zM498.5344 102.4a121.2416 121.2416 0 0 1 121.2416 121.2416v592.896a121.2416 121.2416 0 0 1-121.2416 121.2416H121.2416A121.2416 121.2416 0 0 1 0 816.4864V223.6416A121.2416 121.2416 0 0 1 121.2416 102.4z m0 80.8448H121.2416a40.448 40.448 0 0 0-40.448 40.448v592.7936c0 22.3232 18.1248 40.448 40.448 40.448h377.2928a40.448 40.448 0 0 0 40.448-40.448V223.6416a40.448 40.448 0 0 0-40.448-40.448zM371.8656 716.8a26.9312 26.9312 0 0 1 0 53.9136H264.0896a26.9312 26.9312 0 0 1 0-53.9136h107.776z m336.896-606.3104a237.1584 237.1584 0 0 1 226.304 180.5312h53.9136c3.2768 0 6.4 1.024 7.3728 3.9936 0.9728 2.9184 0.0512 4.864-1.9968 6.8096l-78.1312 75.4176a21.5552 21.5552 0 0 1-21.5552 0l-78.1824-75.4176A5.376 5.376 0 0 1 819.2 293.7344h64.6656a185.9584 185.9584 0 0 0-175.104-132.096h-37.7856v-51.2z" p-id="11957"></path></svg>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<svg t="1765333944912" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13131" width="256" height="256"><path d="M811.52 927.744h-599.04c-81.92 0-148.992-66.56-148.992-148.992V188.928c0-81.92 66.56-148.992 148.992-148.992h599.04c81.92 0 148.992 66.56 148.992 148.992v589.824c0 82.432-67.072 148.992-148.992 148.992m-599.04-829.44c-50.176 0-90.624 40.96-90.624 90.624v589.824c0 50.176 40.96 90.624 90.624 90.624h599.04c50.176 0 90.624-40.96 90.624-90.624V188.928c0-50.176-40.96-90.624-90.624-90.624h-599.04m12.288 307.2v-307.2h574.464v307.2c0 41.472-33.792 74.752-74.752 74.752h-424.96c-40.96 0-74.752-33.28-74.752-74.752z m516.096-8.704V98.304H283.136v298.496c0 16.896 13.824 30.72 30.72 30.72h396.8c16.896-0.512 30.208-13.824 30.208-30.72z m-125.44-53.248h22.016c9.728 0 17.92-8.192 17.92-17.92V178.176c0-9.728-8.192-17.92-17.92-17.92h-22.016c-9.728 0-17.92 8.192-17.92 17.92v146.944c0 10.24 8.192 18.432 17.92 18.432z" p-id="13132"></path></svg>
|
||||
</template>
|
||||
|
|
@ -25,6 +25,10 @@ import {CustomLineModel, CustomLine, CUSTOM_LINE} from "./model/CustomLine"
|
|||
import {ElMessageBox} from 'element-plus'
|
||||
import {useI18n} from "vue-i18n"
|
||||
|
||||
defineOptions({
|
||||
name: 'toolsFlow'
|
||||
})
|
||||
|
||||
const containerRef = ref(HTMLElement | null);
|
||||
const {t} = useI18n()
|
||||
let lf = ref(LogicFlow | null);
|
||||
|
|
@ -256,7 +260,7 @@ const handleKeydown = (event) => {
|
|||
.right-panel {
|
||||
width: 320px;
|
||||
background: #fff;
|
||||
border-left: 1px solid #ddd;
|
||||
border-left: 1px solid var(--el-border-color-light);
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,67 +1,148 @@
|
|||
<template>
|
||||
<section class="panel">
|
||||
<el-scrollbar class="h100">
|
||||
<el-main class="h100">
|
||||
<el-form class="h100" :label-position="config.labelPosition" :label-width="config.labelWidth"
|
||||
:size="config.size" :disabled="config.disabled">
|
||||
<drag :fields="fields" @change="changeHandle" name="page" v-model:curKey="curKey"
|
||||
v-model:counter="counter"/>
|
||||
</el-form>
|
||||
</el-main>
|
||||
<section class="header">
|
||||
<el-icon size="24" title="切换设备类型" :class="{active: data.config.isMobile}" @click="toggleDevice">
|
||||
<component :is="'pi-icon-qie-huan'"/>
|
||||
</el-icon>
|
||||
<el-icon size="22" title="暂存" @click="tempSave">
|
||||
<component :is="'pi-icon-zan-cun'"/>
|
||||
</el-icon>
|
||||
<el-icon size="24" title="清空" @click="empty">
|
||||
<component :is="'el-icon-delete'"/>
|
||||
</el-icon>
|
||||
<el-icon size="24" title="复制代码" @click="copyCode">
|
||||
<component :is="'el-icon-document'"/>
|
||||
</el-icon>
|
||||
<el-icon size="24" title="复制代码" @click="downFile">
|
||||
<component :is="'el-icon-download'"/>
|
||||
</el-icon>
|
||||
<el-icon size="24" title="复制JSON" @click="copyJson">
|
||||
<component :is="'pi-icon-json'"/>
|
||||
</el-icon>
|
||||
</section>
|
||||
<el-scrollbar style="height: calc(100% - 20px);" :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"/>
|
||||
</el-form>
|
||||
</el-scrollbar>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {computed, ref} from "vue"
|
||||
import {getCurrentInstance, ref} from "vue"
|
||||
import drag from "./drag.vue"
|
||||
|
||||
defineExpose({clickAddComp})
|
||||
import tools from "@/utils/tools"
|
||||
import {ElMessageBox} from "element-plus"
|
||||
import {useI18n} from "vue-i18n"
|
||||
import FormBuild from "./formBuild"
|
||||
import api from "@/api/index.js";
|
||||
|
||||
const props = defineProps({
|
||||
fields: {type: Array, default: []},
|
||||
config: {type: Object, default: {}},
|
||||
counter: {type: Number, default: 0}
|
||||
data: {type: FormBuild, default: []}
|
||||
})
|
||||
const emit = defineEmits(['change', "update:counter"])
|
||||
let curKey = ref("")
|
||||
const {t} = useI18n()
|
||||
const {proxy} = getCurrentInstance()
|
||||
|
||||
const counter = computed({
|
||||
get() {
|
||||
return props.counter
|
||||
},
|
||||
set(value) {
|
||||
emit('update:counter', value)
|
||||
}
|
||||
})
|
||||
|
||||
// 添加项时
|
||||
function clickAddComp(e) {
|
||||
props.fields.push(e)
|
||||
emit('change', e)
|
||||
function toggleDevice() {
|
||||
props.data.config.isMobile = !props.data.config.isMobile
|
||||
}
|
||||
|
||||
function changeHandle(e) {
|
||||
emit('change', e)
|
||||
function tempSave() {
|
||||
tools.data.set("FORM-FIELDS", props.data.fields)
|
||||
tools.data.set("FORM-CONFIG", props.data.config)
|
||||
proxy.$message.success("保存成功")
|
||||
}
|
||||
|
||||
function empty() {
|
||||
ElMessageBox.confirm("确定要清空所有表单数据吗", t('system.warning'), {
|
||||
confirmButtonText: t('system.ok'), cancelButtonText: t('system.cancel'), type: 'warning'
|
||||
}).then(() => {
|
||||
props.data.restData()
|
||||
}).catch(() => {
|
||||
})
|
||||
}
|
||||
|
||||
function copyJson() {
|
||||
navigator.clipboard.writeText(JSON.stringify({
|
||||
fields: props.data.fields,
|
||||
config: props.data.config
|
||||
}))
|
||||
proxy.$message.success("复制成功")
|
||||
}
|
||||
|
||||
async function copyCode() {
|
||||
const res = await api.tools.form.build({
|
||||
fields: props.data.fields,
|
||||
config: props.data.config
|
||||
})
|
||||
console.log(res.data['form.vue'])
|
||||
navigator.clipboard.writeText(res.data['form.vue'])
|
||||
proxy.$message.success("复制成功")
|
||||
}
|
||||
|
||||
async function downFile() {
|
||||
const res = await api.tools.form.build({
|
||||
fields: props.data.fields,
|
||||
config: props.data.config
|
||||
})
|
||||
console.log(res)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.panel {
|
||||
flex: 1;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
.h100 {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.pad10 {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.mobile {
|
||||
width: 414px;
|
||||
height: 736px !important;
|
||||
border: 1px solid var(--el-border-color);
|
||||
border-radius: 5px;
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
:deep(.el-scrollbar__view) {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #f6f7ff;
|
||||
padding: 2px 10px;
|
||||
gap: 8px;
|
||||
border-radius: 3px;
|
||||
justify-content: end;
|
||||
|
||||
.active {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
i {
|
||||
cursor: pointer;
|
||||
color: #666666;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
i:hover {
|
||||
background-color: #c9ced3;
|
||||
border-radius: 50%;
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -246,3 +246,193 @@ export function setByPath(obj, path, value) {
|
|||
keys.slice(0, -1).forEach(k => o = o[k])
|
||||
o[keys[keys.length - 1]] = value
|
||||
}
|
||||
|
||||
export const inputComps = [{
|
||||
title: "单行文本",
|
||||
icon: "pi-icon-line-input",
|
||||
name: "text",
|
||||
props: {
|
||||
type: 'text'
|
||||
},
|
||||
rules: [],
|
||||
width: "100%",
|
||||
required: false
|
||||
}, {
|
||||
title: "多行文本",
|
||||
icon: "pi-icon-multi-input",
|
||||
name: "textarea",
|
||||
props: {
|
||||
type: 'textarea'
|
||||
},
|
||||
rules: [],
|
||||
width: "100%",
|
||||
required: false
|
||||
}, {
|
||||
title: "密码",
|
||||
icon: "pi-icon-lock",
|
||||
name: "password",
|
||||
props: {
|
||||
type: 'password',
|
||||
showPassword: true
|
||||
},
|
||||
rules: [],
|
||||
width: "100%",
|
||||
required: false
|
||||
}, {
|
||||
title: "计数器",
|
||||
icon: "pi-icon-number-input",
|
||||
name: "number",
|
||||
props: {
|
||||
controlsPosition: ''
|
||||
},
|
||||
rules: [],
|
||||
width: "100%",
|
||||
required: false,
|
||||
value: 1
|
||||
}]
|
||||
export const choiceComps = [{
|
||||
title: "下拉组件",
|
||||
icon: "pi-icon-select",
|
||||
name: "select",
|
||||
props: {},
|
||||
rules: [],
|
||||
options: [],
|
||||
width: "100%",
|
||||
required: false,
|
||||
}, {
|
||||
title: "级联组件",
|
||||
icon: "pi-icon-cascader",
|
||||
name: "cascader",
|
||||
props: {
|
||||
props: {
|
||||
label: 'label',
|
||||
value: 'value',
|
||||
multiple: false,
|
||||
},
|
||||
options: [{label: '一号楼', value: 'r1', children: [{label: '二单元', value: 'c2'}]}]
|
||||
},
|
||||
rules: [],
|
||||
width: "100%",
|
||||
required: false,
|
||||
}, {
|
||||
title: "单选组件",
|
||||
icon: "pi-icon-radio",
|
||||
name: "radio",
|
||||
props: {},
|
||||
rules: [],
|
||||
options: [],
|
||||
width: "100%",
|
||||
style: '',
|
||||
required: false,
|
||||
}, {
|
||||
title: "多选组件",
|
||||
icon: "pi-icon-checkbox",
|
||||
name: "checkbox",
|
||||
props: {},
|
||||
rules: [],
|
||||
options: [],
|
||||
style: '',
|
||||
required: false,
|
||||
}, {
|
||||
title: "开关",
|
||||
icon: "pi-icon-switch",
|
||||
name: "switch",
|
||||
props: {},
|
||||
rules: [],
|
||||
required: false,
|
||||
}, {
|
||||
title: "滑块",
|
||||
icon: "pi-icon-slider",
|
||||
name: "slider",
|
||||
props: {},
|
||||
rules: [],
|
||||
width: "100%",
|
||||
required: false,
|
||||
}, {
|
||||
title: "时间选择",
|
||||
icon: "pi-icon-time-picker",
|
||||
name: "time",
|
||||
props: {
|
||||
format: 'HH:mm:ss',
|
||||
valueFormat: 'HH:mm:ss'
|
||||
},
|
||||
rules: []
|
||||
}, {
|
||||
title: "时间范围",
|
||||
icon: "pi-icon-time-range",
|
||||
name: "timerange",
|
||||
props: {
|
||||
isRange: true,
|
||||
format: 'HH:mm:ss',
|
||||
valueFormat: 'HH:mm:ss'
|
||||
},
|
||||
rules: [],
|
||||
width: "100%",
|
||||
required: false,
|
||||
}, {
|
||||
title: "日期选择",
|
||||
icon: "pi-icon-date-picker",
|
||||
name: "date",
|
||||
props: {
|
||||
type: "date",
|
||||
format: 'YYYY-MM-DD',
|
||||
valueFormat: 'YYYY-MM-DD'
|
||||
},
|
||||
rules: [],
|
||||
width: "100%",
|
||||
required: false,
|
||||
}, {
|
||||
title: "日期范围",
|
||||
icon: "pi-icon-date-range",
|
||||
name: "daterange",
|
||||
props: {
|
||||
type: "daterange",
|
||||
format: 'YYYY-MM-DD',
|
||||
valueFormat: 'YYYY-MM-DD'
|
||||
},
|
||||
rules: [],
|
||||
width: "100%",
|
||||
required: false,
|
||||
}, {
|
||||
title: "评分",
|
||||
icon: "pi-icon-rate",
|
||||
name: "rate",
|
||||
props: {},
|
||||
rules: [],
|
||||
required: false,
|
||||
}, {
|
||||
title: "颜色选择",
|
||||
icon: "pi-icon-color-picker",
|
||||
name: "color",
|
||||
props: {},
|
||||
rules: [],
|
||||
required: false,
|
||||
}, {
|
||||
title: "上传",
|
||||
icon: "pi-icon-upload-file",
|
||||
name: "upload",
|
||||
props: {
|
||||
listType: 'text',
|
||||
name: 'file'
|
||||
},
|
||||
rules: [],
|
||||
required: false,
|
||||
btnText: "点击上传"
|
||||
}]
|
||||
export const layoutComps = [{
|
||||
title: "行容器",
|
||||
icon: "pi-icon-row-layout",
|
||||
name: "layout",
|
||||
props: {
|
||||
gutter: 15
|
||||
},
|
||||
children: []
|
||||
}, {
|
||||
title: "按钮",
|
||||
icon: "pi-icon-button",
|
||||
name: "button",
|
||||
props: {
|
||||
type: 'primary'
|
||||
},
|
||||
btnText: "按钮文字"
|
||||
}];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
<template>
|
||||
<el-dialog :title="titleMap[mode]" v-model="visible" :width="500" destroy-on-close @closed="$emit('closed')">
|
||||
<el-form :model="form" :rules="rules" :disabled="mode==='show'" ref="formRef"
|
||||
label-width="70" label-position="right" size="default">
|
||||
<el-form-item label="字典名称" prop="dict_name">
|
||||
<el-input type="text" v-model="form.dict_name" placeholder="请输入字典名称" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="字典类型" prop="dict_type">
|
||||
<el-input type="text" v-model="form.dict_type" placeholder="请输入字典类型" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input type="textarea" :rows="3" v-model="form.remark" placeholder="请输入备注" clearable></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="visible=false">取 消</el-button>
|
||||
<el-button v-if="mode!=='show'" type="primary" :loading="isSaveing" @click="submit()">保 存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {getCurrentInstance, ref} from 'vue'
|
||||
import api from "@/api/index"
|
||||
|
||||
defineExpose({
|
||||
open
|
||||
})
|
||||
const emit = defineEmits(['success', 'closed'])
|
||||
const formRef = ref(null)
|
||||
const {proxy} = getCurrentInstance()
|
||||
|
||||
let mode = ref('add')
|
||||
let titleMap = ref({
|
||||
add: '新增',
|
||||
edit: '编辑',
|
||||
show: '查看'
|
||||
})
|
||||
let visible = ref(false)
|
||||
let isSaveing = ref(false)
|
||||
let form = ref({
|
||||
dict_id: null,
|
||||
dict_name: null,
|
||||
dict_type: null,
|
||||
remark: null
|
||||
})
|
||||
const rules = ref({
|
||||
dict_name: [
|
||||
{required: true, message: '请填写字典名称'}
|
||||
],
|
||||
dict_type: [
|
||||
{required: true, message: '请填写字典类型'}
|
||||
]
|
||||
})
|
||||
|
||||
function open(m = 'add', data = null) {
|
||||
mode.value = m
|
||||
visible.value = true
|
||||
Object.assign(form.value, data)
|
||||
}
|
||||
|
||||
async function submit() {
|
||||
// 校验登录
|
||||
const validate = await formRef.value.validate().catch(() => {
|
||||
});
|
||||
if (!validate) {
|
||||
return false
|
||||
}
|
||||
isSaveing.value = true;
|
||||
const res = form.value.dict_id ? await api.system.dict.edit(form.value) : await api.system.dict.add(form.value);
|
||||
isSaveing.value = false;
|
||||
emit('success')
|
||||
visible.value = false;
|
||||
proxy.$message.success(res.msg)
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,18 +1,18 @@
|
|||
<template>
|
||||
<draggable :list="fields" :scroll="true" animation="200" item-key="id" class="w100 h100"
|
||||
<draggable :list="data.fields" :scroll="true" animation="200" item-key="id" class="w100 h100"
|
||||
:group="group" @update:list="fields = $event" @add="addComp" @sort="sortComp"
|
||||
ghostClass="ghostClass" :class="{empty: fields.length === 0, layout: isRow}">
|
||||
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': curr===element.id}"
|
||||
<el-row v-if="element.name === 'layout'" class="item row" :class="{'active': field.id===element.id}"
|
||||
@click.stop="clickComp(element)" v-bind="element.props">
|
||||
<span class="name">{{ element.field_name }}</span>
|
||||
<drag :fields="element.children" v-model:curKey="curr" :name="element.field_name"
|
||||
:is-row="true" v-model:counter="counter" @change="changeHandle"/>
|
||||
<drag :fields="element.children" :config="data.config" :data
|
||||
:name="element.field_name" :is-row="true"/>
|
||||
</el-row>
|
||||
<item v-else class="item" :class="{'active': curr===element.id}" :field="element"
|
||||
<item v-else class="item" :class="{'active': field.id===element.id}" :field="element"
|
||||
@click.stop="clickComp(element)"/>
|
||||
<div v-if="curr===element.id" class="tools-box">
|
||||
<div v-if="field.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>
|
||||
|
|
@ -30,71 +30,52 @@ import draggable from 'vuedraggable'
|
|||
import {computed, nextTick} from "vue"
|
||||
import item from "./item.vue"
|
||||
import drag from "./drag.vue"
|
||||
import tools from "@/utils/tools.js"
|
||||
|
||||
const emit = defineEmits(['change', 'update:curKey', 'update:counter'])
|
||||
import tools from "@/utils/tools"
|
||||
import FormBuild from "./formBuild"
|
||||
|
||||
const props = defineProps({
|
||||
fields: {type: Array, default: []},
|
||||
data: {type: FormBuild, default: {}},
|
||||
curKey: {type: String, default: ''},
|
||||
isRow: {type: Boolean, default: false},
|
||||
counter: {type: Number, default: 0},
|
||||
name: {type: String, default: 'page'}
|
||||
})
|
||||
|
||||
const group = {name: props.name, pull: true, put: true}
|
||||
const curr = computed({
|
||||
get() {
|
||||
return props.curKey
|
||||
},
|
||||
set(value) {
|
||||
emit('update:curKey', value)
|
||||
}
|
||||
})
|
||||
|
||||
const counter = computed({
|
||||
get() {
|
||||
return props.counter
|
||||
},
|
||||
set(value) {
|
||||
emit('update:counter', value)
|
||||
}
|
||||
const field = computed(() => {
|
||||
return props.data.activeField || {}
|
||||
})
|
||||
|
||||
// 排序
|
||||
function sortComp(e) {
|
||||
let element = props.fields[e.newIndex]
|
||||
let element = props.data.fields[e.newIndex]
|
||||
if (element) {
|
||||
curr.value = element.id
|
||||
emit('change', element)
|
||||
props.data.setActiveField(element)
|
||||
}
|
||||
}
|
||||
|
||||
// 添加项时
|
||||
function addComp(e) {
|
||||
let element = props.fields[e.newIndex]
|
||||
let element = props.data.fields[e.newIndex]
|
||||
if (props.isRow) {
|
||||
element.span = 12
|
||||
}
|
||||
curr.value = element.id
|
||||
emit('change', element)
|
||||
props.data.setActiveField(element)
|
||||
}
|
||||
|
||||
// 选中项
|
||||
function clickComp(element) {
|
||||
if (curr.value === element.id) {
|
||||
if (field.value.id === element.id) {
|
||||
return;
|
||||
}
|
||||
curr.value = element.id
|
||||
emit('change', element)
|
||||
props.data.setActiveField(element)
|
||||
}
|
||||
|
||||
// 删除字段
|
||||
function delComp(index) {
|
||||
nextTick(() => {
|
||||
// 原数组长度
|
||||
const len = props.fields.length
|
||||
props.fields.splice(index, 1);
|
||||
const len = props.data.fields.length
|
||||
props.data.fields.splice(index, 1);
|
||||
let i = 0;
|
||||
if (len > 1) {
|
||||
if (index === 0) {
|
||||
|
|
@ -105,37 +86,31 @@ function delComp(index) {
|
|||
i = index
|
||||
}
|
||||
}
|
||||
let element = props.fields[i] || {}
|
||||
curr.value = element.id || null
|
||||
emit('change', element)
|
||||
let element = props.data.fields[i] || {}
|
||||
props.data.setActiveField(element)
|
||||
})
|
||||
}
|
||||
|
||||
function copyComp(index) {
|
||||
nextTick(() => {
|
||||
// 复制当前元素到尾部
|
||||
const tmp = JSON.parse(JSON.stringify(props.fields[index]))
|
||||
const tmp = JSON.parse(JSON.stringify(props.data.fields[index]))
|
||||
tmp.field_name = increaseNum(tmp.field_name)
|
||||
tmp.id = increaseNum(tmp.id)
|
||||
counter.value++
|
||||
props.fields.push(tmp)
|
||||
props.data.config.counter++
|
||||
props.data.fields.push(tmp)
|
||||
// 将复制的元素移动到当前元素下边
|
||||
tools.array.zIndexTo(props.fields, props.fields.length - 1, index + 1)
|
||||
let element = props.fields[index + 1]
|
||||
curr.value = element.id
|
||||
emit('change', element)
|
||||
tools.array.zIndexTo(props.data.fields, props.data.fields.length - 1, index + 1)
|
||||
let element = props.data.fields[index + 1]
|
||||
props.data.setActiveField(element)
|
||||
})
|
||||
}
|
||||
|
||||
function increaseNum(str) {
|
||||
return str.replace(/(\d+)(?!.*\d)/, () => {
|
||||
return props.counter.toString();
|
||||
return props.data.config.counter.toString();
|
||||
});
|
||||
}
|
||||
|
||||
function changeHandle(e) {
|
||||
emit('change', e)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
interface Config {
|
||||
ref: string,
|
||||
model: string,
|
||||
rules: string,
|
||||
size: string,
|
||||
labelPosition: string,
|
||||
labelWidth: number,
|
||||
disabled: boolean,
|
||||
isMobile: boolean,
|
||||
counter: 0
|
||||
}
|
||||
|
||||
export default class FormBuild {
|
||||
// 表单配置
|
||||
config: Config
|
||||
// 字段信息
|
||||
fields: Array<any>
|
||||
// 激活字段
|
||||
activeField: Object
|
||||
|
||||
constructor() {
|
||||
this.config = {
|
||||
ref: 'formRef',
|
||||
model: 'form',
|
||||
rules: 'rules',
|
||||
size: 'default',
|
||||
labelPosition: 'right',
|
||||
labelWidth: 100,
|
||||
disabled: false,
|
||||
isMobile: false,
|
||||
counter: 0
|
||||
}
|
||||
this.fields = []
|
||||
this.activeField = null
|
||||
}
|
||||
|
||||
restData() {
|
||||
this.config = {
|
||||
ref: 'formRef',
|
||||
model: 'form',
|
||||
rules: 'rules',
|
||||
size: 'default',
|
||||
labelPosition: 'right',
|
||||
labelWidth: 100,
|
||||
disabled: false,
|
||||
isMobile: false,
|
||||
counter: 0
|
||||
}
|
||||
this.fields = []
|
||||
}
|
||||
|
||||
initData(config: Config, fields: Array<any>) {
|
||||
this.config = config
|
||||
this.fields = fields
|
||||
}
|
||||
|
||||
setActiveField(field: Object) {
|
||||
this.activeField = field
|
||||
}
|
||||
}
|
||||
|
|
@ -1,67 +1,43 @@
|
|||
<template>
|
||||
<el-container class="pi-panel">
|
||||
<el-main class="main">
|
||||
<left-panel @addField="addField" v-model:counter="counter"></left-panel>
|
||||
<el-divider direction="vertical" style="height: 100%"/>
|
||||
<center-panel ref="centerRef" :fields="fields" :config="config" @change="setField"
|
||||
v-model:counter="counter"></center-panel>
|
||||
<el-divider direction="vertical" style="height: 100%"/>
|
||||
<right-panel :config="config" :curField="curField" @save="tempSave"></right-panel>
|
||||
</el-main>
|
||||
<left-panel :data="formData"></left-panel>
|
||||
<center-panel ref="centerRef" :data="formData"></center-panel>
|
||||
<right-panel :data="formData" :fieldd="field"></right-panel>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {onMounted, ref, getCurrentInstance} from "vue"
|
||||
import {onMounted, ref, reactive} from "vue"
|
||||
import leftPanel from "./left"
|
||||
import centerPanel from "./center"
|
||||
import rightPanel from "./right"
|
||||
import tools from "@/utils/tools"
|
||||
import FormBuild from "./formBuild"
|
||||
|
||||
const {proxy} = getCurrentInstance()
|
||||
const centerRef = ref(null)
|
||||
let fields = ref([])
|
||||
let config = ref({
|
||||
ref: 'formRef',
|
||||
model: 'form',
|
||||
rules: 'rules',
|
||||
size: 'default',
|
||||
labelPosition: 'right',
|
||||
labelWidth: 100,
|
||||
disabled: false
|
||||
defineOptions({
|
||||
name: "toolsForm"
|
||||
})
|
||||
let curField = ref({})
|
||||
let counter = ref(0)
|
||||
|
||||
const centerRef = ref(null)
|
||||
|
||||
let formData = reactive(new FormBuild())
|
||||
let field = ref({})
|
||||
|
||||
onMounted(() => {
|
||||
fields.value = tools.data.get("FORM-FIELDS-DATA") || []
|
||||
const _config = tools.data.get("FORM-CONFIG-DATA")
|
||||
if (_config) {
|
||||
config.value = _config
|
||||
const fields = tools.data.get("FORM-FIELDS")
|
||||
const config = tools.data.get("FORM-CONFIG")
|
||||
if (fields && config) {
|
||||
formData.initData(config, fields)
|
||||
}
|
||||
counter.value = tools.data.get("FORM-COUNTER-DATA") || 0
|
||||
})
|
||||
|
||||
function setField(v) {
|
||||
curField.value = v
|
||||
function activeField(v) {
|
||||
field.value = v
|
||||
}
|
||||
|
||||
function addField(e) {
|
||||
centerRef.value.clickAddComp(e)
|
||||
}
|
||||
|
||||
function tempSave() {
|
||||
console.log("保存参数", fields.value)
|
||||
tools.data.set("FORM-FIELDS-DATA", fields.value)
|
||||
tools.data.set("FORM-CONFIG-DATA", config.value)
|
||||
tools.data.set("FORM-COUNTER-DATA", counter.value)
|
||||
proxy.$message.success("保存成功")
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.main {
|
||||
.pi-panel {
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<section class="panel">
|
||||
<el-aside class="panel">
|
||||
<el-scrollbar>
|
||||
<div class="title">
|
||||
<el-text>
|
||||
|
|
@ -9,7 +9,8 @@
|
|||
输入组件
|
||||
</el-text>
|
||||
</div>
|
||||
<draggable v-model="inputComps" animation="200" item-key="name" class="go-base" :group="group" :sort="false"
|
||||
<draggable v-model="inputComps" animation="200" item-key="name" class="draggroup" :group="group"
|
||||
:sort="false"
|
||||
:clone="cloneField">
|
||||
<template #item="{ element }">
|
||||
<div class="item" @click="handleClick(element)">
|
||||
|
|
@ -31,7 +32,8 @@
|
|||
选择组件
|
||||
</el-text>
|
||||
</div>
|
||||
<draggable v-model="choiceComps" animation="200" item-key="name" class="go-base" :group="group" :sort="false"
|
||||
<draggable v-model="choiceComps" animation="200" item-key="name" class="draggroup" :group="group"
|
||||
:sort="false"
|
||||
:clone="cloneField">
|
||||
<template #item="{ element }">
|
||||
<div class="item" @click="handleClick(element)">
|
||||
|
|
@ -53,7 +55,8 @@
|
|||
布局组件
|
||||
</el-text>
|
||||
</div>
|
||||
<draggable v-model="layoutComps" animation="200" item-key="name" class="go-base" :group="group" :sort="false"
|
||||
<draggable v-model="layoutComps" animation="200" item-key="name" class="draggroup" :group="group"
|
||||
:sort="false"
|
||||
:clone="cloneField">
|
||||
<template #item="{ element }">
|
||||
<div class="item" @click="handleClick(element)">
|
||||
|
|
@ -68,234 +71,38 @@
|
|||
</template>
|
||||
</draggable>
|
||||
</el-scrollbar>
|
||||
</section>
|
||||
</el-aside>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import draggable from 'vuedraggable'
|
||||
import {computed, ref} from "vue"
|
||||
import FormBuild from "./formBuild"
|
||||
import {inputComps, choiceComps, layoutComps} from "./config"
|
||||
|
||||
const emit = defineEmits(['addField', 'update:counter'])
|
||||
const props = defineProps({
|
||||
counter: {type: Number, default: 0}
|
||||
data: {type: FormBuild, default: {}}
|
||||
})
|
||||
|
||||
const group = {name: 'base', pull: 'clone', put: false}
|
||||
const inputComps = [{
|
||||
title: "单行文本",
|
||||
icon: "pi-icon-line-input",
|
||||
name: "text",
|
||||
props: {
|
||||
type: 'text'
|
||||
},
|
||||
rules: [{regex: '', message: ''}],
|
||||
width: "100%",
|
||||
required: false
|
||||
}, {
|
||||
title: "多行文本",
|
||||
icon: "pi-icon-multi-input",
|
||||
name: "textarea",
|
||||
props: {
|
||||
type: 'textarea'
|
||||
},
|
||||
rules: [],
|
||||
width: "100%",
|
||||
required: false
|
||||
}, {
|
||||
title: "密码",
|
||||
icon: "pi-icon-lock",
|
||||
name: "password",
|
||||
props: {
|
||||
type: 'password',
|
||||
showPassword: true
|
||||
},
|
||||
rules: [],
|
||||
width: "100%",
|
||||
required: false
|
||||
}, {
|
||||
title: "计数器",
|
||||
icon: "pi-icon-number-input",
|
||||
name: "number",
|
||||
props: {
|
||||
controlsPosition: ''
|
||||
},
|
||||
rules: [],
|
||||
width: "100%",
|
||||
required: false,
|
||||
value: 1
|
||||
}]
|
||||
const choiceComps = [{
|
||||
title: "下拉组件",
|
||||
icon: "pi-icon-select",
|
||||
name: "select",
|
||||
props: {},
|
||||
rules: [],
|
||||
options: [],
|
||||
width: "100%",
|
||||
required: false,
|
||||
}, {
|
||||
title: "级联组件",
|
||||
icon: "pi-icon-cascader",
|
||||
name: "cascader",
|
||||
props: {
|
||||
props: {
|
||||
label: 'label',
|
||||
value: 'value',
|
||||
multiple: false,
|
||||
},
|
||||
options: [{label: '一号楼', value: 'r1', children: [{label: '二单元', value: 'c2'}]}]
|
||||
},
|
||||
rules: [],
|
||||
width: "100%",
|
||||
required: false,
|
||||
}, {
|
||||
title: "单选组件",
|
||||
icon: "pi-icon-radio",
|
||||
name: "radio",
|
||||
props: {},
|
||||
rules: [],
|
||||
options: [],
|
||||
width: "100%",
|
||||
style: '',
|
||||
required: false,
|
||||
}, {
|
||||
title: "多选组件",
|
||||
icon: "pi-icon-checkbox",
|
||||
name: "checkbox",
|
||||
props: {},
|
||||
rules: [],
|
||||
options: [],
|
||||
style: '',
|
||||
required: false,
|
||||
}, {
|
||||
title: "开关",
|
||||
icon: "pi-icon-switch",
|
||||
name: "switch",
|
||||
props: {},
|
||||
rules: [],
|
||||
required: false,
|
||||
}, {
|
||||
title: "滑块",
|
||||
icon: "pi-icon-slider",
|
||||
name: "slider",
|
||||
props: {},
|
||||
rules: [],
|
||||
width: "100%",
|
||||
required: false,
|
||||
}, {
|
||||
title: "时间选择",
|
||||
icon: "pi-icon-time-picker",
|
||||
name: "time",
|
||||
props: {
|
||||
format: 'HH:mm:ss',
|
||||
valueFormat: 'HH:mm:ss'
|
||||
},
|
||||
rules: []
|
||||
}, {
|
||||
title: "时间范围",
|
||||
icon: "pi-icon-time-range",
|
||||
name: "timerange",
|
||||
props: {
|
||||
isRange: true,
|
||||
format: 'HH:mm:ss',
|
||||
valueFormat: 'HH:mm:ss'
|
||||
},
|
||||
rules: [],
|
||||
width: "100%",
|
||||
required: false,
|
||||
}, {
|
||||
title: "日期选择",
|
||||
icon: "pi-icon-date-picker",
|
||||
name: "date",
|
||||
props: {
|
||||
type: "date",
|
||||
format: 'YYYY-MM-DD',
|
||||
valueFormat: 'YYYY-MM-DD'
|
||||
},
|
||||
rules: [],
|
||||
width: "100%",
|
||||
required: false,
|
||||
}, {
|
||||
title: "日期范围",
|
||||
icon: "pi-icon-date-range",
|
||||
name: "daterange",
|
||||
props: {
|
||||
type: "daterange",
|
||||
format: 'YYYY-MM-DD',
|
||||
valueFormat: 'YYYY-MM-DD'
|
||||
},
|
||||
rules: [],
|
||||
width: "100%",
|
||||
required: false,
|
||||
}, {
|
||||
title: "评分",
|
||||
icon: "pi-icon-rate",
|
||||
name: "rate",
|
||||
props: {},
|
||||
rules: [],
|
||||
required: false,
|
||||
}, {
|
||||
title: "颜色选择",
|
||||
icon: "pi-icon-color-picker",
|
||||
name: "color",
|
||||
props: {},
|
||||
rules: [],
|
||||
required: false,
|
||||
}, {
|
||||
title: "上传",
|
||||
icon: "pi-icon-upload-file",
|
||||
name: "upload",
|
||||
props: {
|
||||
listType: 'text',
|
||||
name: 'file'
|
||||
},
|
||||
rules: [],
|
||||
required: false,
|
||||
btnText: "点击上传"
|
||||
}]
|
||||
const layoutComps = [{
|
||||
title: "行容器",
|
||||
icon: "pi-icon-row-layout",
|
||||
name: "layout",
|
||||
props: {
|
||||
gutter: 15
|
||||
},
|
||||
children: []
|
||||
}, {
|
||||
title: "按钮",
|
||||
icon: "pi-icon-button",
|
||||
name: "button",
|
||||
props: {
|
||||
type: 'primary'
|
||||
},
|
||||
btnText: "按钮文字"
|
||||
}];
|
||||
const counter = computed({
|
||||
get() {
|
||||
return props.counter
|
||||
},
|
||||
set(value) {
|
||||
emit('update:counter', value)
|
||||
}
|
||||
})
|
||||
|
||||
function cloneField(e) {
|
||||
const field = JSON.parse(JSON.stringify(e));
|
||||
field.field_name = field.name + "_" + counter.value;
|
||||
field.id = field.name + counter.value
|
||||
counter.value++
|
||||
field.field_name = field.name + "_" + props.data.config.counter;
|
||||
field.id = field.name + props.data.config.counter
|
||||
props.data.config.counter++
|
||||
return field
|
||||
}
|
||||
|
||||
function handleClick(e) {
|
||||
emit('addField', cloneField(e))
|
||||
let field = cloneField(e)
|
||||
props.data.fields.push(field)
|
||||
props.data.setActiveField(field)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.panel {
|
||||
width: 260px;
|
||||
padding: 10px;
|
||||
|
||||
.title {
|
||||
margin-bottom: 10px;
|
||||
|
|
@ -318,14 +125,14 @@ function handleClick(e) {
|
|||
display: none !important;
|
||||
}
|
||||
|
||||
.go-base {
|
||||
.draggroup {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.item {
|
||||
width: 125px;
|
||||
width: 115px;
|
||||
font-size: 12px;
|
||||
cursor: move;
|
||||
background: #f6f7ff;
|
||||
|
|
|
|||
|
|
@ -1,69 +1,71 @@
|
|||
<template>
|
||||
<section class="panel">
|
||||
<el-aside class="panel">
|
||||
<el-scrollbar>
|
||||
<el-tabs v-model="activeName" stretch>
|
||||
<el-tab-pane label="组件属性" name="field">
|
||||
<el-form v-model="fForm" label-width="90px">
|
||||
<el-form-item v-if="fForm.name !== 'button' && fForm.name !== 'layout'" label="字段名" prop="field_name">
|
||||
<el-input v-model="fForm.field_name"></el-input>
|
||||
<el-form :model="field" label-width="90px">
|
||||
<el-form-item v-if="field.name !== 'button' && field.name !== 'layout'" label="字段名"
|
||||
prop="field_name">
|
||||
<el-input v-model="field.field_name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="fForm.name !== 'layout'" label="标题" prop="title">
|
||||
<el-input v-model="fForm.title"></el-input>
|
||||
<el-form-item v-if="field.name !== 'layout'" label="标题" prop="title">
|
||||
<el-input v-model="field.title"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="fForm.name !== 'button' && fForm.name !== 'layout'" label="默认值" prop="value">
|
||||
<el-input v-model="fForm.value"></el-input>
|
||||
<el-form-item v-if="field.name !== 'button' && field.name !== 'layout'" label="默认值"
|
||||
prop="value">
|
||||
<el-input v-model="field.value"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="fForm.span !== undefined" label="栅格列数" prop="span">
|
||||
<el-slider v-model="fForm.span" :min="1" :max="24"/>
|
||||
<el-form-item v-if="field.span !== undefined" label="栅格列数" prop="span">
|
||||
<el-slider v-model="field.span" :min="1" :max="24"/>
|
||||
</el-form-item>
|
||||
<template v-for="item in fieldEditors[fForm.name] || []" :key="item.key">
|
||||
<template v-for="item in fieldEditors[field.name] || []" :key="item.key">
|
||||
<el-form-item :label="item.label">
|
||||
<el-input
|
||||
v-if="item.type === 'input'"
|
||||
:model-value="getByPath(fForm, item.key)"
|
||||
@input="val => setByPath(fForm, item.key, val)"
|
||||
:model-value="getByPath(field, item.key)"
|
||||
@input="val => setByPath(field, item.key, val)"
|
||||
clearable
|
||||
/>
|
||||
<el-input
|
||||
v-else-if="item.type === 'number'"
|
||||
type="number"
|
||||
:model-value="getByPath(fForm, item.key)"
|
||||
@input="val => setByPath(fForm, item.key, Number(val))"
|
||||
:model-value="getByPath(field, item.key)"
|
||||
@input="val => setByPath(field, item.key, Number(val))"
|
||||
/>
|
||||
<el-switch
|
||||
v-else-if="item.type === 'switch'"
|
||||
:model-value="getByPath(fForm, item.key)"
|
||||
@change="val => setByPath(fForm, item.key, val)"
|
||||
:model-value="getByPath(field, item.key)"
|
||||
@change="val => setByPath(field, item.key, val)"
|
||||
/>
|
||||
<el-color-picker v-else-if="item.type === 'color'" show-alpha
|
||||
:model-value="getByPath(fForm, item.key)"
|
||||
@change="val => setByPath(fForm, item.key, val)"/>
|
||||
:model-value="getByPath(field, item.key)"
|
||||
@change="val => setByPath(field, item.key, val)"/>
|
||||
<el-radio-group v-else-if="item.type === 'radio'"
|
||||
:model-value="getByPath(fForm, item.key)"
|
||||
@change="val => setByPath(fForm, item.key, val)">
|
||||
:model-value="getByPath(field, item.key)"
|
||||
@change="val => setByPath(field, 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(fForm, item.key)"
|
||||
@change="val => setByPath(fForm, item.key, val)">
|
||||
<el-select v-else-if="item.type === 'select'" :model-value="getByPath(field, item.key)"
|
||||
@change="val => setByPath(field, 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(fForm, item.key)"
|
||||
@update:modelValue="val => setByPath(fForm, item.key, val)"
|
||||
:model-value="getByPath(field, item.key)"
|
||||
@update:modelValue="val => setByPath(field, item.key, val)"
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<el-form-item label="是否必填" v-if="fForm.required !== undefined">
|
||||
<el-switch v-model="fForm.required"/>
|
||||
<el-form-item label="是否必填" v-if="field.required !== undefined">
|
||||
<el-switch v-model="field.required"/>
|
||||
</el-form-item>
|
||||
<template v-if="fForm.options !== undefined">
|
||||
<template v-if="field.options !== undefined">
|
||||
<el-divider>选项</el-divider>
|
||||
<pi-draggable v-model="fForm.options" item-key="label" :template="{label:'', value:''}">
|
||||
<pi-draggable v-model="field.options" item-key="label" :template="{label:'', value:''}">
|
||||
<template #default="scope">
|
||||
<div style="display:flex;">
|
||||
<el-input v-model="scope.element.label" placeholder="label"/>
|
||||
|
|
@ -72,9 +74,9 @@
|
|||
</template>
|
||||
</pi-draggable>
|
||||
</template>
|
||||
<template v-if="fForm.name !== 'button' && fForm.name !== 'layout'">
|
||||
<template v-if="field.name !== 'button' && field.name !== 'layout'">
|
||||
<el-divider>正则校验</el-divider>
|
||||
<pi-draggable v-model="fForm.rules" item-key="regex" :template="{regex:'',message:''}">
|
||||
<pi-draggable v-model="field.rules" item-key="regex" :template="{regex:'',message:''}">
|
||||
<template #default="scope">
|
||||
<el-form-item label="表达式">
|
||||
<el-input v-model="scope.element.regex"/>
|
||||
|
|
@ -88,44 +90,41 @@
|
|||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="表单属性" name="form">
|
||||
<el-form v-model="cForm" label-width="90px">
|
||||
<el-form :model="data.config" label-width="90px">
|
||||
<el-form-item label="表单名称" prop="ref">
|
||||
<el-input v-model="cForm.ref"></el-input>
|
||||
<el-input v-model="data.config.ref"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="表单模型" prop="model">
|
||||
<el-input v-model="cForm.model"></el-input>
|
||||
<el-input v-model="data.config.model"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="校验模型" prop="rules">
|
||||
<el-input v-model="cForm.rules"></el-input>
|
||||
<el-input v-model="data.config.rules"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="表单尺寸" prop="size">
|
||||
<el-radio-group v-model="cForm.size">
|
||||
<el-radio-group v-model="data.config.size">
|
||||
<el-radio-button value="large">较大</el-radio-button>
|
||||
<el-radio-button value="default">默认</el-radio-button>
|
||||
<el-radio-button value="small">较小</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="标签对齐" prop="labelPosition">
|
||||
<el-radio-group v-model="cForm.labelPosition">
|
||||
<el-radio-group v-model="data.config.labelPosition">
|
||||
<el-radio-button value="left">左对齐</el-radio-button>
|
||||
<el-radio-button value="right">右对齐</el-radio-button>
|
||||
<el-radio-button value="top">顶部对齐</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="标签宽度" prop="labelWidth">
|
||||
<el-input-number v-model="cForm.labelWidth"/>
|
||||
<el-input-number v-model="data.config.labelWidth"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="禁用表单" prop="disabled">
|
||||
<el-switch v-model="cForm.disabled"/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="act">
|
||||
<el-button type="primary" @click="emit('save')">暂存</el-button>
|
||||
<el-switch v-model="data.config.disabled"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-scrollbar>
|
||||
</section>
|
||||
</el-aside>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
|
@ -133,34 +132,23 @@ import {computed, ref} from "vue";
|
|||
import piIcon from "@/components/piIcon"
|
||||
import piDraggable from "@/components/piDraggable"
|
||||
import {fieldEditors, getByPath, setByPath} from "./config"
|
||||
import FormBuild from "./formBuild";
|
||||
|
||||
const emit = defineEmits(['update:field'])
|
||||
const props = defineProps({
|
||||
curField: {type: Object, default: {}},
|
||||
config: {type: Object, default: {}}
|
||||
data: {type: FormBuild, default: {}}
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue', 'save'])
|
||||
let activeName = ref("field")
|
||||
let cForm = computed({
|
||||
get() {
|
||||
return props.config
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('update:modelValue', value)
|
||||
}
|
||||
})
|
||||
let fForm = computed({
|
||||
get() {
|
||||
return props.curField
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('update:modelValue', value)
|
||||
}
|
||||
const field = computed(() => {
|
||||
return props.data.activeField || {}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.panel {
|
||||
width: 350px
|
||||
width: 350px;
|
||||
padding: 10px;
|
||||
border-left: 1px solid var(--el-border-color-light);
|
||||
}
|
||||
|
||||
:deep(.el-scrollbar__bar) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue