mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 01:33:05 +00:00
feat: Support single line multi select cards (#3976)
This commit is contained in:
parent
b1dcdcbf97
commit
67bb0a0abd
|
|
@ -16,6 +16,11 @@ from application.flow.common import Answer
|
|||
from application.flow.i_step_node import NodeResult
|
||||
from application.flow.step_node.form_node.i_form_node import IFormNode
|
||||
|
||||
multi_select_list = [
|
||||
'MultiSelect',
|
||||
'MultiRow'
|
||||
]
|
||||
|
||||
|
||||
def get_default_option(option_list, _type, value_field):
|
||||
try:
|
||||
|
|
@ -23,10 +28,10 @@ def get_default_option(option_list, _type, value_field):
|
|||
default_value_list = [o.get(value_field) for o in option_list if o.get('default')]
|
||||
if len(default_value_list) == 0:
|
||||
return [option_list[0].get(
|
||||
value_field)] if _type == 'MultiSelect' else option_list[0].get(
|
||||
value_field)] if multi_select_list.__contains__(_type) else option_list[0].get(
|
||||
value_field)
|
||||
else:
|
||||
if _type == 'MultiSelect':
|
||||
if multi_select_list.__contains__(_type):
|
||||
return default_value_list
|
||||
else:
|
||||
return default_value_list[0]
|
||||
|
|
@ -84,7 +89,7 @@ class BaseFormNode(IFormNode):
|
|||
if tooltip is not None:
|
||||
_value.get('attrs')['tooltip'] = generate_prompt(self.workflow_manage, tooltip)
|
||||
|
||||
if ['SingleSelect', 'MultiSelect', 'RadioCard', 'RadioRow'].__contains__(field.get('input_type')):
|
||||
if ['SingleSelect', 'MultiSelect', 'RadioCard', 'RadioRow', 'MultiRow'].__contains__(field.get('input_type')):
|
||||
if field.get('assignment_method') == 'ref_variables':
|
||||
option_list = self.workflow_manage.get_reference_field(field.get('option_list')[0],
|
||||
field.get('option_list')[1:])
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ const input_type_list = [
|
|||
label: t('dynamicsForm.input_type_list.RadioRow'),
|
||||
value: 'RadioRow',
|
||||
},
|
||||
{
|
||||
label: t('dynamicsForm.input_type_list.MultiRow'),
|
||||
value: 'MultiRow',
|
||||
},
|
||||
{
|
||||
label: t('dynamicsForm.input_type_list.Slider'),
|
||||
value: 'Slider',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,252 @@
|
|||
<template>
|
||||
<el-form-item v-if="getModel">
|
||||
<template #label>
|
||||
<div class="flex-between">
|
||||
{{ $t('dynamicsForm.AssignmentMethod.label', '赋值方式') }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-row style="width: 100%" :gutter="10">
|
||||
<el-radio-group @change="formValue.option_list = []" v-model="formValue.assignment_method">
|
||||
<el-radio :value="item.value" size="large" v-for="item in assignment_method_option_list"
|
||||
>{{ item.label }}
|
||||
<el-popover
|
||||
width="300px"
|
||||
v-if="item.value == 'ref_variables'"
|
||||
class="box-item"
|
||||
placement="top-start"
|
||||
>
|
||||
{{ $t('dynamicsForm.AssignmentMethod.ref_variables.popover') }}:<br />
|
||||
[<br />
|
||||
{<br />
|
||||
"label": "xx",<br />
|
||||
"value": "xx",<br />
|
||||
"default": false<br />
|
||||
}<br />
|
||||
]<br />
|
||||
label: {{ $t('dynamicsForm.AssignmentMethod.ref_variables.popover_label') }}
|
||||
{{ $t('common.required') }}<br />
|
||||
value: {{ $t('dynamicsForm.AssignmentMethod.ref_variables.popover_value') }}
|
||||
{{ $t('common.required') }}<br />
|
||||
default:{{ $t('dynamicsForm.AssignmentMethod.ref_variables.popover_default') }}
|
||||
<template #reference>
|
||||
<el-icon><InfoFilled /></el-icon>
|
||||
</template>
|
||||
</el-popover>
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="formValue.assignment_method == 'ref_variables'"
|
||||
:required="true"
|
||||
prop="option_list"
|
||||
:rules="[default_ref_variables_value_rule]"
|
||||
>
|
||||
<NodeCascader
|
||||
ref="nodeCascaderRef"
|
||||
:nodeModel="model"
|
||||
class="w-full"
|
||||
:placeholder="$t('views.applicationWorkflow.variable.placeholder')"
|
||||
v-model="formValue.option_list"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="formValue.assignment_method == 'custom'">
|
||||
<template #label>
|
||||
<div class="flex-between">
|
||||
{{ $t('dynamicsForm.Select.label') }}
|
||||
<el-button link type="primary" @click.stop="addOption()">
|
||||
<AppIcon iconName="app-add-outlined" class="mr-4"></AppIcon>
|
||||
{{ $t('common.add') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-row style="width: 100%" :gutter="10">
|
||||
<el-col :span="10">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
{{ $t('dynamicsForm.tag.label') }}
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
{{ $t('dynamicsForm.Select.label') }}
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row
|
||||
style="width: 100%"
|
||||
v-for="(option, $index) in formValue.option_list"
|
||||
:key="$index"
|
||||
:gutter="10"
|
||||
class="mb-8"
|
||||
>
|
||||
<el-col :span="10">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
<el-input
|
||||
v-model="formValue.option_list[$index].label"
|
||||
:placeholder="$t('dynamicsForm.tag.placeholder')"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
<el-input
|
||||
v-model="formValue.option_list[$index].value"
|
||||
:placeholder="$t('dynamicsForm.Select.label')"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="1">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
<el-button link class="ml-8" @click.stop="delOption($index)">
|
||||
<AppIcon iconName="app-delete"></AppIcon>
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="formValue.assignment_method == 'custom'"
|
||||
class="defaultValueItem"
|
||||
:label="$t('dynamicsForm.default.label')"
|
||||
:required="formValue.required"
|
||||
prop="default_value"
|
||||
:rules="
|
||||
formValue.required
|
||||
? [
|
||||
{
|
||||
required: true,
|
||||
message: `${$t('dynamicsForm.default.label')}${$t('dynamicsForm.default.requiredMessage')}`,
|
||||
},
|
||||
]
|
||||
: []
|
||||
"
|
||||
>
|
||||
<div class="defaultValueCheckbox">
|
||||
<el-checkbox
|
||||
v-model="formValue.show_default_value"
|
||||
:label="$t('dynamicsForm.default.show')"
|
||||
/>
|
||||
</div>
|
||||
<MultiRow
|
||||
:form-field="formField"
|
||||
v-model="formValue.default_value"
|
||||
:other-params="{}"
|
||||
field="default_value"
|
||||
>
|
||||
</MultiRow>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, inject } from 'vue'
|
||||
import MultiRow from '@/components/dynamics-form/items/MultiRow.vue'
|
||||
import NodeCascader from '@/workflow/common/NodeCascader.vue'
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import { t } from '@/locales'
|
||||
const getModel = inject('getModel') as any
|
||||
|
||||
const assignment_method_option_list = computed(() => {
|
||||
const option_list = [
|
||||
{
|
||||
label: t('dynamicsForm.AssignmentMethod.custom.label', '自定义'),
|
||||
value: 'custom',
|
||||
},
|
||||
]
|
||||
if (getModel) {
|
||||
option_list.push({
|
||||
label: t('dynamicsForm.AssignmentMethod.ref_variables.label', '引用变量'),
|
||||
value: 'ref_variables',
|
||||
})
|
||||
}
|
||||
return option_list
|
||||
})
|
||||
|
||||
const model = computed(() => {
|
||||
if (getModel) {
|
||||
return getModel()
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
})
|
||||
const props = defineProps<{
|
||||
modelValue: any
|
||||
}>()
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const formValue = computed({
|
||||
set: (item) => {
|
||||
emit('update:modelValue', item)
|
||||
},
|
||||
get: () => {
|
||||
return props.modelValue
|
||||
},
|
||||
})
|
||||
|
||||
const default_ref_variables_value_rule = {
|
||||
required: true,
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
console.log(value.length)
|
||||
if (!(Array.isArray(value) && value.length > 1)) {
|
||||
callback(
|
||||
t('dynamicsForm.AssignmentMethod.ref_variables.label', '引用变量') + t('common.required'),
|
||||
)
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
trigger: 'blur',
|
||||
}
|
||||
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<FormField>(() => {
|
||||
return { field: '', ...getData() }
|
||||
})
|
||||
const getData = () => {
|
||||
return {
|
||||
input_type: 'MultiRow',
|
||||
attrs: {},
|
||||
default_value: formValue.value.default_value,
|
||||
text_field: 'label',
|
||||
value_field: 'value',
|
||||
option_list: formValue.value.option_list,
|
||||
assignment_method: formValue.value.assignment_method || 'custom',
|
||||
}
|
||||
}
|
||||
const rander = (form_data: any) => {
|
||||
formValue.value.option_list = form_data.option_list || []
|
||||
formValue.value.default_value = form_data.default_value
|
||||
formValue.value.assignment_method = form_data.assignment_method || 'custom'
|
||||
}
|
||||
|
||||
defineExpose({ getData, rander })
|
||||
onMounted(() => {
|
||||
formValue.value.option_list = []
|
||||
formValue.value.default_value = ''
|
||||
formValue.value.assignment_method = 'custom'
|
||||
if (formValue.value.show_default_value === undefined) {
|
||||
formValue.value.show_default_value = true
|
||||
}
|
||||
addOption()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.defaultValueItem {
|
||||
position: relative;
|
||||
.defaultValueCheckbox {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: -35px;
|
||||
}
|
||||
}
|
||||
:deep(.el-form-item__label) {
|
||||
display: block;
|
||||
}
|
||||
|
||||
:deep(.el-select-dropdown) {
|
||||
max-width: 400px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
<template>
|
||||
<div class="radio_content">
|
||||
<div
|
||||
v-for="item in option_list"
|
||||
:key="item.value"
|
||||
class="item"
|
||||
:class="[
|
||||
inputDisabled ? 'is-disabled' : '',
|
||||
_value.includes(item[valueField]) ? 'active' : '',
|
||||
]"
|
||||
@click="selected(item[valueField])"
|
||||
>
|
||||
{{ item[textField] }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject } from 'vue'
|
||||
import type { FormField } from '@/components/dynamics-form/type'
|
||||
import { useFormDisabled, formItemContextKey } from 'element-plus'
|
||||
const inputDisabled = useFormDisabled()
|
||||
const props = defineProps<{
|
||||
formValue?: any
|
||||
formfieldList?: Array<FormField>
|
||||
field: string
|
||||
otherParams: any
|
||||
formField: FormField
|
||||
view?: boolean
|
||||
// 选中的值
|
||||
modelValue?: any
|
||||
}>()
|
||||
const elFormItem = inject(formItemContextKey, void 0)
|
||||
const selected = (activeValue: string | number) => {
|
||||
if (_value.value.includes(activeValue)) {
|
||||
emit(
|
||||
'update:modelValue',
|
||||
props.modelValue.filter((i: any) => i != activeValue),
|
||||
)
|
||||
} else {
|
||||
emit('update:modelValue', props.modelValue ? [...props.modelValue, activeValue] : [activeValue])
|
||||
}
|
||||
if (elFormItem?.validate) {
|
||||
elFormItem.validate('change')
|
||||
}
|
||||
}
|
||||
const _value = computed(() => {
|
||||
return props.modelValue ? props.modelValue : []
|
||||
})
|
||||
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: var(--el-text-color-primary);
|
||||
padding: 3px 4px;
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
.is-disabled {
|
||||
border: 1px solid var(--el-card-border-color);
|
||||
background-color: var(--el-fill-color-light);
|
||||
color: var(--el-text-color-placeholder);
|
||||
cursor: not-allowed;
|
||||
&:hover {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
.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>
|
||||
|
|
@ -12,6 +12,7 @@ export default {
|
|||
RadioRow: '单行选项卡',
|
||||
UploadInput: '文件上传',
|
||||
TextareaInput: '多行文本框',
|
||||
MultiRow: '单行多选卡',
|
||||
},
|
||||
default: {
|
||||
label: '默认值',
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ export default {
|
|||
RadioRow: '單行選項卡',
|
||||
UploadInput: '文件上傳',
|
||||
TextareaInput: '多行文字方塊',
|
||||
MultiRow: '單行多選卡',
|
||||
},
|
||||
default: {
|
||||
label: '預設值',
|
||||
|
|
|
|||
Loading…
Reference in New Issue