feat: Group field dialog
parent
42d7aeb5bf
commit
2fc4a393ad
|
|
@ -17,7 +17,8 @@ class VariableListSerializer(serializers.Serializer):
|
||||||
|
|
||||||
class VariableGroupSerializer(serializers.Serializer):
|
class VariableGroupSerializer(serializers.Serializer):
|
||||||
id = serializers.CharField(required=True, label=_("Group id"))
|
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)
|
variable_list = VariableListSerializer(many=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ class BaseVariableAggregationNode(IVariableAggregation):
|
||||||
'variable_to_json': self.set_variable_to_json,
|
'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},{})
|
return NodeResult({'result': result,**result},{})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -39,11 +39,11 @@
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</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">
|
<el-card shadow="never" class="card-never" style="--el-card-padding: 12px">
|
||||||
|
|
||||||
<div class="flex-between mb-12">
|
<div class="flex-between mb-12">
|
||||||
<el-form-item
|
<!-- <el-form-item
|
||||||
v-if="editingGroupIndex === gIndex"
|
v-if="editingGroupIndex === gIndex"
|
||||||
:prop="`group_list.${gIndex}.group_name`"
|
:prop="`group_list.${gIndex}.group_name`"
|
||||||
:rules="groupNameRules(gIndex)"
|
:rules="groupNameRules(gIndex)"
|
||||||
|
|
@ -58,10 +58,10 @@
|
||||||
style="width: 200px; font-weight: bold;"
|
style="width: 200px; font-weight: bold;"
|
||||||
>
|
>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item> -->
|
||||||
<span v-else class="font-bold">{{ group_list.group_name }}</span>
|
<span class="font-bold">{{ group.field }}</span>
|
||||||
<div class="flex align-center">
|
<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-icon><EditPen /></el-icon>
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button @click="deleteGroup(gIndex)" size="large" link :disabled="form_data.group_list.length <= 1">
|
<el-button @click="deleteGroup(gIndex)" size="large" link :disabled="form_data.group_list.length <= 1">
|
||||||
|
|
@ -70,7 +70,7 @@
|
||||||
</div>
|
</div>
|
||||||
</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-row :gutter="8">
|
||||||
<el-col :span="21">
|
<el-col :span="21">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
|
|
@ -96,7 +96,7 @@
|
||||||
link
|
link
|
||||||
size="large"
|
size="large"
|
||||||
class="mt-4"
|
class="mt-4"
|
||||||
:disabled="group_list.variable_list.length <= 1"
|
:disabled="group.variable_list.length <= 1"
|
||||||
@click="deleteVariable(gIndex, vIndex)"
|
@click="deleteVariable(gIndex, vIndex)"
|
||||||
>
|
>
|
||||||
<AppIcon iconName="app-delete"></AppIcon>
|
<AppIcon iconName="app-delete"></AppIcon>
|
||||||
|
|
@ -112,36 +112,37 @@
|
||||||
|
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</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"/>
|
<AppIcon iconName="app-add-outlined" class="mr-4"/>
|
||||||
{{ $t('views.applicationWorkflow.nodes.variableAggregationNode.add') }}
|
{{ $t('views.applicationWorkflow.nodes.variableAggregationNode.add') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
<GroupFieldDialog ref="GroupFieldDialogRef" @refresh="refreshFieldList"></GroupFieldDialog>
|
||||||
</NodeContainer>
|
</NodeContainer>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { set, cloneDeep, debounce } from 'lodash'
|
import { set, cloneDeep } from 'lodash'
|
||||||
import NodeCascader from '@/workflow/common/NodeCascader.vue'
|
import NodeCascader from '@/workflow/common/NodeCascader.vue'
|
||||||
import NodeContainer from '@/workflow/common/NodeContainer.vue'
|
import NodeContainer from '@/workflow/common/NodeContainer.vue'
|
||||||
|
import GroupFieldDialog from './component/GroupFieldDialog.vue'
|
||||||
import { ref, computed, onMounted, nextTick } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
import { isLastNode } from '@/workflow/common/data'
|
import { isLastNode } from '@/workflow/common/data'
|
||||||
import { t } from '@/locales'
|
import { t } from '@/locales'
|
||||||
import { randomId } from '@/utils/common'
|
import { randomId } from '@/utils/common'
|
||||||
|
import { MsgError } from '@/utils/message'
|
||||||
|
|
||||||
const props = defineProps<{ nodeModel: any }>()
|
const props = defineProps<{ nodeModel: any }>()
|
||||||
const VariableAggregationRef = ref()
|
const VariableAggregationRef = ref()
|
||||||
const nodeCascaderRef = ref()
|
const nodeCascaderRef = ref()
|
||||||
const editingGroupIndex = ref<number | null>(null)
|
const GroupFieldDialogRef = ref()
|
||||||
const groupNameInputRef = ref()
|
|
||||||
|
|
||||||
|
|
||||||
const form = {
|
const form = {
|
||||||
strategy: 'first_non_null',
|
strategy: 'first_non_null',
|
||||||
group_list: [
|
group_list: [
|
||||||
{
|
{
|
||||||
id: randomId(),
|
id: randomId(),
|
||||||
group_name: 'Group1',
|
label: 'Group1',
|
||||||
|
field: 'Group1',
|
||||||
variable_list: [
|
variable_list: [
|
||||||
{
|
{
|
||||||
v_id: randomId(),
|
v_id: randomId(),
|
||||||
|
|
@ -165,68 +166,53 @@ const form_data = computed({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const isGroupNameValid = ref<boolean>(true)
|
const inputFieldList = ref<any[]>([])
|
||||||
const groupNameErrMsg = ref('')
|
|
||||||
const tempGroupName = ref('')
|
|
||||||
|
|
||||||
const editGroupName = async (gIndex: number) => {
|
function openAddOrEditDialog(group?: any, index?: any) {
|
||||||
editingGroupIndex.value = gIndex
|
let data = null
|
||||||
tempGroupName.value = form_data.value.group_list[gIndex].group_name
|
if (group && index !== undefined) {
|
||||||
isGroupNameValid.value = true
|
data = {
|
||||||
groupNameErrMsg.value = ''
|
field: group.field,
|
||||||
await nextTick()
|
label: group.label,
|
||||||
if (groupNameInputRef.value) {
|
|
||||||
groupNameInputRef.value.focus()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GroupFieldDialogRef.value.open(data,index)
|
||||||
|
}
|
||||||
|
|
||||||
const groupNameRules = (gIndex: number) => [
|
function refreshFieldList(data: any, index: any) {
|
||||||
{
|
for (let i = 0; i < inputFieldList.value.length; i++) {
|
||||||
required: true,
|
if (inputFieldList.value[i].field === data.field && index !== i) {
|
||||||
message: t('views.applicationWorkflow.nodes.variableAggregationNode.group.noneError'),
|
MsgError(t('views.applicationWorkflow.tip.paramErrorMessage') + data.field)
|
||||||
trigger: 'blur'
|
return
|
||||||
},
|
}
|
||||||
{
|
}
|
||||||
validator: (rule: any, value: string, callback: any) => {
|
if ([undefined, null].includes(index)) {
|
||||||
const trimmedValue = value?.trim() || ''
|
inputFieldList.value.push(data)
|
||||||
|
addGroup(data)
|
||||||
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 {
|
} else {
|
||||||
callback()
|
inputFieldList.value.splice(index, 1, data)
|
||||||
}
|
editGroupDesc(data, index)
|
||||||
},
|
|
||||||
trigger: 'change' // 实时触发
|
|
||||||
}
|
}
|
||||||
|
GroupFieldDialogRef.value.close()
|
||||||
|
const fields = [
|
||||||
|
...inputFieldList.value.map((item) => ({ label: item.label, value: item.field })),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
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)
|
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 deleteGroup = (gIndex: number) => {
|
||||||
const c_group_list = cloneDeep(form_data.value.group_list)
|
const c_group_list = cloneDeep(form_data.value.group_list)
|
||||||
c_group_list.splice(gIndex,1)
|
c_group_list.splice(gIndex,1)
|
||||||
form_data.value.group_list = c_group_list
|
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)
|
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
|
form_data.value.group_list = c_group_list
|
||||||
}
|
}
|
||||||
|
|
||||||
const addGroup = () => {
|
const addGroup = (data: any) => {
|
||||||
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 c_group_list = cloneDeep(form_data.value.group_list)
|
const c_group_list = cloneDeep(form_data.value.group_list)
|
||||||
c_group_list.push({
|
c_group_list.push({
|
||||||
id: randomId(),
|
id: randomId(),
|
||||||
group_name: group_name,
|
field: data.field,
|
||||||
|
label: data.label,
|
||||||
variable_list: [{
|
variable_list: [{
|
||||||
v_id: randomId(),
|
v_id: randomId(),
|
||||||
variable: []
|
variable: []
|
||||||
}]
|
}]
|
||||||
})
|
})
|
||||||
form_data.value.group_list = c_group_list
|
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 = async () => {
|
||||||
const validate_list = [
|
const validate_list = [
|
||||||
...nodeCascaderRef.value.map((item:any)=>item.validate()),
|
...nodeCascaderRef.value.map((item:any)=>item.validate()),
|
||||||
|
|
@ -288,7 +264,10 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set(props.nodeModel, 'validate', validate)
|
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)
|
set(props.nodeModel.properties.config, 'fields', fields)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue