mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 01:33:05 +00:00
feat: 表单节点添加多选框,选项卡等组件 (#1651)
This commit is contained in:
parent
1bc7f70f79
commit
6801a24c38
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue