feat: 表单节点添加多选框,选项卡等组件 (#1651)

This commit is contained in:
shaohuzhang1 2024-11-19 14:24:38 +08:00 committed by GitHub
parent 1bc7f70f79
commit 6801a24c38
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 528 additions and 54 deletions

View File

@ -15,6 +15,10 @@ const input_type_list = [
label: '单选框',
value: 'SingleSelect'
},
{
label: '多选框',
value: 'MultiSelect'
},
{
label: '日期',
value: 'DatePicker'
@ -22,6 +26,14 @@ const input_type_list = [
{
label: 'JSON文本框',
value: 'JsonInput'
},
{
label: '选项卡',
value: 'RadioCard'
},
{
label: '单行选项卡',
value: 'RadioRow'
}
]
export { input_type_list }

View File

@ -0,0 +1,129 @@
<template>
<el-form-item>
<template #label>
<div class="flex-between">
选项值
<el-button link type="primary" @click.stop="addOption()">
<el-icon class="mr-4">
<Plus />
</el-icon>
添加
</el-button>
</div>
</template>
<el-row style="width: 100%" :gutter="10">
<el-col :span="10"
><div class="grid-content ep-bg-purple" />
标签</el-col
>
<el-col :span="12"
><div class="grid-content ep-bg-purple" />
选项值</el-col
>
</el-row>
<el-row
style="width: 100%"
v-for="(option, $index) in formValue.option_list"
:key="$index"
:gutter="10"
>
<el-col :span="10"
><div class="grid-content ep-bg-purple" />
<el-input v-model="formValue.option_list[$index].label" placeholder="请输入选项标签"
/></el-col>
<el-col :span="12"
><div class="grid-content ep-bg-purple" />
<el-input v-model="formValue.option_list[$index].value" placeholder="请输入选项值"
/></el-col>
<el-col :span="1"
><div class="grid-content ep-bg-purple" />
<el-button link class="ml-8" @click.stop="delOption($index)">
<el-icon>
<Delete />
</el-icon> </el-button
></el-col>
</el-row>
</el-form-item>
<el-form-item
label="默认值"
:required="formValue.required"
prop="default_value"
:rules="formValue.required ? [{ required: true, message: '默认值 为必填属性' }] : []"
>
<el-select
class="m-2"
multiple
collapse-tags
filterable
clearable
v-model="formValue.default_value"
:teleported="false"
popper-class="default-select"
>
<el-option
v-for="(option, index) in formValue.option_list"
:key="index"
:label="option.value"
:value="option.value"
/>
</el-select>
</el-form-item>
</template>
<script setup lang="ts">
import { computed, onMounted } from 'vue'
const props = defineProps<{
modelValue: any
}>()
const emit = defineEmits(['update:modelValue'])
const formValue = computed({
set: (item) => {
emit('update:modelValue', item)
},
get: () => {
return props.modelValue
}
})
const addOption = () => {
formValue.value.option_list.push({ value: '', label: '' })
}
const delOption = (index: number) => {
const option = formValue.value.option_list[index]
if (option.value && formValue.value.default_value == option.value) {
formValue.value.default_value = ''
}
formValue.value.option_list.splice(index, 1)
}
const getData = () => {
return {
input_type: 'MultiSelect',
attrs: {},
default_value: formValue.value.default_value,
textField: 'label',
valueField: 'value',
option_list: formValue.value.option_list
}
}
const rander = (form_data: any) => {
formValue.value.option_list = form_data.option_list || []
formValue.value.default_value = form_data.default_value
}
defineExpose({ getData, rander })
onMounted(() => {
formValue.value.option_list = []
formValue.value.default_value = ''
})
</script>
<style lang="scss" scoped>
:deep(.el-form-item__label) {
display: block;
}
:deep(.el-select-dropdown) {
max-width: 400px;
}
</style>

View File

@ -0,0 +1,122 @@
<template>
<el-form-item>
<template #label>
<div class="flex-between">
选项值
<el-button link type="primary" @click.stop="addOption()">
<el-icon class="mr-4">
<Plus />
</el-icon>
添加
</el-button>
</div>
</template>
<el-row style="width: 100%" :gutter="10">
<el-col :span="10"
><div class="grid-content ep-bg-purple" />
标签</el-col
>
<el-col :span="12"
><div class="grid-content ep-bg-purple" />
选项值</el-col
>
</el-row>
<el-row
style="width: 100%"
v-for="(option, $index) in formValue.option_list"
:key="$index"
:gutter="10"
>
<el-col :span="10"
><div class="grid-content ep-bg-purple" />
<el-input v-model="formValue.option_list[$index].label" placeholder="请输入选项标签"
/></el-col>
<el-col :span="12"
><div class="grid-content ep-bg-purple" />
<el-input v-model="formValue.option_list[$index].value" placeholder="请输入选项值"
/></el-col>
<el-col :span="1"
><div class="grid-content ep-bg-purple" />
<el-button link class="ml-8" @click.stop="delOption($index)">
<el-icon>
<Delete />
</el-icon> </el-button
></el-col>
</el-row>
</el-form-item>
<el-form-item
label="默认值"
:required="formValue.required"
prop="default_value"
:rules="formValue.required ? [{ required: true, message: '默认值 为必填属性' }] : []"
>
<RadioCard
:form-field="formField"
v-model="formValue.default_value"
:other-params="{}"
field="default_value"
>
</RadioCard>
</el-form-item>
</template>
<script setup lang="ts">
import { computed, onMounted } from 'vue'
import RadioCard from '@/components/dynamics-form/items/radio/RadioCard.vue'
const props = defineProps<{
modelValue: any
}>()
const emit = defineEmits(['update:modelValue'])
const formValue = computed({
set: (item) => {
emit('update:modelValue', item)
},
get: () => {
return props.modelValue
}
})
const addOption = () => {
formValue.value.option_list.push({ value: '', label: '' })
}
const delOption = (index: number) => {
const option = formValue.value.option_list[index]
if (option.value && formValue.value.default_value == option.value) {
formValue.value.default_value = ''
}
formValue.value.option_list.splice(index, 1)
}
const formField = computed(() => {
return getData()
})
const getData = () => {
return {
input_type: 'RadioCard',
attrs: {},
default_value: formValue.value.default_value,
text_field: 'label',
value_field: 'value',
option_list: formValue.value.option_list
}
}
const rander = (form_data: any) => {
formValue.value.option_list = form_data.option_list || []
formValue.value.default_value = form_data.default_value
}
defineExpose({ getData, rander })
onMounted(() => {
formValue.value.option_list = []
formValue.value.default_value = ''
})
</script>
<style lang="scss" scoped>
:deep(.el-form-item__label) {
display: block;
}
:deep(.el-select-dropdown) {
max-width: 400px;
}
</style>

View File

@ -0,0 +1,122 @@
<template>
<el-form-item>
<template #label>
<div class="flex-between">
选项值
<el-button link type="primary" @click.stop="addOption()">
<el-icon class="mr-4">
<Plus />
</el-icon>
添加
</el-button>
</div>
</template>
<el-row style="width: 100%" :gutter="10">
<el-col :span="10"
><div class="grid-content ep-bg-purple" />
标签</el-col
>
<el-col :span="12"
><div class="grid-content ep-bg-purple" />
选项值</el-col
>
</el-row>
<el-row
style="width: 100%"
v-for="(option, $index) in formValue.option_list"
:key="$index"
:gutter="10"
>
<el-col :span="10"
><div class="grid-content ep-bg-purple" />
<el-input v-model="formValue.option_list[$index].label" placeholder="请输入选项标签"
/></el-col>
<el-col :span="12"
><div class="grid-content ep-bg-purple" />
<el-input v-model="formValue.option_list[$index].value" placeholder="请输入选项值"
/></el-col>
<el-col :span="1"
><div class="grid-content ep-bg-purple" />
<el-button link class="ml-8" @click.stop="delOption($index)">
<el-icon>
<Delete />
</el-icon> </el-button
></el-col>
</el-row>
</el-form-item>
<el-form-item
label="默认值"
:required="formValue.required"
prop="default_value"
:rules="formValue.required ? [{ required: true, message: '默认值 为必填属性' }] : []"
>
<RadioRow
:form-field="formField"
v-model="formValue.default_value"
:other-params="{}"
field="default_value"
>
</RadioRow>
</el-form-item>
</template>
<script setup lang="ts">
import { computed, onMounted } from 'vue'
import RadioRow from '@/components/dynamics-form/items/radio/RadioRow.vue'
const props = defineProps<{
modelValue: any
}>()
const emit = defineEmits(['update:modelValue'])
const formValue = computed({
set: (item) => {
emit('update:modelValue', item)
},
get: () => {
return props.modelValue
}
})
const addOption = () => {
formValue.value.option_list.push({ value: '', label: '' })
}
const delOption = (index: number) => {
const option = formValue.value.option_list[index]
if (option.value && formValue.value.default_value == option.value) {
formValue.value.default_value = ''
}
formValue.value.option_list.splice(index, 1)
}
const formField = computed(() => {
return getData()
})
const getData = () => {
return {
input_type: 'RadioCard',
attrs: {},
default_value: formValue.value.default_value,
text_field: 'label',
value_field: 'value',
option_list: formValue.value.option_list
}
}
const rander = (form_data: any) => {
formValue.value.option_list = form_data.option_list || []
formValue.value.default_value = form_data.default_value
}
defineExpose({ getData, rander })
onMounted(() => {
formValue.value.option_list = []
formValue.value.default_value = ''
})
</script>
<style lang="scss" scoped>
:deep(.el-form-item__label) {
display: block;
}
:deep(.el-select-dropdown) {
max-width: 400px;
}
</style>

View File

@ -12,18 +12,38 @@
</div>
</template>
<div
class="w-full flex-between mb-8"
<el-row style="width: 100%" :gutter="10">
<el-col :span="10"
><div class="grid-content ep-bg-purple" />
标签</el-col
>
<el-col :span="12"
><div class="grid-content ep-bg-purple" />
选项值</el-col
>
</el-row>
<el-row
style="width: 100%"
v-for="(option, $index) in formValue.option_list"
:key="$index"
:gutter="10"
>
<el-input v-model="formValue.option_list[$index].value" placeholder="请输入选项值" />
<el-button link class="ml-8" @click.stop="delOption($index)">
<el-icon>
<Delete />
</el-icon>
</el-button>
</div>
<el-col :span="10"
><div class="grid-content ep-bg-purple" />
<el-input v-model="formValue.option_list[$index].label" placeholder="请输入选项标签"
/></el-col>
<el-col :span="12"
><div class="grid-content ep-bg-purple" />
<el-input v-model="formValue.option_list[$index].value" placeholder="请输入选项值"
/></el-col>
<el-col :span="1"
><div class="grid-content ep-bg-purple" />
<el-button link class="ml-8" @click.stop="delOption($index)">
<el-icon>
<Delete />
</el-icon> </el-button
></el-col>
</el-row>
</el-form-item>
<el-form-item
label="默认值"
@ -58,7 +78,7 @@ const formValue = computed({
})
const addOption = () => {
formValue.value.option_list.push({ value: '' })
formValue.value.option_list.push({ value: '', label: '' })
}
const delOption = (index: number) => {
@ -74,8 +94,8 @@ const getData = () => {
input_type: 'SingleSelect',
attrs: {},
default_value: formValue.value.default_value,
text_field: 'value',
value_field: 'value',
textField: 'label',
valueField: 'value',
option_list: formValue.value.option_list
}
}

View File

@ -1,18 +1,19 @@
<template>
<div class="radio_content">
<div
<div class="radio_content" v-resize="resize" :style="radioContentStyle">
<el-card
v-for="item in option_list"
:key="item.value"
class="item"
shadow="never"
:class="[modelValue == item[valueField] ? 'active' : '']"
@click="selected(item[valueField])"
>
{{ item[textField] }}
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { watch, computed } from 'vue'
import { computed, ref } from 'vue'
import type { FormField } from '@/components/dynamics-form/type'
const props = defineProps<{
formValue?: any
@ -29,7 +30,24 @@ const selected = (activeValue: string | number) => {
emit('update:modelValue', activeValue)
}
const emit = defineEmits(['update:modelValue'])
const width = ref<number>()
const radioContentStyle = computed(() => {
if (width.value) {
if (width.value < 350) {
return { '--maxkb-radio-card-width': '316px' }
} else if (width.value > 770) {
return { '--maxkb-radio-card-width': '378px' }
} else {
return { '--maxkb-radio-card-width': '100%' }
}
}
return {}
})
const resize = (wh: any) => {
if (wh.height) {
width.value = wh.width
}
}
const textField = computed(() => {
return props.formField.text_field ? props.formField.text_field : 'key'
})
@ -41,52 +59,24 @@ const valueField = computed(() => {
const option_list = computed(() => {
return props.formField.option_list ? props.formField.option_list : []
})
watch(
option_list,
() => {
if (
(option_list.value &&
option_list.value.length > 0 &&
!option_list.value.some((item) => item.value === props.modelValue)) ||
!props.modelValue
) {
emit('update:modelValue', option_list.value[0][valueField.value])
}
},
{ immediate: true }
)
</script>
<style lang="scss" scoped>
.radio_content {
height: 32px;
display: inline-flex;
border: 1px solid #bbbfc4;
border-radius: 4px;
font-weight: 400;
font-size: 14px;
color: #1f2329;
padding: 3px 4px;
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
width: 100%;
.active {
border-radius: 4px;
background: var(--el-color-primary-light-9);
color: var(--el-color-primary);
border: 1px solid var(--el-color-primary);
}
.item {
cursor: pointer;
margin: 0px 2px;
padding: 2px 8px;
height: 20px;
height: 38px;
display: flex;
justify-content: center;
align-items: center;
&:last-child {
margin: 0 4px 0 2px;
}
&:first-child {
margin: 0 2px 0 4px;
}
width: var(--maxkb-radio-card-width, 100%);
margin: 4px;
}
}
</style>

View File

@ -0,0 +1,79 @@
<template>
<div class="radio_content">
<div
v-for="item in option_list"
:key="item.value"
class="item"
:class="[modelValue == item[valueField] ? 'active' : '']"
@click="selected(item[valueField])"
>
{{ item[textField] }}
</div>
</div>
</template>
<script lang="ts" setup>
import { computed } from 'vue'
import type { FormField } from '@/components/dynamics-form/type'
const props = defineProps<{
formValue?: any
formfieldList?: Array<FormField>
field: string
otherParams: any
formField: FormField
view?: boolean
//
modelValue?: any
}>()
const selected = (activeValue: string | number) => {
emit('update:modelValue', activeValue)
}
const emit = defineEmits(['update:modelValue'])
const textField = computed(() => {
return props.formField.text_field ? props.formField.text_field : 'key'
})
const valueField = computed(() => {
return props.formField.value_field ? props.formField.value_field : 'value'
})
const option_list = computed(() => {
return props.formField.option_list ? props.formField.option_list : []
})
</script>
<style lang="scss" scoped>
.radio_content {
height: 32px;
display: inline-flex;
border: 1px solid #bbbfc4;
border-radius: 4px;
font-weight: 400;
font-size: 14px;
color: #1f2329;
padding: 3px 4px;
box-sizing: border-box;
white-space: nowrap;
.active {
border-radius: 4px;
background: var(--el-color-primary-light-9);
color: var(--el-color-primary);
}
.item {
cursor: pointer;
margin: 0px 2px;
padding: 2px 8px;
height: 20px;
display: flex;
justify-content: center;
align-items: center;
&:last-child {
margin: 0 4px 0 2px;
}
&:first-child {
margin: 0 2px 0 4px;
}
}
}
</style>

View File

@ -76,7 +76,7 @@
<el-table-column label="必填">
<template #default="{ row }">
<div @click.stop>
<el-switch disabled size="small" v-model="row.is_required" />
<el-switch disabled size="small" v-model="row.required" />
</div>
</template>
</el-table-column>