feat: Group field dialog

This commit is contained in:
zhangzhanwei 2025-10-27 13:43:40 +08:00 committed by zhanweizhang7
parent 42d7aeb5bf
commit 2fc4a393ad
4 changed files with 179 additions and 81 deletions

View File

@ -17,7 +17,8 @@ class VariableListSerializer(serializers.Serializer):
class VariableGroupSerializer(serializers.Serializer):
id = serializers.CharField(required=True, label=_("Group id"))
group_name = serializers.CharField(required=True, label=_("group_name"))
field = serializers.CharField(required=True, label=_("group_name"))
label = serializers.CharField(required=True)
variable_list = VariableListSerializer(many=True)

View File

@ -38,7 +38,7 @@ class BaseVariableAggregationNode(IVariableAggregation):
'variable_to_json': self.set_variable_to_json,
}
result = { item.get('group_name'):strategy_map[strategy](item.get('variable_list')) for item in group_list}
result = { item.get('field'):strategy_map[strategy](item.get('variable_list')) for item in group_list}
return NodeResult({'result': result,**result},{})

View File

@ -0,0 +1,118 @@
<template>
<el-dialog
:title="isEdit ? $t('common.param.editParam') : $t('common.param.addParam')"
v-model="dialogVisible"
:close-on-click-modal="false"
:close-on-press-escape="false"
:destroy-on-close="true"
:before-close="close"
append-to-body
>
<el-form
label-position="top"
ref="fieldFormRef"
:rules="rules"
:model="form"
require-asterisk-position="right"
>
<el-form-item
:label="$t('dynamicsForm.paramForm.field.label')"
:required="true"
prop="field"
:rules="rules.field"
>
<el-input
v-model="form.field"
:maxlength="64"
:placeholder="$t('dynamicsForm.paramForm.field.placeholder')"
show-word-limit
/>
</el-form-item>
<el-form-item
:label="$t('dynamicsForm.paramForm.name.label')"
:required="true"
prop="label"
:rules="rules.label"
>
<el-input
v-model="form.label"
:maxlength="64"
show-word-limit
:placeholder="$t('dynamicsForm.paramForm.name.placeholder')"
/>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click.prevent="close"> {{ $t('common.cancel') }} </el-button>
<el-button type="primary" @click="submit(fieldFormRef)" :loading="loading">
{{ isEdit ? $t('common.save') : $t('common.add') }}
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue'
import type { FormInstance } from 'element-plus'
import { cloneDeep } from 'lodash'
import { t } from '@/locales'
const emit = defineEmits(['refresh'])
const fieldFormRef = ref()
const loading = ref<boolean>(false)
const isEdit = ref(false)
const currentIndex = ref(null)
const form = ref<any>({
field: '',
label: '',
})
const rules = reactive({
label: [
{ required: true, message: t('dynamicsForm.paramForm.name.requiredMessage'), trigger: 'blur' },
],
field: [
{ required: true, message: t('dynamicsForm.paramForm.field.requiredMessage'), trigger: 'blur' },
{
pattern: /^[a-zA-Z0-9_]+$/,
message: t('dynamicsForm.paramForm.field.requiredMessage2'),
trigger: 'blur',
},
],
})
const dialogVisible = ref<boolean>(false)
const open = (data: any, index?: any) => {
if (data) {
form.value = cloneDeep(data)
isEdit.value = true
currentIndex.value = index
}
dialogVisible.value = true
}
const close = () => {
dialogVisible.value = false
isEdit.value = false
currentIndex.value = null
form.value = {
field: '',
label: '',
}
}
const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid) => {
if (valid) {
emit('refresh', form.value, currentIndex.value)
}
})
}
defineExpose({ open, close })
</script>
<style lang="scss" scoped></style>

View File

@ -39,11 +39,11 @@
/>
</el-select>
</el-form-item>
<div v-for="(group_list, gIndex) in form_data.group_list" :key="group_list.id" class="mb-8">
<div v-for="(group, gIndex) in form_data.group_list" :key="group.id" class="mb-8">
<el-card shadow="never" class="card-never" style="--el-card-padding: 12px">
<div class="flex-between mb-12">
<el-form-item
<!-- <el-form-item
v-if="editingGroupIndex === gIndex"
:prop="`group_list.${gIndex}.group_name`"
:rules="groupNameRules(gIndex)"
@ -58,10 +58,10 @@
style="width: 200px; font-weight: bold;"
>
</el-input>
</el-form-item>
<span v-else class="font-bold">{{ group_list.group_name }}</span>
</el-form-item> -->
<span class="font-bold">{{ group.field }}</span>
<div class="flex align-center">
<el-button @click="editGroupName(gIndex)" size="large" link>
<el-button @click="openAddOrEditDialog(group,gIndex)" size="large" link>
<el-icon><EditPen /></el-icon>
</el-button>
<el-button @click="deleteGroup(gIndex)" size="large" link :disabled="form_data.group_list.length <= 1">
@ -70,7 +70,7 @@
</div>
</div>
<div v-for="(item, vIndex) in group_list.variable_list" :key="item.v_id" class="mb-4">
<div v-for="(item, vIndex) in group.variable_list" :key="item.v_id" class="mb-4">
<el-row :gutter="8">
<el-col :span="21">
<el-form-item
@ -96,7 +96,7 @@
link
size="large"
class="mt-4"
:disabled="group_list.variable_list.length <= 1"
:disabled="group.variable_list.length <= 1"
@click="deleteVariable(gIndex, vIndex)"
>
<AppIcon iconName="app-delete"></AppIcon>
@ -112,36 +112,37 @@
</el-card>
</div>
<el-button @click="addGroup" type="primary" size="large" link>
<el-button @click="openAddOrEditDialog()" type="primary" size="large" link>
<AppIcon iconName="app-add-outlined" class="mr-4"/>
{{ $t('views.applicationWorkflow.nodes.variableAggregationNode.add') }}
</el-button>
</el-form>
<GroupFieldDialog ref="GroupFieldDialogRef" @refresh="refreshFieldList"></GroupFieldDialog>
</NodeContainer>
</template>
<script setup lang="ts">
import { set, cloneDeep, debounce } from 'lodash'
import { set, cloneDeep } from 'lodash'
import NodeCascader from '@/workflow/common/NodeCascader.vue'
import NodeContainer from '@/workflow/common/NodeContainer.vue'
import { ref, computed, onMounted, nextTick } from 'vue'
import GroupFieldDialog from './component/GroupFieldDialog.vue'
import { ref, computed, onMounted } from 'vue'
import { isLastNode } from '@/workflow/common/data'
import { t } from '@/locales'
import { randomId } from '@/utils/common'
import { MsgError } from '@/utils/message'
const props = defineProps<{ nodeModel: any }>()
const VariableAggregationRef = ref()
const nodeCascaderRef = ref()
const editingGroupIndex = ref<number | null>(null)
const groupNameInputRef = ref()
const GroupFieldDialogRef = ref()
const form = {
strategy: 'first_non_null',
group_list: [
{
id: randomId(),
group_name: 'Group1',
label: 'Group1',
field: 'Group1',
variable_list: [
{
v_id: randomId(),
@ -165,68 +166,53 @@ const form_data = computed({
}
})
const isGroupNameValid = ref<boolean>(true)
const groupNameErrMsg = ref('')
const tempGroupName = ref('')
const inputFieldList = ref<any[]>([])
const editGroupName = async (gIndex: number) => {
editingGroupIndex.value = gIndex
tempGroupName.value = form_data.value.group_list[gIndex].group_name
isGroupNameValid.value = true
groupNameErrMsg.value = ''
await nextTick()
if (groupNameInputRef.value) {
groupNameInputRef.value.focus()
function openAddOrEditDialog(group?: any, index?: any) {
let data = null
if (group && index !== undefined) {
data = {
field: group.field,
label: group.label,
}
}
GroupFieldDialogRef.value.open(data,index)
}
const groupNameRules = (gIndex: number) => [
{
required: true,
message: t('views.applicationWorkflow.nodes.variableAggregationNode.group.noneError'),
trigger: 'blur'
},
{
validator: (rule: any, value: string, callback: any) => {
const trimmedValue = value?.trim() || ''
const hasDuplicate = form_data.value.group_list.some((item: any, index: number) =>
index !== gIndex && item.group_name.trim() === trimmedValue
)
if (hasDuplicate) {
callback(new Error(t('views.applicationWorkflow.nodes.variableAggregationNode.group.dupError')))
} else {
callback()
}
},
trigger: 'change' //
function refreshFieldList(data: any, index: any) {
for (let i = 0; i < inputFieldList.value.length; i++) {
if (inputFieldList.value[i].field === data.field && index !== i) {
MsgError(t('views.applicationWorkflow.tip.paramErrorMessage') + data.field)
return
}
}
]
const validateGroupNameField = debounce((gIndex: number) => {
VariableAggregationRef.value?.validateField(`group_list.${gIndex}.group_name`)
}, 500)
const finishEditGroupName = async (gIndex: number) => {
try {
await VariableAggregationRef.value?.validateField(`group_list.${gIndex}.group_name`)
const c_group_list = cloneDeep(form_data.value.group_list)
const fields = c_group_list.map((item:any) => ({ label: item.group_name, value: item.group_name}))
set(props.nodeModel.properties.config, 'fields', fields)
editingGroupIndex.value = null
} catch (error) {
form_data.value.group_list[gIndex].group_name = tempGroupName.value
editingGroupIndex.value = null
if ([undefined, null].includes(index)) {
inputFieldList.value.push(data)
addGroup(data)
} else {
inputFieldList.value.splice(index, 1, data)
editGroupDesc(data, index)
}
GroupFieldDialogRef.value.close()
const fields = [
...inputFieldList.value.map((item) => ({ label: item.label, value: item.field })),
]
set(props.nodeModel.properties.config, 'fields', fields)
}
const editGroupDesc = (data: any, gIndex: any) => {
const c_group_list = cloneDeep(form_data.value.group_list)
c_group_list[gIndex].field = data.field
c_group_list[gIndex].label = data.label
form_data.value.group_list = c_group_list
}
const deleteGroup = (gIndex: number) => {
const c_group_list = cloneDeep(form_data.value.group_list)
c_group_list.splice(gIndex,1)
form_data.value.group_list = c_group_list
const fields = c_group_list.map((item:any) => ({ label: item.group_name, value: item.group_name}))
inputFieldList.value.splice(gIndex, 1)
const fields = c_group_list.map((item:any) => ({ label: item.label, value: item.field}))
set(props.nodeModel.properties.config, 'fields', fields)
}
@ -245,32 +231,22 @@ const deleteVariable = (gIndex: number,vIndex: number) => {
form_data.value.group_list = c_group_list
}
const addGroup = () => {
let group_number = form_data.value.group_list.length + 1
let group_name = `Group${group_number}`
while (form_data.value.group_list.some((item: any) => item.group_name === group_name)) {
group_number++
group_name = `Group${group_number}`
}
const addGroup = (data: any) => {
const c_group_list = cloneDeep(form_data.value.group_list)
c_group_list.push({
id: randomId(),
group_name: group_name,
field: data.field,
label: data.label,
variable_list: [{
v_id: randomId(),
variable: []
}]
})
form_data.value.group_list = c_group_list
const fields = c_group_list.map((item:any) => ({ label: item.group_name, value: item.group_name}))
set(props.nodeModel.properties.config, 'fields', fields)
}
const validate = async () => {
const validate_list = [
...nodeCascaderRef.value.map((item:any)=>item.validate()),
@ -288,7 +264,10 @@ onMounted(() => {
}
}
set(props.nodeModel, 'validate', validate)
const fields = form_data.value.group_list.map((item:any) => ({ label: item.group_name, value: item.group_name}))
if (props.nodeModel.properties.node_data.group_list) {
inputFieldList.value = form_data.value.group_list.map((item:any) => ({ label: item.label, field: item.field}))
}
const fields = form_data.value.group_list.map((item: any) => ({ label: item.label, value: item.field }))
set(props.nodeModel.properties.config, 'fields', fields)
})