perf: formdesign
parent
45a4ac80d9
commit
f4ca72a7a2
|
@ -1,18 +1,10 @@
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import type { PropType } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
import { defineComponent } from 'vue'
|
|
||||||
import { Col, Row } from 'ant-design-vue'
|
import { Col, Row } from 'ant-design-vue'
|
||||||
import type { IFormConfig, IVFormComponent } from '../../../typings/v-form-component'
|
import type { IFormConfig, IVFormComponent } from '../../../typings/v-form-component'
|
||||||
import VFormItem from '../../VFormItem/index.vue'
|
import VFormItem from '../../VFormItem/index.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
defineProps({
|
||||||
name: 'FormRender',
|
|
||||||
components: {
|
|
||||||
VFormItem,
|
|
||||||
Row,
|
|
||||||
Col,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
formData: {
|
formData: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
|
@ -29,16 +21,20 @@ export default defineComponent({
|
||||||
type: Function as PropType<(key: string, value: any) => void>,
|
type: Function as PropType<(key: string, value: any) => void>,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
},
|
|
||||||
emits: ['change', 'submit', 'reset'],
|
|
||||||
setup(_props) {},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['change', 'submit', 'reset'])
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<template v-if="['Grid'].includes(schema.component)">
|
<template v-if="['Grid'].includes(schema.component)">
|
||||||
<Row class="grid-row">
|
<Row class="grid-row">
|
||||||
<Col v-for="(colItem, index) in schema.columns" :key="index" class="grid-col" :span="colItem.span">
|
<Col
|
||||||
|
v-for="(colItem, index) in schema.columns"
|
||||||
|
:key="index"
|
||||||
|
class="grid-col"
|
||||||
|
:span="colItem.span"
|
||||||
|
>
|
||||||
<FormRender
|
<FormRender
|
||||||
v-for="(item, k) in colItem.children"
|
v-for="(item, k) in colItem.children"
|
||||||
:key="k"
|
:key="k"
|
||||||
|
@ -56,11 +52,14 @@ export default defineComponent({
|
||||||
:schema="schema"
|
:schema="schema"
|
||||||
:form-data="formData"
|
:form-data="formData"
|
||||||
:set-form-model="setFormModel"
|
:set-form-model="setFormModel"
|
||||||
@change="$emit('change', { schema, value: $event })"
|
@change="emit('change', { schema, value: $event })"
|
||||||
@submit="$emit('submit', schema)"
|
@submit="emit('submit', schema)"
|
||||||
@reset="$emit('reset')"
|
@reset="emit('reset')"
|
||||||
|
>
|
||||||
|
<template
|
||||||
|
v-if="schema.componentProps && schema.componentProps.slotName"
|
||||||
|
#[schema.componentProps!.slotName]
|
||||||
>
|
>
|
||||||
<template v-if="schema.componentProps && schema.componentProps.slotName" #[schema.componentProps!.slotName]>
|
|
||||||
<slot :name="schema.componentProps!.slotName" />
|
<slot :name="schema.componentProps!.slotName" />
|
||||||
</template>
|
</template>
|
||||||
</VFormItem>
|
</VFormItem>
|
||||||
|
|
|
@ -45,12 +45,16 @@ export default defineComponent({
|
||||||
})
|
})
|
||||||
|
|
||||||
const noHiddenList = computed(() => {
|
const noHiddenList = computed(() => {
|
||||||
return props.formConfig.schemas && props.formConfig.schemas.filter(item => item.hidden !== true)
|
return (
|
||||||
|
props.formConfig.schemas
|
||||||
|
&& props.formConfig.schemas.filter(item => item.hidden !== true)
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const fApi = useVModel(props, 'fApi', emit)
|
const fApi = useVModel(props, 'fApi', emit)
|
||||||
|
|
||||||
const { submit, validate, clearValidate, resetFields, validateField } = useFormInstanceMethods(props, formModelNew, context, eFormModel)
|
const { submit, validate, clearValidate, resetFields, validateField }
|
||||||
|
= useFormInstanceMethods(props, formModelNew, context, eFormModel)
|
||||||
|
|
||||||
const { linkOn, ...methods } = useVFormMethods(
|
const { linkOn, ...methods } = useVFormMethods(
|
||||||
{ formConfig: props.formConfig, formData: props.formModel } as unknown as IProps,
|
{ formConfig: props.formConfig, formData: props.formModel } as unknown as IProps,
|
||||||
|
@ -78,7 +82,9 @@ export default defineComponent({
|
||||||
/**
|
/**
|
||||||
* 获取表单属性
|
* 获取表单属性
|
||||||
*/
|
*/
|
||||||
const formModelProps = computed(() => omit(props.formConfig, ['disabled', 'labelWidth', 'schemas']) as Recordable)
|
const formModelProps = computed(
|
||||||
|
() => omit(props.formConfig, ['disabled', 'labelWidth', 'schemas']) as Recordable,
|
||||||
|
)
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
submit()
|
submit()
|
||||||
|
@ -127,7 +133,10 @@ export default defineComponent({
|
||||||
@reset="resetFields"
|
@reset="resetFields"
|
||||||
>
|
>
|
||||||
<template v-if="schema && schema.componentProps" #[`schema.componentProps!.slotName`]>
|
<template v-if="schema && schema.componentProps" #[`schema.componentProps!.slotName`]>
|
||||||
<slot :name="schema.componentProps!.slotName" v-bind="{ formModel, field: schema.field, schema }" />
|
<slot
|
||||||
|
:name="schema.componentProps!.slotName"
|
||||||
|
v-bind="{ formModel, field: schema.field, schema }"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</FormRender>
|
</FormRender>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<!--
|
<!--
|
||||||
* @Description: 渲染代码
|
* @Description: 渲染代码
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { computed, defineComponent, reactive, toRefs } from 'vue'
|
import { computed, reactive } from 'vue'
|
||||||
import { Modal } from 'ant-design-vue'
|
import { Modal } from 'ant-design-vue'
|
||||||
import { formatRules, removeAttrs } from '../../../utils'
|
import { formatRules, removeAttrs } from '../../../utils'
|
||||||
import type { IFormConfig } from '../../../typings/v-form-component'
|
import type { IFormConfig } from '../../../typings/v-form-component'
|
||||||
|
@ -38,37 +38,31 @@ let codeVueLast = `
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<\/script>`
|
<\/script>`;
|
||||||
//
|
//
|
||||||
export default defineComponent({
|
|
||||||
name: 'CodeModal',
|
|
||||||
components: { PreviewCode, Modal },
|
|
||||||
setup() {
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
open: false,
|
open: false,
|
||||||
jsonData: {} as IFormConfig
|
jsonData: {} as IFormConfig,
|
||||||
})
|
});
|
||||||
|
|
||||||
const showModal = (formConfig: IFormConfig) => {
|
const showModal = (formConfig: IFormConfig) => {
|
||||||
formConfig.schemas && formatRules(formConfig.schemas)
|
formConfig.schemas && formatRules(formConfig.schemas);
|
||||||
state.open = true
|
state.open = true;
|
||||||
state.jsonData = formConfig
|
state.jsonData = formConfig;
|
||||||
}
|
};
|
||||||
|
|
||||||
const editorVueJson = computed(() => {
|
const editorVueJson = computed(() => {
|
||||||
return codeVueFront + JSON.stringify(removeAttrs(state.jsonData), null, '\t') + codeVueLast
|
return codeVueFront + JSON.stringify(removeAttrs(state.jsonData), null, '\t') + codeVueLast;
|
||||||
})
|
});
|
||||||
|
|
||||||
return { ...toRefs(state), editorVueJson, showModal }
|
defineExpose({ showModal })
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<Modal
|
<Modal
|
||||||
title="代码"
|
title="代码"
|
||||||
:footer="null"
|
:footer="null"
|
||||||
:open="open"
|
:open="state.open"
|
||||||
@cancel="open = false"
|
@cancel="state.open = false"
|
||||||
wrapClassName="v-code-modal"
|
wrapClassName="v-code-modal"
|
||||||
style="top: 20px"
|
style="top: 20px"
|
||||||
width="850px"
|
width="850px"
|
||||||
|
|
|
@ -2,7 +2,20 @@
|
||||||
* @Description: 组件属性控件
|
* @Description: 组件属性控件
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Checkbox, Col, Empty, Form, FormItem, Input, InputNumber, RadioGroup, Row, Select, Switch } from 'ant-design-vue'
|
import {
|
||||||
|
Checkbox,
|
||||||
|
Col,
|
||||||
|
Empty,
|
||||||
|
Form,
|
||||||
|
FormItem,
|
||||||
|
Input,
|
||||||
|
InputNumber,
|
||||||
|
RadioGroup,
|
||||||
|
Row,
|
||||||
|
Select,
|
||||||
|
Switch,
|
||||||
|
} from 'ant-design-vue'
|
||||||
|
import RadioButtonGroup from '/@/components/Form/src/components/RadioButtonGroup.vue'
|
||||||
import { computed, defineComponent, ref, watch } from 'vue'
|
import { computed, defineComponent, ref, watch } from 'vue'
|
||||||
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
||||||
import {
|
import {
|
||||||
|
@ -14,7 +27,6 @@ import {
|
||||||
import { formItemsForEach, remove } from '../../../utils'
|
import { formItemsForEach, remove } from '../../../utils'
|
||||||
import type { IBaseFormAttrs } from '../config/formItemPropsConfig'
|
import type { IBaseFormAttrs } from '../config/formItemPropsConfig'
|
||||||
import FormOptions from './FormOptions.vue'
|
import FormOptions from './FormOptions.vue'
|
||||||
import RadioButtonGroup from '@/components/Form/src/components/RadioButtonGroup.vue'
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'ComponentProps',
|
name: 'ComponentProps',
|
||||||
|
@ -45,8 +57,10 @@ export default defineComponent({
|
||||||
|
|
||||||
const { formConfig } = useFormDesignState()
|
const { formConfig } = useFormDesignState()
|
||||||
|
|
||||||
if (formConfig.value.currentItem)
|
if (formConfig.value.currentItem) {
|
||||||
formConfig.value.currentItem.componentProps = formConfig.value.currentItem.componentProps || {}
|
formConfig.value.currentItem.componentProps
|
||||||
|
= formConfig.value.currentItem.componentProps || {}
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => formConfig.value.currentItem?.field,
|
() => formConfig.value.currentItem?.field,
|
||||||
|
@ -114,14 +128,14 @@ export default defineComponent({
|
||||||
// 控制性的选项
|
// 控制性的选项
|
||||||
const controlOptions = computed(() => {
|
const controlOptions = computed(() => {
|
||||||
return allOptions.value.filter((item) => {
|
return allOptions.value.filter((item) => {
|
||||||
return item.category === 'control'
|
return item.category == 'control'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// 非控制性选择
|
// 非控制性选择
|
||||||
const inputOptions = computed(() => {
|
const inputOptions = computed(() => {
|
||||||
return allOptions.value.filter((item) => {
|
return allOptions.value.filter((item) => {
|
||||||
return item.category === 'input'
|
return item.category == 'input'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -199,12 +213,23 @@ export default defineComponent({
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</div>
|
</div>
|
||||||
<FormItem label="关联字段">
|
<FormItem label="关联字段">
|
||||||
<Select v-model:value="formConfig.currentItem.link" mode="multiple" :options="linkOptions" />
|
<Select
|
||||||
|
v-model:value="formConfig.currentItem.link"
|
||||||
|
mode="multiple"
|
||||||
|
:options="linkOptions"
|
||||||
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|
||||||
<FormItem
|
<FormItem
|
||||||
v-if="
|
v-if="
|
||||||
['Select', 'CheckboxGroup', 'RadioGroup', 'TreeSelect', 'Cascader', 'AutoComplete'].includes(formConfig.currentItem.component)
|
[
|
||||||
|
'Select',
|
||||||
|
'CheckboxGroup',
|
||||||
|
'RadioGroup',
|
||||||
|
'TreeSelect',
|
||||||
|
'Cascader',
|
||||||
|
'AutoComplete',
|
||||||
|
].includes(formConfig.currentItem.component)
|
||||||
"
|
"
|
||||||
label="选项"
|
label="选项"
|
||||||
>
|
>
|
||||||
|
|
|
@ -3,7 +3,18 @@
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent, watch } from 'vue'
|
import { computed, defineComponent, watch } from 'vue'
|
||||||
import { Checkbox, Col, Empty, Form, FormItem, Input, RadioGroup, Select, Slider, Switch } from 'ant-design-vue'
|
import {
|
||||||
|
Checkbox,
|
||||||
|
Col,
|
||||||
|
Empty,
|
||||||
|
Form,
|
||||||
|
FormItem,
|
||||||
|
Input,
|
||||||
|
RadioGroup,
|
||||||
|
Select,
|
||||||
|
Slider,
|
||||||
|
Switch,
|
||||||
|
} from 'ant-design-vue'
|
||||||
import { isArray } from 'lodash-es'
|
import { isArray } from 'lodash-es'
|
||||||
import {
|
import {
|
||||||
advanceFormItemColProps,
|
advanceFormItemColProps,
|
||||||
|
@ -40,8 +51,10 @@ export default defineComponent({
|
||||||
() => {
|
() => {
|
||||||
if (formConfig.value.currentItem) {
|
if (formConfig.value.currentItem) {
|
||||||
formConfig.value.currentItem.itemProps = formConfig.value.currentItem.itemProps || {}
|
formConfig.value.currentItem.itemProps = formConfig.value.currentItem.itemProps || {}
|
||||||
formConfig.value.currentItem.itemProps.labelCol = formConfig.value.currentItem.itemProps.labelCol || {}
|
formConfig.value.currentItem.itemProps.labelCol
|
||||||
formConfig.value.currentItem.itemProps.wrapperCol = formConfig.value.currentItem.itemProps.wrapperCol || {}
|
= formConfig.value.currentItem.itemProps.labelCol || {}
|
||||||
|
formConfig.value.currentItem.itemProps.wrapperCol
|
||||||
|
= formConfig.value.currentItem.itemProps.wrapperCol || {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ deep: true, immediate: true },
|
{ deep: true, immediate: true },
|
||||||
|
|
|
@ -40,13 +40,19 @@ export default defineComponent({
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="drag-move-box" :class="{ active: schema.key === formConfig.currentItem?.key }" @click.stop="handleSelectItem">
|
<div
|
||||||
|
class="drag-move-box"
|
||||||
|
:class="{ active: schema.key === formConfig.currentItem?.key }"
|
||||||
|
@click.stop="handleSelectItem"
|
||||||
|
>
|
||||||
<div class="form-item-box">
|
<div class="form-item-box">
|
||||||
<VFormItem :form-config="formConfig" :schema="schema" />
|
<VFormItem :form-config="formConfig" :schema="schema" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="show-key-box">
|
<div class="show-key-box">
|
||||||
{{ schema.label + (schema.field ? `/${schema.field}` : '') }}
|
{{ schema.label + (schema.field ? `/${schema.field}` : '') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FormNodeOperate :schema="schema" :current-item="formConfig.currentItem" />
|
<FormNodeOperate :schema="schema" :current-item="formConfig.currentItem" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
<!--
|
<!--
|
||||||
* @Description: 节点操作复制删除控件
|
* @Description: 节点操作复制删除控件
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { computed, defineComponent } from 'vue'
|
import { computed } from 'vue'
|
||||||
import type { IVFormComponent } from '../../../typings/v-form-component'
|
import type { IVFormComponent } from '../../../typings/v-form-component'
|
||||||
import { remove } from '../../../utils'
|
import { remove } from '../../../utils'
|
||||||
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
||||||
import Icon from '@/components/Icon/index'
|
import { Icon } from '@/components/Icon'
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps({
|
||||||
name: 'FormNodeOperate',
|
|
||||||
components: {
|
|
||||||
Icon,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
schema: {
|
schema: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
|
@ -22,8 +17,8 @@ export default defineComponent({
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
},
|
})
|
||||||
setup(props) {
|
|
||||||
const { formConfig, formDesignMethods } = useFormDesignState()
|
const { formConfig, formDesignMethods } = useFormDesignState()
|
||||||
const activeClass = computed(() => {
|
const activeClass = computed(() => {
|
||||||
return props.schema.key === props.currentItem.key ? 'active' : 'unactivated'
|
return props.schema.key === props.currentItem.key ? 'active' : 'unactivated'
|
||||||
|
@ -31,15 +26,20 @@ export default defineComponent({
|
||||||
/**
|
/**
|
||||||
* 删除当前项
|
* 删除当前项
|
||||||
*/
|
*/
|
||||||
const handleDelete = () => {
|
function handleDelete() {
|
||||||
const traverse = (schemas: IVFormComponent[]) => {
|
const traverse = (schemas: IVFormComponent[]) => {
|
||||||
schemas.some((formItem, index) => {
|
schemas.some((formItem, index) => {
|
||||||
const { component, key } = formItem
|
const { component, key } = formItem;
|
||||||
// 处理栅格和标签页布局
|
// 处理栅格和标签页布局
|
||||||
;['Grid', 'Tabs'].includes(component) && formItem.columns?.forEach(item => traverse(item.children))
|
['Grid', 'Tabs'].includes(component)
|
||||||
|
&& formItem.columns?.forEach(item => traverse(item.children))
|
||||||
if (key === props.currentItem.key) {
|
if (key === props.currentItem.key) {
|
||||||
const params: IVFormComponent
|
const params: IVFormComponent
|
||||||
= schemas.length === 1 ? { component: '' } : schemas.length - 1 > index ? schemas[index + 1] : schemas[index - 1]
|
= schemas.length === 1
|
||||||
|
? { component: '' }
|
||||||
|
: schemas.length - 1 > index
|
||||||
|
? schemas[index + 1]
|
||||||
|
: schemas[index - 1]
|
||||||
formDesignMethods.handleSetSelectItem(params)
|
formDesignMethods.handleSetSelectItem(params)
|
||||||
remove(schemas, index)
|
remove(schemas, index)
|
||||||
return true
|
return true
|
||||||
|
@ -49,12 +49,9 @@ export default defineComponent({
|
||||||
traverse(formConfig.value!.schemas)
|
traverse(formConfig.value!.schemas)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleCopy = () => {
|
function handleCopy() {
|
||||||
formDesignMethods.handleCopy()
|
formDesignMethods.handleCopy()
|
||||||
}
|
}
|
||||||
return { activeClass, handleDelete, handleCopy }
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -1,20 +1,13 @@
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, reactive, toRefs } from 'vue'
|
|
||||||
import { Input } from 'ant-design-vue'
|
import { Input } from 'ant-design-vue'
|
||||||
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
||||||
import { remove } from '../../../utils'
|
import { remove } from '../../../utils'
|
||||||
import message from '../../../utils/message'
|
import message from '../../../utils/message'
|
||||||
import Icon from '@/components/Icon/index'
|
import { Icon } from '@/components/Icon'
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'FormOptions',
|
|
||||||
components: { Input, Icon },
|
|
||||||
// props: {},
|
|
||||||
setup() {
|
|
||||||
const state = reactive({})
|
|
||||||
const { formConfig } = useFormDesignState()
|
const { formConfig } = useFormDesignState()
|
||||||
const key = formConfig.value.currentItem?.component === 'TreeSelect' ? 'treeData' : 'options'
|
const key = formConfig.value.currentItem?.component === 'TreeSelect' ? 'treeData' : 'options'
|
||||||
const addOptions = () => {
|
function addOptions() {
|
||||||
if (!formConfig.value.currentItem?.componentProps?.[key])
|
if (!formConfig.value.currentItem?.componentProps?.[key])
|
||||||
formConfig.value.currentItem!.componentProps![key] = []
|
formConfig.value.currentItem!.componentProps![key] = []
|
||||||
const len = formConfig.value.currentItem?.componentProps?.[key].length + 1
|
const len = formConfig.value.currentItem?.componentProps?.[key].length + 1
|
||||||
|
@ -23,33 +16,22 @@ export default defineComponent({
|
||||||
value: `${len}`,
|
value: `${len}`,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const deleteOptions = (index: number) => {
|
function deleteOptions(index: number) {
|
||||||
remove(formConfig.value.currentItem?.componentProps?.[key], index)
|
remove(formConfig.value.currentItem?.componentProps?.[key], index)
|
||||||
}
|
}
|
||||||
|
|
||||||
const addGridOptions = () => {
|
function addGridOptions() {
|
||||||
formConfig.value.currentItem?.columns?.push({
|
formConfig.value.currentItem?.columns?.push({
|
||||||
span: 12,
|
span: 12,
|
||||||
children: [],
|
children: [],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const deleteGridOptions = (index: number) => {
|
function deleteGridOptions(index: number) {
|
||||||
if (index === 0)
|
if (index === 0)
|
||||||
return message.warning('请至少保留一个栅格')
|
return message.warning('请至少保留一个栅格')
|
||||||
|
|
||||||
remove(formConfig.value.currentItem!.columns!, index)
|
remove(formConfig.value.currentItem!.columns!, index)
|
||||||
}
|
}
|
||||||
return {
|
|
||||||
...toRefs(state),
|
|
||||||
formConfig,
|
|
||||||
addOptions,
|
|
||||||
deleteOptions,
|
|
||||||
key,
|
|
||||||
deleteGridOptions,
|
|
||||||
addGridOptions,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -1,28 +1,19 @@
|
||||||
<!--
|
<!--
|
||||||
* @Description: 右侧属性面板控件 表单属性面板
|
* @Description: 右侧属性面板控件 表单属性面板
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue'
|
|
||||||
import type { RadioChangeEvent } from 'ant-design-vue'
|
import type { RadioChangeEvent } from 'ant-design-vue'
|
||||||
import { Checkbox, Col, InputNumber, Slider } from 'ant-design-vue'
|
import {
|
||||||
|
|
||||||
// import RadioButtonGroup from '/@/components/RadioButtonGroup.vue';
|
|
||||||
import { Form, FormItem, Radio } from 'ant-design-vue'
|
|
||||||
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'FormProps',
|
|
||||||
components: {
|
|
||||||
InputNumber,
|
|
||||||
Slider,
|
|
||||||
Checkbox,
|
Checkbox,
|
||||||
RadioGroup: Radio.Group,
|
Col,
|
||||||
RadioButton: Radio.Button,
|
|
||||||
Form,
|
Form,
|
||||||
FormItem,
|
FormItem,
|
||||||
Col,
|
InputNumber,
|
||||||
},
|
Radio,
|
||||||
setup() {
|
Slider,
|
||||||
|
} from 'ant-design-vue'
|
||||||
|
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
||||||
|
|
||||||
const { formConfig } = useFormDesignState()
|
const { formConfig } = useFormDesignState()
|
||||||
|
|
||||||
formConfig.value = formConfig.value || {
|
formConfig.value = formConfig.value || {
|
||||||
|
@ -30,14 +21,10 @@ export default defineComponent({
|
||||||
wrapperCol: { span: 24 },
|
wrapperCol: { span: 24 },
|
||||||
}
|
}
|
||||||
|
|
||||||
const lableLayoutChange = (e: RadioChangeEvent) => {
|
function lableLayoutChange(e: RadioChangeEvent) {
|
||||||
if (e.target.value === 'Grid')
|
if (e.target.value === 'Grid')
|
||||||
formConfig.value.layout = 'horizontal'
|
formConfig.value.layout = 'horizontal'
|
||||||
}
|
}
|
||||||
|
|
||||||
return { formConfig, lableLayoutChange }
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -46,33 +33,42 @@ export default defineComponent({
|
||||||
<!-- <e-upload v-model="fileList"></e-upload> -->
|
<!-- <e-upload v-model="fileList"></e-upload> -->
|
||||||
|
|
||||||
<FormItem label="表单布局">
|
<FormItem label="表单布局">
|
||||||
<RadioGroup v-model:value="formConfig.layout" button-style="solid">
|
<Radio.Group v-model:value="formConfig.layout" button-style="solid">
|
||||||
<RadioButton value="horizontal">
|
<Radio.Button value="horizontal">
|
||||||
水平
|
水平
|
||||||
</RadioButton>
|
</Radio.Button>
|
||||||
<RadioButton value="vertical" :disabled="formConfig.labelLayout === 'Grid'">
|
<Radio.Button value="vertical" :disabled="formConfig.labelLayout === 'Grid'">
|
||||||
垂直
|
垂直
|
||||||
</RadioButton>
|
</Radio.Button>
|
||||||
<RadioButton value="inline" :disabled="formConfig.labelLayout === 'Grid'">
|
<Radio.Button value="inline" :disabled="formConfig.labelLayout === 'Grid'">
|
||||||
行内
|
行内
|
||||||
</RadioButton>
|
</Radio.Button>
|
||||||
</RadioGroup>
|
</Radio.Group>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|
||||||
<!-- <Row> -->
|
<!-- <Row> -->
|
||||||
<FormItem label="标签布局">
|
<FormItem label="标签布局">
|
||||||
<RadioGroup v-model:value="formConfig.labelLayout" button-style="solid" @change="lableLayoutChange">
|
<Radio.Group
|
||||||
<RadioButton value="flex">
|
v-model:value="formConfig.labelLayout"
|
||||||
|
button-style="solid"
|
||||||
|
@change="lableLayoutChange"
|
||||||
|
>
|
||||||
|
<Radio.Button value="flex">
|
||||||
固定
|
固定
|
||||||
</RadioButton>
|
</Radio.Button>
|
||||||
<RadioButton value="Grid" :disabled="formConfig.layout !== 'horizontal'">
|
<Radio.Button value="Grid" :disabled="formConfig.layout !== 'horizontal'">
|
||||||
栅格
|
栅格
|
||||||
</RadioButton>
|
</Radio.Button>
|
||||||
</RadioGroup>
|
</Radio.Group>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<!-- </Row> -->
|
<!-- </Row> -->
|
||||||
<FormItem v-show="formConfig.labelLayout === 'flex'" label="标签宽度(px)">
|
<FormItem v-show="formConfig.labelLayout === 'flex'" label="标签宽度(px)">
|
||||||
<InputNumber v-model:value="formConfig.labelWidth" :style="{ width: '100%' }" :min="0" :step="1" />
|
<InputNumber
|
||||||
|
v-model:value="formConfig.labelWidth"
|
||||||
|
:style="{ width: '100%' }"
|
||||||
|
:min="0"
|
||||||
|
:step="1"
|
||||||
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<div v-if="formConfig.labelLayout === 'Grid'">
|
<div v-if="formConfig.labelLayout === 'Grid'">
|
||||||
<FormItem label="labelCol">
|
<FormItem label="labelCol">
|
||||||
|
@ -83,28 +79,28 @@ export default defineComponent({
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|
||||||
<FormItem label="标签对齐">
|
<FormItem label="标签对齐">
|
||||||
<RadioGroup v-model:value="formConfig.labelAlign" button-style="solid">
|
<Radio.Group v-model:value="formConfig.labelAlign" button-style="solid">
|
||||||
<RadioButton value="left">
|
<Radio.Button value="left">
|
||||||
靠左
|
靠左
|
||||||
</RadioButton>
|
</Radio.Button>
|
||||||
<RadioButton value="right">
|
<Radio.Button value="right">
|
||||||
靠右
|
靠右
|
||||||
</RadioButton>
|
</Radio.Button>
|
||||||
</RadioGroup>
|
</Radio.Group>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|
||||||
<FormItem label="控件大小">
|
<FormItem label="控件大小">
|
||||||
<RadioGroup v-model:value="formConfig.size" button-style="solid">
|
<Radio.Group v-model:value="formConfig.size" button-style="solid">
|
||||||
<RadioButton value="default">
|
<Radio.Button value="default">
|
||||||
默认
|
默认
|
||||||
</RadioButton>
|
</Radio.Button>
|
||||||
<RadioButton value="small">
|
<Radio.Button value="small">
|
||||||
小
|
小
|
||||||
</RadioButton>
|
</Radio.Button>
|
||||||
<RadioButton value="large">
|
<Radio.Button value="large">
|
||||||
大
|
大
|
||||||
</RadioButton>
|
</Radio.Button>
|
||||||
</RadioGroup>
|
</Radio.Group>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</div>
|
</div>
|
||||||
<FormItem label="表单属性">
|
<FormItem label="表单属性">
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<!--
|
<!--
|
||||||
* @Description: 导入JSON模板
|
* @Description: 导入JSON模板
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, reactive, ref, toRefs } from 'vue'
|
import { reactive, ref } from 'vue'
|
||||||
|
|
||||||
// import message from '../../../utils/message';
|
// import message from '../../../utils/message';
|
||||||
import { Modal, Upload } from 'ant-design-vue'
|
import { Modal, Upload } from 'ant-design-vue'
|
||||||
|
@ -14,14 +14,6 @@ import { formItemsForEach, generateKey } from '../../../utils'
|
||||||
import { CodeEditor, MODE } from '@/components/CodeEditor'
|
import { CodeEditor, MODE } from '@/components/CodeEditor'
|
||||||
import { useMessage } from '@/hooks/web/useMessage'
|
import { useMessage } from '@/hooks/web/useMessage'
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'ImportJsonModal',
|
|
||||||
components: {
|
|
||||||
CodeEditor,
|
|
||||||
Upload,
|
|
||||||
Modal,
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
const { createMessage } = useMessage()
|
const { createMessage } = useMessage()
|
||||||
|
|
||||||
const myEditor = ref(null)
|
const myEditor = ref(null)
|
||||||
|
@ -53,13 +45,13 @@ export default defineComponent({
|
||||||
handleSetSelectItem: null,
|
handleSetSelectItem: null,
|
||||||
})
|
})
|
||||||
const { formDesignMethods } = useFormDesignState()
|
const { formDesignMethods } = useFormDesignState()
|
||||||
const handleCancel = () => {
|
function handleCancel() {
|
||||||
state.open = false
|
state.open = false
|
||||||
}
|
}
|
||||||
const showModal = () => {
|
function showModal() {
|
||||||
state.open = true
|
state.open = true
|
||||||
}
|
}
|
||||||
const handleImportJson = () => {
|
function handleImportJson() {
|
||||||
// 导入JSON
|
// 导入JSON
|
||||||
try {
|
try {
|
||||||
const editorJsonData = JSON.parse(state.json) as IFormConfig
|
const editorJsonData = JSON.parse(state.json) as IFormConfig
|
||||||
|
@ -79,7 +71,7 @@ export default defineComponent({
|
||||||
createMessage.error('导入失败,数据格式不对')
|
createMessage.error('导入失败,数据格式不对')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const beforeUpload = (e: File) => {
|
function beforeUpload(e: File) {
|
||||||
// 通过json文件导入
|
// 通过json文件导入
|
||||||
const reader = new FileReader()
|
const reader = new FileReader()
|
||||||
reader.readAsText(e)
|
reader.readAsText(e)
|
||||||
|
@ -90,23 +82,13 @@ export default defineComponent({
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
defineExpose({ showModal })
|
||||||
myEditor,
|
|
||||||
handleImportJson,
|
|
||||||
beforeUpload,
|
|
||||||
handleCancel,
|
|
||||||
showModal,
|
|
||||||
...toRefs(state),
|
|
||||||
MODE,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Modal
|
<Modal
|
||||||
title="JSON数据"
|
title="JSON数据"
|
||||||
:open="open"
|
:open="state.open"
|
||||||
cancel-text="关闭"
|
cancel-text="关闭"
|
||||||
:destroy-on-close="true"
|
:destroy-on-close="true"
|
||||||
wrap-class-name="v-code-modal"
|
wrap-class-name="v-code-modal"
|
||||||
|
@ -126,7 +108,12 @@ export default defineComponent({
|
||||||
<a-button @click="handleCancel">
|
<a-button @click="handleCancel">
|
||||||
取消
|
取消
|
||||||
</a-button>
|
</a-button>
|
||||||
<Upload class="upload-button" :before-upload="beforeUpload" :show-upload-list="false" accept="application/json">
|
<Upload
|
||||||
|
class="upload-button"
|
||||||
|
:before-upload="beforeUpload"
|
||||||
|
:show-upload-list="false"
|
||||||
|
accept="application/json"
|
||||||
|
>
|
||||||
<a-button type="primary">
|
<a-button type="primary">
|
||||||
导入json文件
|
导入json文件
|
||||||
</a-button>
|
</a-button>
|
||||||
|
|
|
@ -1,21 +1,15 @@
|
||||||
<!--
|
<!--
|
||||||
* @Description: 渲染JSON数据
|
* @Description: 渲染JSON数据
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { computed, defineComponent, reactive, toRefs } from 'vue'
|
import { computed, reactive } from 'vue'
|
||||||
import { Modal } from 'ant-design-vue'
|
import { Modal } from 'ant-design-vue'
|
||||||
import type { IFormConfig } from '../../../typings/v-form-component'
|
import type { IFormConfig } from '../../../typings/v-form-component'
|
||||||
import { formatRules, removeAttrs } from '../../../utils'
|
import { formatRules, removeAttrs } from '../../../utils'
|
||||||
import PreviewCode from './PreviewCode.vue'
|
import PreviewCode from './PreviewCode.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
const emit = defineEmits(['cancel'])
|
||||||
name: 'JsonModal',
|
|
||||||
components: {
|
|
||||||
PreviewCode,
|
|
||||||
Modal,
|
|
||||||
},
|
|
||||||
emits: ['cancel'],
|
|
||||||
setup(_props, { emit }) {
|
|
||||||
const state = reactive<{
|
const state = reactive<{
|
||||||
open: boolean
|
open: boolean
|
||||||
jsonData: IFormConfig
|
jsonData: IFormConfig
|
||||||
|
@ -27,7 +21,7 @@ export default defineComponent({
|
||||||
* 显示Json数据弹框
|
* 显示Json数据弹框
|
||||||
* @param jsonData
|
* @param jsonData
|
||||||
*/
|
*/
|
||||||
const showModal = (jsonData: IFormConfig) => {
|
function showModal(jsonData: IFormConfig) {
|
||||||
formatRules(jsonData.schemas)
|
formatRules(jsonData.schemas)
|
||||||
state.jsonData = jsonData
|
state.jsonData = jsonData
|
||||||
state.open = true
|
state.open = true
|
||||||
|
@ -39,21 +33,19 @@ export default defineComponent({
|
||||||
})
|
})
|
||||||
|
|
||||||
// 关闭弹框
|
// 关闭弹框
|
||||||
const handleCancel = () => {
|
function handleCancel() {
|
||||||
state.open = false
|
state.open = false
|
||||||
emit('cancel')
|
emit('cancel')
|
||||||
}
|
}
|
||||||
|
|
||||||
return { ...toRefs(state), editorJson, handleCancel, showModal }
|
defineExpose({ showModal })
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Modal
|
<Modal
|
||||||
title="JSON数据"
|
title="JSON数据"
|
||||||
:footer="null"
|
:footer="null"
|
||||||
:open="open"
|
:open="state.open"
|
||||||
:destroy-on-close="true"
|
:destroy-on-close="true"
|
||||||
wrap-class-name="v-code-modal"
|
wrap-class-name="v-code-modal"
|
||||||
style="top: 20px"
|
style="top: 20px"
|
||||||
|
|
|
@ -73,7 +73,13 @@ export default defineComponent({
|
||||||
<CodeEditor ref="myEditor" :value="editorJson" :mode="MODE.JSON" />
|
<CodeEditor ref="myEditor" :value="editorJson" :mode="MODE.JSON" />
|
||||||
</div>
|
</div>
|
||||||
<div class="copy-btn-box">
|
<div class="copy-btn-box">
|
||||||
<a-button type="primary" class="copy-btn" data-clipboard-action="copy" :data-clipboard-text="editorJson" @click="handleCopyJson">
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
class="copy-btn"
|
||||||
|
data-clipboard-action="copy"
|
||||||
|
:data-clipboard-text="editorJson"
|
||||||
|
@click="handleCopyJson"
|
||||||
|
>
|
||||||
复制数据
|
复制数据
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button type="primary" @click="handleExportJson">
|
<a-button type="primary" @click="handleExportJson">
|
||||||
|
|
|
@ -183,7 +183,9 @@ export const baseFormItemProps: IBaseFormAttrs[] = [
|
||||||
label: '控件-FormItem',
|
label: '控件-FormItem',
|
||||||
component: 'Select',
|
component: 'Select',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
options: baseComponents.concat(customComponents).map(item => ({ value: item.component, label: item.label })),
|
options: baseComponents
|
||||||
|
.concat(customComponents)
|
||||||
|
.map(item => ({ value: item.component, label: item.label })),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { type Ref, provide, ref } from 'vue'
|
import type { Ref } from 'vue'
|
||||||
|
import { provide, ref } from 'vue'
|
||||||
import { Layout, LayoutContent, LayoutSider } from 'ant-design-vue'
|
import { Layout, LayoutContent, LayoutSider } from 'ant-design-vue'
|
||||||
|
|
||||||
import { cloneDeep } from 'lodash-es'
|
import { cloneDeep } from 'lodash-es'
|
||||||
import { type UseRefHistoryReturn, useRefHistory } from '@vueuse/core'
|
import type { UseRefHistoryReturn } from '@vueuse/core'
|
||||||
|
import { useRefHistory } from '@vueuse/core'
|
||||||
import VFormPreview from '../VFormPreview/index.vue'
|
import VFormPreview from '../VFormPreview/index.vue'
|
||||||
import VFormPreview2 from '../VFormPreview/useForm.vue'
|
import VFormPreview2 from '../VFormPreview/useForm.vue'
|
||||||
import type { IFormConfig, IVFormComponent, PropsTabKey } from '../../typings/v-form-component'
|
import type { IFormConfig, IVFormComponent, PropsTabKey } from '../../typings/v-form-component'
|
||||||
|
@ -13,18 +14,14 @@ import type { IFormDesignMethods, IPropsPanel, IToolbarMethods } from '../../typ
|
||||||
import CollapseItem from './modules/CollapseItem.vue'
|
import CollapseItem from './modules/CollapseItem.vue'
|
||||||
import FormComponentPanel from './modules/FormComponentPanel.vue'
|
import FormComponentPanel from './modules/FormComponentPanel.vue'
|
||||||
import JsonModal from './components/JsonModal.vue'
|
import JsonModal from './components/JsonModal.vue'
|
||||||
|
|
||||||
import Toolbar from './modules/Toolbar.vue'
|
import Toolbar from './modules/Toolbar.vue'
|
||||||
import PropsPanel from './modules/PropsPanel.vue'
|
import PropsPanel from './modules/PropsPanel.vue'
|
||||||
import ImportJsonModal from './components/ImportJsonModal.vue'
|
import ImportJsonModal from './components/ImportJsonModal.vue'
|
||||||
import CodeModal from './components/CodeModal.vue'
|
import CodeModal from './components/CodeModal.vue'
|
||||||
|
|
||||||
import 'codemirror/mode/javascript/javascript'
|
|
||||||
|
|
||||||
import { globalConfigState } from './config/formItemPropsConfig'
|
import { globalConfigState } from './config/formItemPropsConfig'
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
|
|
||||||
import { CollapseContainer } from '@/components/Container/index'
|
import { CollapseContainer } from '@/components/Container/index'
|
||||||
|
import 'codemirror/mode/javascript/javascript'
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
title: {
|
title: {
|
||||||
|
@ -94,7 +91,9 @@ const historyReturn = useRefHistory(formConfig, {
|
||||||
*/
|
*/
|
||||||
function handleSetSelectItem(schema: IVFormComponent) {
|
function handleSetSelectItem(schema: IVFormComponent) {
|
||||||
formConfig.value.currentItem = schema
|
formConfig.value.currentItem = schema
|
||||||
handleChangePropsTabs(schema.key ? (formConfig.value.activeKey! === 1 ? 2 : formConfig.value.activeKey!) : 1)
|
handleChangePropsTabs(
|
||||||
|
schema.key ? (formConfig.value.activeKey! === 1 ? 2 : formConfig.value.activeKey!) : 1,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function setGlobalConfigState(formItem: IVFormComponent) {
|
function setGlobalConfigState(formItem: IVFormComponent) {
|
||||||
|
@ -154,7 +153,8 @@ function copyFormItem(formItem: IVFormComponent) {
|
||||||
* @param item {IVFormComponent} 当前点击的组件
|
* @param item {IVFormComponent} 当前点击的组件
|
||||||
* @param isCopy {boolean} 是否复制
|
* @param isCopy {boolean} 是否复制
|
||||||
*/
|
*/
|
||||||
function handleCopy(item: IVFormComponent = formConfig.value.currentItem as IVFormComponent, isCopy = true) {
|
function handleCopy(item: IVFormComponent = formConfig.value.currentItem as IVFormComponent,
|
||||||
|
isCopy = true) {
|
||||||
const key = formConfig.value.currentItem?.key
|
const key = formConfig.value.currentItem?.key
|
||||||
/**
|
/**
|
||||||
* 遍历当表单项配置,如果是复制,则复制一份表单项,如果不是复制,则直接添加到表单项中
|
* 遍历当表单项配置,如果是复制,则复制一份表单项,如果不是复制,则直接添加到表单项中
|
||||||
|
@ -165,7 +165,9 @@ function handleCopy(item: IVFormComponent = formConfig.value.currentItem as IVFo
|
||||||
schemas.some((formItem: IVFormComponent, index: number) => {
|
schemas.some((formItem: IVFormComponent, index: number) => {
|
||||||
if (formItem.key === key) {
|
if (formItem.key === key) {
|
||||||
// 判断是不是复制
|
// 判断是不是复制
|
||||||
isCopy ? schemas.splice(index, 0, copyFormItem(formItem)) : schemas.splice(index + 1, 0, item)
|
isCopy
|
||||||
|
? schemas.splice(index, 0, copyFormItem(formItem))
|
||||||
|
: schemas.splice(index + 1, 0, item)
|
||||||
const event = {
|
const event = {
|
||||||
newIndex: index + 1,
|
newIndex: index + 1,
|
||||||
}
|
}
|
||||||
|
@ -254,7 +256,7 @@ provide<IFormDesignMethods>('formDesignMethods', {
|
||||||
collapsed-width="0"
|
collapsed-width="0"
|
||||||
width="270"
|
width="270"
|
||||||
:zero-width-trigger-style="{
|
:zero-width-trigger-style="{
|
||||||
'margin-top': '-70px',
|
'margin-top': '-60px',
|
||||||
'background-color': 'gray',
|
'background-color': 'gray',
|
||||||
}"
|
}"
|
||||||
breakpoint="md"
|
breakpoint="md"
|
||||||
|
@ -293,7 +295,11 @@ provide<IFormDesignMethods>('formDesignMethods', {
|
||||||
@handle-open-code-modal="handleOpenModal(codeModal!)"
|
@handle-open-code-modal="handleOpenModal(codeModal!)"
|
||||||
@handle-clear-form-items="handleClearFormItems"
|
@handle-clear-form-items="handleClearFormItems"
|
||||||
/>
|
/>
|
||||||
<FormComponentPanel :current-item="formConfig.currentItem" :data="formConfig" @handle-set-select-item="handleSetSelectItem" />
|
<FormComponentPanel
|
||||||
|
:current-item="formConfig.currentItem"
|
||||||
|
:data="formConfig"
|
||||||
|
@handle-set-select-item="handleSetSelectItem"
|
||||||
|
/>
|
||||||
</LayoutContent>
|
</LayoutContent>
|
||||||
<LayoutSider
|
<LayoutSider
|
||||||
:class="`right ${prefixCls}-sider`"
|
:class="`right ${prefixCls}-sider`"
|
||||||
|
@ -301,12 +307,15 @@ provide<IFormDesignMethods>('formDesignMethods', {
|
||||||
:reverse-arrow="true"
|
:reverse-arrow="true"
|
||||||
collapsed-width="0"
|
collapsed-width="0"
|
||||||
width="270"
|
width="270"
|
||||||
:zero-width-trigger-style="{ 'margin-top': '-70px', 'background-color': 'gray' }"
|
:zero-width-trigger-style="{ 'margin-top': '-60px', 'background-color': 'gray' }"
|
||||||
breakpoint="lg"
|
breakpoint="lg"
|
||||||
>
|
>
|
||||||
<PropsPanel ref="propsPanel" :active-key="formConfig.activeKey">
|
<PropsPanel ref="propsPanel" :active-key="formConfig.activeKey">
|
||||||
<template v-for="item of formConfig.schemas" #[`${item.component}Props`]="data">
|
<template v-for="item of formConfig.schemas" #[`${item.component}Props`]="data">
|
||||||
<slot :name="`${item.component}Props`" v-bind="{ formItem: data, props: data.componentProps }" />
|
<slot
|
||||||
|
:name="`${item.component}Props`"
|
||||||
|
v-bind="{ formItem: data, props: data.componentProps }"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</PropsPanel>
|
</PropsPanel>
|
||||||
</LayoutSider>
|
</LayoutSider>
|
||||||
|
|
|
@ -2,24 +2,25 @@
|
||||||
import { defineComponent, reactive } from 'vue'
|
import { defineComponent, reactive } from 'vue'
|
||||||
import draggable from 'vuedraggable'
|
import draggable from 'vuedraggable'
|
||||||
import type { IVFormComponent } from '../../../typings/v-form-component'
|
import type { IVFormComponent } from '../../../typings/v-form-component'
|
||||||
|
|
||||||
// import { toRefs } from '@vueuse/core';
|
|
||||||
import { Icon } from '@/components/Icon'
|
import { Icon } from '@/components/Icon'
|
||||||
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'CollapseItem',
|
name: 'CollapseItem',
|
||||||
components: { Draggable: draggable, Icon },
|
components: { Draggable: draggable, Icon },
|
||||||
props: {
|
props: {
|
||||||
list: {
|
list: {
|
||||||
type: [Array] as PropType<IVFormComponent[]>,
|
type: [Array],
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
handleListPush: {
|
handleListPush: {
|
||||||
type: Function as PropType<(item: IVFormComponent) => void>,
|
type: Function,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
|
const { prefixCls } = useDesign('form-design-collapse-item')
|
||||||
|
|
||||||
const state = reactive({})
|
const state = reactive({})
|
||||||
const handleStart = (e: any, list1: IVFormComponent[]) => {
|
const handleStart = (e: any, list1: IVFormComponent[]) => {
|
||||||
emit('start', list1[e.oldIndex].component)
|
emit('start', list1[e.oldIndex].component)
|
||||||
|
@ -32,13 +33,13 @@ export default defineComponent({
|
||||||
const cloneItem = (one) => {
|
const cloneItem = (one) => {
|
||||||
return props.handleListPush(one)
|
return props.handleListPush(one)
|
||||||
}
|
}
|
||||||
return { state, handleStart, handleAdd, cloneItem }
|
return { prefixCls, state, handleStart, handleAdd, cloneItem }
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div :class="prefixCls">
|
||||||
<Draggable
|
<Draggable
|
||||||
tag="ul"
|
tag="ul"
|
||||||
:model-value="list"
|
:model-value="list"
|
||||||
|
@ -54,7 +55,11 @@ export default defineComponent({
|
||||||
@add="handleAdd"
|
@add="handleAdd"
|
||||||
>
|
>
|
||||||
<template #item="{ element, index }">
|
<template #item="{ element, index }">
|
||||||
<li class="bs-box text-ellipsis" @dragstart="$emit('add-attrs', list, index)" @click="$emit('handle-list-push', element)">
|
<li
|
||||||
|
class="bs-box text-ellipsis"
|
||||||
|
@dragstart="$emit('add-attrs', list, index)"
|
||||||
|
@click="$emit('handle-list-push', element)"
|
||||||
|
>
|
||||||
<!-- <svg v-if="element.icon.indexOf('icon-') > -1" class="icon" aria-hidden="true">
|
<!-- <svg v-if="element.icon.indexOf('icon-') > -1" class="icon" aria-hidden="true">
|
||||||
<use :xlink:href="`#${element.icon}`" />
|
<use :xlink:href="`#${element.icon}`" />
|
||||||
</svg> -->
|
</svg> -->
|
||||||
|
@ -67,8 +72,11 @@ export default defineComponent({
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
@prefix-cls: ~'@{namespace}-form-design-collapse-item';
|
||||||
|
|
||||||
@import url('../styles/variable.less');
|
@import url('../styles/variable.less');
|
||||||
|
|
||||||
|
.@{prefix-cls} {
|
||||||
ul {
|
ul {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
@ -84,12 +92,16 @@ ul {
|
||||||
margin: 2.7px;
|
margin: 2.7px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
cursor: move;
|
cursor: move;
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid @border-color;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
color: @primary-color;
|
||||||
|
border: 1px solid @primary-color;
|
||||||
|
// z-index: 1;
|
||||||
|
box-shadow: 0 2px 6px @primary-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,4 +109,5 @@ ul {
|
||||||
svg {
|
svg {
|
||||||
display: inline !important;
|
display: inline !important;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -7,8 +7,8 @@ import draggable from 'vuedraggable'
|
||||||
import { computed, defineComponent } from 'vue'
|
import { computed, defineComponent } from 'vue'
|
||||||
import { cloneDeep } from 'lodash-es'
|
import { cloneDeep } from 'lodash-es'
|
||||||
import { Empty, Form } from 'ant-design-vue'
|
import { Empty, Form } from 'ant-design-vue'
|
||||||
import LayoutItem from '../components/LayoutItem.vue'
|
|
||||||
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
||||||
|
import LayoutItem from '../components/LayoutItem.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'FormComponentPanel',
|
name: 'FormComponentPanel',
|
||||||
|
@ -20,7 +20,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
emits: ['handleSetSelectItem'],
|
emits: ['handleSetSelectItem'],
|
||||||
setup(_, { emit }) {
|
setup(_, { emit }) {
|
||||||
const { formConfig } = useFormDesignState() as Recordable
|
const { formConfig } = useFormDesignState()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 拖拽完成事件
|
* 拖拽完成事件
|
||||||
|
@ -61,7 +61,11 @@ export default defineComponent({
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="form-panel v-form-container">
|
<div class="form-panel v-form-container">
|
||||||
<Empty v-show="formConfig.schemas.length === 0" class="empty-text" description="从左侧选择控件添加" />
|
<Empty
|
||||||
|
v-show="formConfig.schemas.length === 0"
|
||||||
|
class="empty-text"
|
||||||
|
description="从左侧选择控件添加"
|
||||||
|
/>
|
||||||
<Form v-bind="formConfig">
|
<Form v-bind="formConfig">
|
||||||
<div class="draggable-box">
|
<div class="draggable-box">
|
||||||
<Draggable
|
<Draggable
|
||||||
|
@ -77,7 +81,12 @@ export default defineComponent({
|
||||||
@start="handleDragStart"
|
@start="handleDragStart"
|
||||||
>
|
>
|
||||||
<template #item="{ element }">
|
<template #item="{ element }">
|
||||||
<LayoutItem class="drag-move" :schema="element" :data="formConfig" :current-item="formConfig.currentItem || {}" />
|
<LayoutItem
|
||||||
|
class="drag-move"
|
||||||
|
:schema="element"
|
||||||
|
:data="formConfig"
|
||||||
|
:current-item="formConfig.currentItem || {}"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</Draggable>
|
</Draggable>
|
||||||
</div>
|
</div>
|
||||||
|
@ -124,6 +133,7 @@ export default defineComponent({
|
||||||
|
|
||||||
.draggable-box {
|
.draggable-box {
|
||||||
height: calc(100vh - 200px);
|
height: calc(100vh - 200px);
|
||||||
|
// width: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
||||||
.drag-move {
|
.drag-move {
|
||||||
|
@ -132,8 +142,6 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-main {
|
.list-main {
|
||||||
// height: 100%;
|
|
||||||
// overflow: auto;
|
|
||||||
// 列表动画
|
// 列表动画
|
||||||
.list-enter-active {
|
.list-enter-active {
|
||||||
transition: all 0.5s;
|
transition: all 0.5s;
|
||||||
|
|
|
@ -28,7 +28,9 @@ export default defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
const { formConfig } = useFormDesignState()
|
const { formConfig } = useFormDesignState()
|
||||||
const slotProps = computed(() => {
|
const slotProps = computed(() => {
|
||||||
return customComponents.find(item => item.component === formConfig.value.currentItem?.component)
|
return customComponents.find(
|
||||||
|
item => item.component === formConfig.value.currentItem?.component,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
return { formConfig, customComponents, slotProps }
|
return { formConfig, customComponents, slotProps }
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { defineComponent, inject, reactive, toRefs } from 'vue'
|
||||||
import type { UseRefHistoryReturn } from '@vueuse/core'
|
import type { UseRefHistoryReturn } from '@vueuse/core'
|
||||||
import { Divider, Tooltip } from 'ant-design-vue'
|
import { Divider, Tooltip } from 'ant-design-vue'
|
||||||
import type { IFormConfig } from '../../../typings/v-form-component'
|
import type { IFormConfig } from '../../../typings/v-form-component'
|
||||||
import Icon from '@/components/Icon/index'
|
import { Icon } from '@/components/Icon'
|
||||||
|
|
||||||
interface IToolbarsConfig {
|
interface IToolbarsConfig {
|
||||||
type: string
|
type: string
|
||||||
|
@ -109,11 +109,11 @@ export default defineComponent({
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
height: @operating-area-height;
|
height: @operating-area-height;
|
||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
padding-left: 30px;
|
padding-left: 40px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: @operating-area-height;
|
line-height: @operating-area-height;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
border-bottom: 2px solid var(--border-color);
|
border-bottom: 2px solid @border-color;
|
||||||
|
|
||||||
a {
|
a {
|
||||||
margin: 0 5px;
|
margin: 0 5px;
|
||||||
|
@ -124,6 +124,10 @@ export default defineComponent({
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: @primary-color;
|
||||||
|
}
|
||||||
|
|
||||||
> span {
|
> span {
|
||||||
padding-left: 2px;
|
padding-left: 2px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
||||||
/* stylelint-disable-next-line selector-pseudo-class-no-unknown */
|
|
||||||
:deep(.list-main) {
|
:deep(.list-main) {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
@ -17,12 +16,13 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 5px;
|
height: 5px;
|
||||||
content: "";
|
background-color: @primary-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,19 +34,25 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: @primary-hover-bg-color;
|
||||||
|
}
|
||||||
|
|
||||||
// 选择时 start
|
// 选择时 start
|
||||||
&::before {
|
&::before {
|
||||||
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: -100%;
|
right: -100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 5px;
|
height: 5px;
|
||||||
content: "";
|
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
|
background-color: @primary-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
outline-offset: 0;
|
outline-offset: 0;
|
||||||
|
background-color: @primary-hover-bg-color;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
right: 0;
|
right: 0;
|
||||||
|
@ -60,18 +66,18 @@
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
content: "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-form-item {
|
.ant-form-item {
|
||||||
padding-bottom: 6px;
|
|
||||||
// 修改ant form-item的margin为padding
|
// 修改ant form-item的margin为padding
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
padding-bottom: 6px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,8 +86,9 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 5px;
|
right: 5px;
|
||||||
bottom: 2px;
|
bottom: 2px;
|
||||||
font-size: 14px;
|
|
||||||
// z-index: 999;
|
// z-index: 999;
|
||||||
|
color: @primary-color;
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.copy,
|
.copy,
|
||||||
|
@ -90,15 +97,15 @@
|
||||||
top: 0;
|
top: 0;
|
||||||
width: 30px;
|
width: 30px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
line-height: 30px;
|
|
||||||
color: #fff;
|
|
||||||
text-align: center;
|
|
||||||
// z-index: 989;
|
// z-index: 989;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
|
color: #fff;
|
||||||
|
line-height: 30px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
&.unactivated {
|
&.unactivated {
|
||||||
pointer-events: none;
|
|
||||||
opacity: 0 !important;
|
opacity: 0 !important;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
|
@ -109,10 +116,12 @@
|
||||||
.copy {
|
.copy {
|
||||||
right: 30px;
|
right: 30px;
|
||||||
border-radius: 0 0 0 8px;
|
border-radius: 0 0 0 8px;
|
||||||
|
background-color: @primary-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.delete {
|
.delete {
|
||||||
right: 0;
|
right: 0;
|
||||||
|
background-color: @primary-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,17 +131,17 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background-color: @layout-background-color;
|
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
|
background-color: @layout-background-color;
|
||||||
|
|
||||||
.form-item-box {
|
.form-item-box {
|
||||||
position: relative;
|
position: relative;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
.ant-form-item {
|
.ant-form-item {
|
||||||
padding-bottom: 15px;
|
|
||||||
// 修改ant form-item的margin为padding
|
// 修改ant form-item的margin为padding
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
padding-bottom: 15px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,19 +166,19 @@
|
||||||
|
|
||||||
// 选择时 start
|
// 选择时 start
|
||||||
&::before {
|
&::before {
|
||||||
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: -100%;
|
right: -100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 5px;
|
height: 5px;
|
||||||
content: "";
|
|
||||||
background: transparent;
|
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
background-color: @layout-hover-bg-color;
|
|
||||||
outline-offset: 0;
|
outline-offset: 0;
|
||||||
|
background-color: @layout-hover-bg-color;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
right: 0;
|
right: 0;
|
||||||
|
@ -184,15 +193,15 @@
|
||||||
top: 0;
|
top: 0;
|
||||||
width: 30px;
|
width: 30px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
line-height: 30px;
|
|
||||||
color: #fff;
|
|
||||||
text-align: center;
|
|
||||||
// z-index: 989;
|
// z-index: 989;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
|
color: #fff;
|
||||||
|
line-height: 30px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
&.unactivated {
|
&.unactivated {
|
||||||
pointer-events: none;
|
|
||||||
opacity: 0 !important;
|
opacity: 0 !important;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
|
@ -202,8 +211,8 @@
|
||||||
|
|
||||||
> .copy {
|
> .copy {
|
||||||
right: 30px;
|
right: 30px;
|
||||||
background-color: @layout-color;
|
|
||||||
border-radius: 0 0 0 8px;
|
border-radius: 0 0 0 8px;
|
||||||
|
background-color: @layout-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .delete {
|
> .delete {
|
||||||
|
|
|
@ -1,32 +1,19 @@
|
||||||
<!--
|
<!--
|
||||||
* @Description:
|
* @Description:
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import type { PropType } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
import { computed, defineComponent, reactive, toRefs, unref } from 'vue'
|
import { computed, unref } from 'vue'
|
||||||
import { asyncComputed } from '@vueuse/core'
|
import { asyncComputed } from '@vueuse/core'
|
||||||
import { omit } from 'lodash-es'
|
import { omit } from 'lodash-es'
|
||||||
import { Col, Divider, FormItem, Tooltip } from 'ant-design-vue'
|
import { Col, Divider, FormItem, Tooltip } from 'ant-design-vue'
|
||||||
import { componentMap } from '../../core/formItemConfig'
|
import { componentMap } from '../../core/formItemConfig'
|
||||||
import type { IFormConfig, IVFormComponent } from '../../typings/v-form-component'
|
import type { IFormConfig, IVFormComponent } from '../../typings/v-form-component'
|
||||||
import { handleAsyncOptions } from '../../utils'
|
import { handleAsyncOptions } from '../../utils'
|
||||||
|
|
||||||
// import FormItem from '/@/components/Form/src/components/FormItem.vue';
|
|
||||||
|
|
||||||
import { useFormModelState } from '../../hooks/useFormDesignState'
|
import { useFormModelState } from '../../hooks/useFormDesignState'
|
||||||
import { Icon } from '@/components/Icon'
|
import { Icon } from '@/components/Icon'
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps({
|
||||||
name: 'VFormItem',
|
|
||||||
components: {
|
|
||||||
Tooltip,
|
|
||||||
Icon,
|
|
||||||
FormItem,
|
|
||||||
Divider,
|
|
||||||
Col,
|
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
|
||||||
formData: {
|
formData: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
|
@ -39,13 +26,10 @@ export default defineComponent({
|
||||||
type: Object as PropType<IFormConfig>,
|
type: Object as PropType<IFormConfig>,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
|
||||||
emits: ['update:form-data', 'change'],
|
|
||||||
setup(props, { emit }) {
|
|
||||||
const state = reactive({
|
|
||||||
componentMap,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:form-data', 'change'])
|
||||||
|
|
||||||
const { formModel: formData1, setFormModel } = useFormModelState()
|
const { formModel: formData1, setFormModel } = useFormModelState()
|
||||||
const colPropsComputed = computed(() => {
|
const colPropsComputed = computed(() => {
|
||||||
const { colProps = {} } = props.schema
|
const { colProps = {} } = props.schema
|
||||||
|
@ -71,7 +55,10 @@ export default defineComponent({
|
||||||
: formConfig.wrapperCol
|
: formConfig.wrapperCol
|
||||||
: {})
|
: {})
|
||||||
|
|
||||||
const style = formConfig.layout === 'horizontal' && formConfig.labelLayout === 'flex' ? { display: 'flex' } : {}
|
const style
|
||||||
|
= formConfig.layout === 'horizontal' && formConfig.labelLayout === 'flex'
|
||||||
|
? { display: 'flex' }
|
||||||
|
: {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将字符串正则格式化成正则表达式
|
* 将字符串正则格式化成正则表达式
|
||||||
|
@ -100,12 +87,12 @@ export default defineComponent({
|
||||||
newConfig.rules = rules
|
newConfig.rules = rules
|
||||||
|
|
||||||
return newConfig
|
return newConfig
|
||||||
}) as Recordable
|
}) as Recordable<any>
|
||||||
|
|
||||||
const componentItem = computed(() => componentMap.get(props.schema.component as string))
|
const componentItem = computed(() => componentMap.get(props.schema.component as string))
|
||||||
|
|
||||||
// console.log('component change:', props.schema.component, componentItem.value);
|
// console.log('component change:', props.schema.component, componentItem.value);
|
||||||
const handleClick = (schema: IVFormComponent) => {
|
function handleClick(schema: IVFormComponent) {
|
||||||
if (schema.component === 'Button' && schema.componentProps?.handle)
|
if (schema.component === 'Button' && schema.componentProps?.handle)
|
||||||
emit(schema.componentProps?.handle)
|
emit(schema.componentProps?.handle)
|
||||||
}
|
}
|
||||||
|
@ -128,10 +115,12 @@ export default defineComponent({
|
||||||
* 处理同步属性
|
* 处理同步属性
|
||||||
*/
|
*/
|
||||||
const cmpProps = computed(() => {
|
const cmpProps = computed(() => {
|
||||||
const isCheck = props.schema && ['Switch', 'Checkbox', 'Radio'].includes(props.schema.component)
|
const isCheck
|
||||||
|
= props.schema && ['Switch', 'Checkbox', 'Radio'].includes(props.schema.component)
|
||||||
const { field } = props.schema
|
const { field } = props.schema
|
||||||
|
|
||||||
let { disabled, ...attrs } = omit(props.schema.componentProps, ['options', 'treeData']) ?? {}
|
let { disabled, ...attrs }
|
||||||
|
= omit(props.schema.componentProps, ['options', 'treeData']) ?? {}
|
||||||
|
|
||||||
disabled = props.formConfig.disabled || disabled
|
disabled = props.formConfig.disabled || disabled
|
||||||
|
|
||||||
|
@ -149,18 +138,6 @@ export default defineComponent({
|
||||||
setFormModel(props.schema.field!, value)
|
setFormModel(props.schema.field!, value)
|
||||||
emit('change', value)
|
emit('change', value)
|
||||||
}
|
}
|
||||||
return {
|
|
||||||
...toRefs(state),
|
|
||||||
componentItem,
|
|
||||||
formItemProps,
|
|
||||||
handleClick,
|
|
||||||
asyncProps,
|
|
||||||
cmpProps,
|
|
||||||
handleChange,
|
|
||||||
colPropsComputed,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -176,8 +153,14 @@ export default defineComponent({
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<slot v-if="schema.componentProps && schema.componentProps?.slotName" :name="schema.componentProps.slotName" v-bind="schema" />
|
<slot
|
||||||
<Divider v-else-if="schema.component === 'Divider' && schema.label && !formItemProps.hiddenLabel">
|
v-if="schema.componentProps && schema.componentProps?.slotName"
|
||||||
|
:name="schema.componentProps.slotName"
|
||||||
|
v-bind="schema"
|
||||||
|
/>
|
||||||
|
<Divider
|
||||||
|
v-else-if="schema.component === 'Divider' && schema.label && !formItemProps.hiddenLabel"
|
||||||
|
>
|
||||||
{{ schema.label }}
|
{{ schema.label }}
|
||||||
</Divider>
|
</Divider>
|
||||||
<!-- 部分控件需要一个空div -->
|
<!-- 部分控件需要一个空div -->
|
||||||
|
|
|
@ -11,19 +11,14 @@
|
||||||
>
|
>
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { computed, defineComponent, unref } from 'vue'
|
import { computed, unref } from 'vue'
|
||||||
import type { IFormConfig, IVFormComponent } from '../../typings/v-form-component'
|
import type { IFormConfig, IVFormComponent } from '../../typings/v-form-component'
|
||||||
import type { FormProps, FormSchema } from '@/components/Form'
|
import type { FormProps, FormSchema } from '@/components/Form'
|
||||||
|
|
||||||
import FormItem from '/@/components/Form/src/components/FormItem.vue'
|
import FormItem from '@/components/Form/src/components/FormItem.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps({
|
||||||
name: 'VFormItem',
|
|
||||||
components: {
|
|
||||||
FormItem,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
formData: {
|
formData: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
|
@ -36,8 +31,8 @@ export default defineComponent({
|
||||||
type: Object as PropType<IFormConfig>,
|
type: Object as PropType<IFormConfig>,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
})
|
||||||
setup(props) {
|
|
||||||
const schema = computed(() => {
|
const schema = computed(() => {
|
||||||
const schema: FormSchema = {
|
const schema: FormSchema = {
|
||||||
...unref(props.schema),
|
...unref(props.schema),
|
||||||
|
@ -50,20 +45,12 @@ export default defineComponent({
|
||||||
const getProps = computed((): FormProps => {
|
const getProps = computed((): FormProps => {
|
||||||
return { ...unref(props.formConfig) } as FormProps
|
return { ...unref(props.formConfig) } as FormProps
|
||||||
})
|
})
|
||||||
return {
|
|
||||||
schemaNew: schema,
|
|
||||||
getProps,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FormItem :schema="schemaNew" :form-props="getProps">
|
<FormItem :schema="schema" :form-props="getProps">
|
||||||
<template v-for="item in Object.keys($slots)" #[item]="data">
|
<template v-for="item in Object.keys($slots)" #[item]="data">
|
||||||
<slot :name="item" v-bind="data || {}" />
|
<slot :name="item" v-bind="data || {}" />
|
||||||
</template>
|
</template>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<!--
|
<!--
|
||||||
* @Description: 渲染组件,无法使用Vben的组件
|
* @Description: 渲染组件,无法使用Vben的组件
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, reactive, ref, toRefs } from 'vue'
|
import { reactive, ref } from 'vue'
|
||||||
import { Modal } from 'ant-design-vue'
|
import { Modal } from 'ant-design-vue'
|
||||||
import type { IFormConfig } from '../../typings/v-form-component'
|
import type { IFormConfig } from '../../typings/v-form-component'
|
||||||
import type { IAnyObject } from '../../typings/base-type'
|
import type { IAnyObject } from '../../typings/base-type'
|
||||||
|
@ -12,14 +12,6 @@ import type { IVFormMethods } from '../../hooks/useVFormMethods'
|
||||||
import JsonModal from '../VFormDesign/components/JsonModal.vue'
|
import JsonModal from '../VFormDesign/components/JsonModal.vue'
|
||||||
import type { IToolbarMethods } from '../../typings/form-type'
|
import type { IToolbarMethods } from '../../typings/form-type'
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'VFormPreview',
|
|
||||||
components: {
|
|
||||||
JsonModal,
|
|
||||||
VFormCreate,
|
|
||||||
Modal,
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
const jsonModal = ref<IToolbarMethods | null>(null)
|
const jsonModal = ref<IToolbarMethods | null>(null)
|
||||||
const state = reactive<{
|
const state = reactive<{
|
||||||
formModel: IAnyObject
|
formModel: IAnyObject
|
||||||
|
@ -37,7 +29,7 @@ export default defineComponent({
|
||||||
* 显示Json数据弹框
|
* 显示Json数据弹框
|
||||||
* @param jsonData
|
* @param jsonData
|
||||||
*/
|
*/
|
||||||
const showModal = (jsonData: IFormConfig) => {
|
function showModal(jsonData: IFormConfig) {
|
||||||
// console.log('showModal-', jsonData);
|
// console.log('showModal-', jsonData);
|
||||||
formatRules(jsonData.schemas)
|
formatRules(jsonData.schemas)
|
||||||
state.formConfig = jsonData
|
state.formConfig = jsonData
|
||||||
|
@ -48,38 +40,29 @@ export default defineComponent({
|
||||||
* 获取表单数据
|
* 获取表单数据
|
||||||
* @return {Promise<void>}
|
* @return {Promise<void>}
|
||||||
*/
|
*/
|
||||||
const handleCancel = () => {
|
function handleCancel() {
|
||||||
state.open = false
|
state.open = false
|
||||||
state.formModel = {}
|
onCancel()
|
||||||
}
|
}
|
||||||
const handleGetData = async () => {
|
async function handleGetData() {
|
||||||
const _data = await state.fApi.submit?.()
|
const _data = await state.fApi.submit?.()
|
||||||
jsonModal.value?.showModal?.(_data)
|
jsonModal.value?.showModal?.(_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSubmit = (_data: IAnyObject) => {
|
function onSubmit(_data: IAnyObject) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
const onCancel = () => {
|
function onCancel() {
|
||||||
state.formModel = {}
|
state.formModel = {}
|
||||||
}
|
}
|
||||||
return {
|
|
||||||
handleGetData,
|
defineExpose({ showModal, onCancel })
|
||||||
handleCancel,
|
|
||||||
...toRefs(state),
|
|
||||||
showModal,
|
|
||||||
jsonModal,
|
|
||||||
onSubmit,
|
|
||||||
onCancel,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Modal
|
<Modal
|
||||||
title="预览(支持布局)"
|
title="预览(支持布局)"
|
||||||
:open="open"
|
:open="state.open"
|
||||||
ok-text="获取数据"
|
ok-text="获取数据"
|
||||||
cancel-text="关闭"
|
cancel-text="关闭"
|
||||||
style="top: 20px"
|
style="top: 20px"
|
||||||
|
@ -88,7 +71,12 @@ export default defineComponent({
|
||||||
@ok="handleGetData"
|
@ok="handleGetData"
|
||||||
@cancel="handleCancel"
|
@cancel="handleCancel"
|
||||||
>
|
>
|
||||||
<VFormCreate v-model:fApi="fApi" v-model:formModel="formModel" :form-config="formConfig" @submit="onSubmit">
|
<VFormCreate
|
||||||
|
v-model:fApi="state.fApi"
|
||||||
|
v-model:formModel="state.formModel"
|
||||||
|
:form-config="state.formConfig"
|
||||||
|
@submit="onSubmit"
|
||||||
|
>
|
||||||
<template #slotName="{ formModel, field }">
|
<template #slotName="{ formModel, field }">
|
||||||
<a-input v-model:value="formModel[field]" placeholder="我是插槽传递的输入框" />
|
<a-input v-model:value="formModel[field]" placeholder="我是插槽传递的输入框" />
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
import { getCurrentInstance, toRaw } from 'vue'
|
|
||||||
import type { Ref, SetupContext } from 'vue'
|
import type { Ref, SetupContext } from 'vue'
|
||||||
|
import { getCurrentInstance, toRaw } from 'vue'
|
||||||
import { cloneDeep, forOwn, isFunction } from 'lodash-es'
|
import { cloneDeep, forOwn, isFunction } from 'lodash-es'
|
||||||
import { Form } from 'ant-design-vue'
|
import { Form } from 'ant-design-vue'
|
||||||
import type { AForm, IVFormComponent } from '../typings/v-form-component'
|
import type { AForm, IVFormComponent } from '../typings/v-form-component'
|
||||||
import type { IAnyObject } from '../typings/base-type'
|
import type { IAnyObject } from '../typings/base-type'
|
||||||
|
|
||||||
export function useFormInstanceMethods(props: IAnyObject, formdata, context: Partial<SetupContext>, _formInstance: Ref<AForm | null>) {
|
export function useFormInstanceMethods(
|
||||||
|
props: IAnyObject,
|
||||||
|
formdata,
|
||||||
|
context: Partial<SetupContext>,
|
||||||
|
_formInstance: Ref<AForm | null>,
|
||||||
|
) {
|
||||||
/**
|
/**
|
||||||
* 绑定props和on中的上下文为parent
|
* 绑定props和on中的上下文为parent
|
||||||
*/
|
*/
|
||||||
|
@ -13,8 +18,9 @@ export function useFormInstanceMethods(props: IAnyObject, formdata, context: Par
|
||||||
const instance = getCurrentInstance()
|
const instance = getCurrentInstance()
|
||||||
const vm = instance?.parent
|
const vm = instance?.parent
|
||||||
if (!vm)
|
if (!vm)
|
||||||
return
|
return;
|
||||||
;(props.formConfig.schemas as IVFormComponent[]).forEach((item) => {
|
|
||||||
|
(props.formConfig.schemas as IVFormComponent[]).forEach((item) => {
|
||||||
// 绑定 props 中的上下文
|
// 绑定 props 中的上下文
|
||||||
forOwn(item.componentProps, (value: any, key) => {
|
forOwn(item.componentProps, (value: any, key) => {
|
||||||
if (isFunction(value))
|
if (isFunction(value))
|
||||||
|
@ -35,7 +41,7 @@ export function useFormInstanceMethods(props: IAnyObject, formdata, context: Par
|
||||||
|
|
||||||
const { resetFields, validate, clearValidate, validateField } = useForm(formdata, [])
|
const { resetFields, validate, clearValidate, validateField } = useForm(formdata, [])
|
||||||
|
|
||||||
const submit = () => {
|
const submit = async () => {
|
||||||
// const _result = await validate();
|
// const _result = await validate();
|
||||||
|
|
||||||
const data = cloneDeep(toRaw(formdata.value))
|
const data = cloneDeep(toRaw(formdata.value))
|
||||||
|
|
|
@ -13,7 +13,11 @@ export interface IProps {
|
||||||
formModel: IAnyObject
|
formModel: IAnyObject
|
||||||
}
|
}
|
||||||
|
|
||||||
type ISet = <T extends keyof IVFormComponent>(field: string, key: T, value: IVFormComponent[T]) => void
|
type ISet = <T extends keyof IVFormComponent>(
|
||||||
|
field: string,
|
||||||
|
key: T,
|
||||||
|
value: IVFormComponent[T],
|
||||||
|
) => void
|
||||||
// 获取当前field绑定的表单项
|
// 获取当前field绑定的表单项
|
||||||
type IGet = (field: string) => IVFormComponent | undefined
|
type IGet = (field: string) => IVFormComponent | undefined
|
||||||
// 获取field在formData中的值
|
// 获取field在formData中的值
|
||||||
|
@ -59,7 +63,8 @@ export function useVFormMethods(
|
||||||
* @param {string} field
|
* @param {string} field
|
||||||
* @return {IVFormComponent | undefined}
|
* @return {IVFormComponent | undefined}
|
||||||
*/
|
*/
|
||||||
const get: IGet = field => findFormItem(props.formConfig.schemas, item => item.field === field)
|
const get: IGet = field =>
|
||||||
|
findFormItem(props.formConfig.schemas, item => item.field === field)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据表单field设置表单项字段值
|
* 根据表单field设置表单项字段值
|
||||||
|
@ -73,6 +78,20 @@ export function useVFormMethods(
|
||||||
formItem[key] = value
|
formItem[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置表单项的props
|
||||||
|
* @param {string} field 需要设置的表单项field
|
||||||
|
* @param {string} key 需要设置的key
|
||||||
|
* @param value 需要设置的值
|
||||||
|
*/
|
||||||
|
const setProps: ISetProps = (field, key, value) => {
|
||||||
|
const formItem = get(field)
|
||||||
|
if (formItem?.componentProps) {
|
||||||
|
['options', 'treeData'].includes(key) && setValue(field, undefined)
|
||||||
|
|
||||||
|
formItem.componentProps[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 设置字段的值,设置后触发校验
|
* 设置字段的值,设置后触发校验
|
||||||
* @param {string} field 需要设置的字段
|
* @param {string} field 需要设置的字段
|
||||||
|
@ -92,20 +111,6 @@ export function useVFormMethods(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* 设置表单项的props
|
|
||||||
* @param {string} field 需要设置的表单项field
|
|
||||||
* @param {string} key 需要设置的key
|
|
||||||
* @param value 需要设置的值
|
|
||||||
*/
|
|
||||||
const setProps: ISetProps = (field, key, value) => {
|
|
||||||
const formItem = get(field)
|
|
||||||
if (formItem?.componentProps) {
|
|
||||||
;['options', 'treeData'].includes(key) && setValue(field, undefined)
|
|
||||||
|
|
||||||
formItem.componentProps[key] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* 设置表单配置方法
|
* 设置表单配置方法
|
||||||
* @param {string} key
|
* @param {string} key
|
||||||
|
@ -143,7 +148,9 @@ export function useVFormMethods(
|
||||||
* @param {string | undefined} field
|
* @param {string | undefined} field
|
||||||
*/
|
*/
|
||||||
const disable: IDisable = (field) => {
|
const disable: IDisable = (field) => {
|
||||||
typeof field === 'string' ? setProps(field, 'disabled', true) : setFormConfig('disabled', field !== false)
|
typeof field === 'string'
|
||||||
|
? setProps(field, 'disabled', true)
|
||||||
|
: setFormConfig('disabled', field !== false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -44,5 +44,9 @@ export interface IFormDesignMethods {
|
||||||
handleAddAttrs(schemas: IVFormComponent[], index: number): void
|
handleAddAttrs(schemas: IVFormComponent[], index: number): void
|
||||||
setFormConfig(config: IFormConfig): void
|
setFormConfig(config: IFormConfig): void
|
||||||
// 添加到表单中之前触发
|
// 添加到表单中之前触发
|
||||||
handleBeforeColAdd(event: { newIndex: string }, schemas: IVFormComponent[], isCopy?: boolean): void
|
handleBeforeColAdd(
|
||||||
|
event: { newIndex: string },
|
||||||
|
schemas: IVFormComponent[],
|
||||||
|
isCopy?: boolean,
|
||||||
|
): void
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,7 +177,12 @@ export interface AForm {
|
||||||
* validate one or several form items
|
* validate one or several form items
|
||||||
* @type Function
|
* @type Function
|
||||||
*/
|
*/
|
||||||
validateField: (name: string, value: any, rules: Record<string, unknown>[], option?: validateOptions) => Promise<RuleError[]>
|
validateField: (
|
||||||
|
name: string,
|
||||||
|
value: any,
|
||||||
|
rules: Record<string, unknown>[],
|
||||||
|
option?: validateOptions,
|
||||||
|
) => Promise<RuleError[]>
|
||||||
/**
|
/**
|
||||||
* reset all the fields and remove validation result
|
* reset all the fields and remove validation result
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// import { VueConstructor } from 'vue';
|
// import { VueConstructor } from 'vue';
|
||||||
import { cloneDeep, isArray, isFunction, isNumber, uniqueId } from 'lodash-es'
|
import { cloneDeep, isArray, isFunction, isNumber, uniqueId } from 'lodash-es'
|
||||||
import type { Ref } from 'vue'
|
|
||||||
import type { IFormConfig, IVFormComponent, IValidationRule } from '../typings/v-form-component'
|
import type { IFormConfig, IVFormComponent, IValidationRule } from '../typings/v-form-component'
|
||||||
|
|
||||||
// import { del } from '@vue/composition-api';
|
// import { del } from '@vue/composition-api';
|
||||||
|
@ -40,7 +39,10 @@ export function generateKey(formItem?: IVFormComponent): string | boolean {
|
||||||
* @param value {number | ((item: T, index: number, array: Array<T>) => boolean}
|
* @param value {number | ((item: T, index: number, array: Array<T>) => boolean}
|
||||||
* @returns {T} 返回删除的数组项
|
* @returns {T} 返回删除的数组项
|
||||||
*/
|
*/
|
||||||
export function remove<T>(array: Array<T>, value: number | ((item: T, index: number, array: Array<T>) => boolean)): T | undefined {
|
export function remove<T>(
|
||||||
|
array: Array<T>,
|
||||||
|
value: number | ((item: T, index: number, array: Array<T>) => boolean),
|
||||||
|
): T | undefined {
|
||||||
let removeVal: Array<T | undefined> = []
|
let removeVal: Array<T | undefined> = []
|
||||||
if (!isArray(array))
|
if (!isArray(array))
|
||||||
return undefined
|
return undefined
|
||||||
|
@ -107,10 +109,10 @@ export function formItemsForEach(array: IVFormComponent[], cb: (item: IVFormComp
|
||||||
/**
|
/**
|
||||||
* 查找表单项
|
* 查找表单项
|
||||||
*/
|
*/
|
||||||
export const findFormItem: (schemas: IVFormComponent[], cb: (formItem: IVFormComponent) => boolean) => IVFormComponent | undefined = (
|
export const findFormItem: (
|
||||||
schemas,
|
schemas: IVFormComponent[],
|
||||||
cb,
|
cb: (formItem: IVFormComponent) => boolean,
|
||||||
) => {
|
) => IVFormComponent | undefined = (schemas, cb) => {
|
||||||
let res
|
let res
|
||||||
const traverse = (schemas: IVFormComponent[]): boolean => {
|
const traverse = (schemas: IVFormComponent[]): boolean => {
|
||||||
return schemas.some((formItem: IVFormComponent) => {
|
return schemas.some((formItem: IVFormComponent) => {
|
||||||
|
@ -203,45 +205,3 @@ export function runCode<T>(code: any): T {
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 针对 https://github.com/xaboy/form-create-designer 封装的工具类
|
|
||||||
*/
|
|
||||||
|
|
||||||
// 编码表单 Conf
|
|
||||||
export function encodeConf(designerRef: Ref<Recordable>) {
|
|
||||||
return JSON.stringify(designerRef.value.getOption())
|
|
||||||
}
|
|
||||||
|
|
||||||
// 编码表单 Fields
|
|
||||||
export function encodeFields(designerRef: Ref<Recordable>) {
|
|
||||||
const rule = designerRef.value.getRule()
|
|
||||||
const fields: string[] = []
|
|
||||||
rule.forEach((item) => {
|
|
||||||
fields.push(JSON.stringify(item))
|
|
||||||
})
|
|
||||||
return fields
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解码表单 Fields
|
|
||||||
export function decodeFields(fields: string[]) {
|
|
||||||
const rule: object[] = []
|
|
||||||
fields.forEach((item) => {
|
|
||||||
rule.push(JSON.parse(item))
|
|
||||||
})
|
|
||||||
return rule
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置表单的 Conf 和 Fields
|
|
||||||
export function setConfAndFields(designerRef: Ref<Recordable>, conf: string, fields: string[]) {
|
|
||||||
designerRef.value.setOption(JSON.parse(conf))
|
|
||||||
designerRef.value.setRule(decodeFields(fields))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置表单的 Conf 和 Fields
|
|
||||||
export function setConfAndFields2(detailPreview: Ref<Recordable>, conf: string, fields: string[], value?: object) {
|
|
||||||
detailPreview.value.option = JSON.parse(conf)
|
|
||||||
detailPreview.value.rule = decodeFields(fields)
|
|
||||||
if (value)
|
|
||||||
detailPreview.value.value = value
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue