Skip to content

Commit b2494a4

Browse files
committed
feat: Group field dialog
1 parent 42d7aeb commit b2494a4

File tree

4 files changed

+179
-81
lines changed

4 files changed

+179
-81
lines changed

apps/application/flow/step_node/variable_aggregation_node/i_variable_aggregation_node.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ class VariableListSerializer(serializers.Serializer):
1717

1818
class VariableGroupSerializer(serializers.Serializer):
1919
id = serializers.CharField(required=True, label=_("Group id"))
20-
group_name = serializers.CharField(required=True, label=_("group_name"))
20+
field = serializers.CharField(required=True, label=_("group_name"))
21+
label = serializers.CharField(required=True)
2122
variable_list = VariableListSerializer(many=True)
2223

2324

apps/application/flow/step_node/variable_aggregation_node/impl/base_variable_aggregation_node.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def execute(self,strategy,group_list,**kwargs) -> NodeResult:
3838
'variable_to_json': self.set_variable_to_json,
3939
}
4040

41-
result = { item.get('group_name'):strategy_map[strategy](item.get('variable_list')) for item in group_list}
41+
result = { item.get('field'):strategy_map[strategy](item.get('variable_list')) for item in group_list}
4242

4343
return NodeResult({'result': result,**result},{})
4444

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<template>
2+
<el-dialog
3+
:title="isEdit ? $t('common.param.editParam') : $t('common.param.addParam')"
4+
v-model="dialogVisible"
5+
:close-on-click-modal="false"
6+
:close-on-press-escape="false"
7+
:destroy-on-close="true"
8+
:before-close="close"
9+
append-to-body
10+
>
11+
<el-form
12+
label-position="top"
13+
ref="fieldFormRef"
14+
:rules="rules"
15+
:model="form"
16+
require-asterisk-position="right"
17+
>
18+
<el-form-item
19+
:label="$t('dynamicsForm.paramForm.field.label')"
20+
:required="true"
21+
prop="field"
22+
:rules="rules.field"
23+
>
24+
<el-input
25+
v-model="form.field"
26+
:maxlength="64"
27+
:placeholder="$t('dynamicsForm.paramForm.field.placeholder')"
28+
show-word-limit
29+
/>
30+
</el-form-item>
31+
<el-form-item
32+
:label="$t('dynamicsForm.paramForm.name.label')"
33+
:required="true"
34+
prop="label"
35+
:rules="rules.label"
36+
>
37+
<el-input
38+
v-model="form.label"
39+
:maxlength="64"
40+
show-word-limit
41+
:placeholder="$t('dynamicsForm.paramForm.name.placeholder')"
42+
/>
43+
</el-form-item>
44+
</el-form>
45+
<template #footer>
46+
<span class="dialog-footer">
47+
<el-button @click.prevent="close"> {{ $t('common.cancel') }} </el-button>
48+
<el-button type="primary" @click="submit(fieldFormRef)" :loading="loading">
49+
{{ isEdit ? $t('common.save') : $t('common.add') }}
50+
</el-button>
51+
</span>
52+
</template>
53+
</el-dialog>
54+
</template>
55+
<script setup lang="ts">
56+
import { reactive, ref } from 'vue'
57+
import type { FormInstance } from 'element-plus'
58+
import { cloneDeep } from 'lodash'
59+
import { t } from '@/locales'
60+
const emit = defineEmits(['refresh'])
61+
62+
const fieldFormRef = ref()
63+
const loading = ref<boolean>(false)
64+
const isEdit = ref(false)
65+
const currentIndex = ref(null)
66+
const form = ref<any>({
67+
field: '',
68+
label: '',
69+
})
70+
71+
const rules = reactive({
72+
label: [
73+
{ required: true, message: t('dynamicsForm.paramForm.name.requiredMessage'), trigger: 'blur' },
74+
],
75+
field: [
76+
{ required: true, message: t('dynamicsForm.paramForm.field.requiredMessage'), trigger: 'blur' },
77+
{
78+
pattern: /^[a-zA-Z0-9_]+$/,
79+
message: t('dynamicsForm.paramForm.field.requiredMessage2'),
80+
trigger: 'blur',
81+
},
82+
],
83+
})
84+
85+
const dialogVisible = ref<boolean>(false)
86+
87+
const open = (data: any, index?: any) => {
88+
if (data) {
89+
form.value = cloneDeep(data)
90+
isEdit.value = true
91+
currentIndex.value = index
92+
}
93+
94+
dialogVisible.value = true
95+
}
96+
97+
const close = () => {
98+
dialogVisible.value = false
99+
isEdit.value = false
100+
currentIndex.value = null
101+
form.value = {
102+
field: '',
103+
label: '',
104+
}
105+
}
106+
107+
const submit = async (formEl: FormInstance | undefined) => {
108+
if (!formEl) return
109+
await formEl.validate((valid) => {
110+
if (valid) {
111+
emit('refresh', form.value, currentIndex.value)
112+
}
113+
})
114+
}
115+
116+
defineExpose({ open, close })
117+
</script>
118+
<style lang="scss" scoped></style>

ui/src/workflow/nodes/variable-aggregation-node/index.vue

Lines changed: 58 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@
3939
/>
4040
</el-select>
4141
</el-form-item>
42-
<div v-for="(group_list, gIndex) in form_data.group_list" :key="group_list.id" class="mb-8">
42+
<div v-for="(group, gIndex) in form_data.group_list" :key="group.id" class="mb-8">
4343
<el-card shadow="never" class="card-never" style="--el-card-padding: 12px">
4444

4545
<div class="flex-between mb-12">
46-
<el-form-item
46+
<!-- <el-form-item
4747
v-if="editingGroupIndex === gIndex"
4848
:prop="`group_list.${gIndex}.group_name`"
4949
:rules="groupNameRules(gIndex)"
@@ -58,10 +58,10 @@
5858
style="width: 200px; font-weight: bold;"
5959
>
6060
</el-input>
61-
</el-form-item>
62-
<span v-else class="font-bold">{{ group_list.group_name }}</span>
61+
</el-form-item> -->
62+
<span class="font-bold">{{ group.field }}</span>
6363
<div class="flex align-center">
64-
<el-button @click="editGroupName(gIndex)" size="large" link>
64+
<el-button @click="openAddOrEditDialog(group,gIndex)" size="large" link>
6565
<el-icon><EditPen /></el-icon>
6666
</el-button>
6767
<el-button @click="deleteGroup(gIndex)" size="large" link :disabled="form_data.group_list.length <= 1">
@@ -70,7 +70,7 @@
7070
</div>
7171
</div>
7272

73-
<div v-for="(item, vIndex) in group_list.variable_list" :key="item.v_id" class="mb-4">
73+
<div v-for="(item, vIndex) in group.variable_list" :key="item.v_id" class="mb-4">
7474
<el-row :gutter="8">
7575
<el-col :span="21">
7676
<el-form-item
@@ -96,7 +96,7 @@
9696
link
9797
size="large"
9898
class="mt-4"
99-
:disabled="group_list.variable_list.length <= 1"
99+
:disabled="group.variable_list.length <= 1"
100100
@click="deleteVariable(gIndex, vIndex)"
101101
>
102102
<AppIcon iconName="app-delete"></AppIcon>
@@ -112,36 +112,37 @@
112112

113113
</el-card>
114114
</div>
115-
<el-button @click="addGroup" type="primary" size="large" link>
115+
<el-button @click="openAddOrEditDialog()" type="primary" size="large" link>
116116
<AppIcon iconName="app-add-outlined" class="mr-4"/>
117117
{{ $t('views.applicationWorkflow.nodes.variableAggregationNode.add') }}
118118
</el-button>
119119
</el-form>
120+
<GroupFieldDialog ref="GroupFieldDialogRef" @refresh="refreshFieldList"></GroupFieldDialog>
120121
</NodeContainer>
121122
</template>
122123
<script setup lang="ts">
123-
import { set, cloneDeep, debounce } from 'lodash'
124+
import { set, cloneDeep } from 'lodash'
124125
import NodeCascader from '@/workflow/common/NodeCascader.vue'
125126
import NodeContainer from '@/workflow/common/NodeContainer.vue'
126-
127-
import { ref, computed, onMounted, nextTick } from 'vue'
127+
import GroupFieldDialog from './component/GroupFieldDialog.vue'
128+
import { ref, computed, onMounted } from 'vue'
128129
import { isLastNode } from '@/workflow/common/data'
129130
import { t } from '@/locales'
130131
import { randomId } from '@/utils/common'
132+
import { MsgError } from '@/utils/message'
131133
132134
const props = defineProps<{ nodeModel: any }>()
133135
const VariableAggregationRef = ref()
134136
const nodeCascaderRef = ref()
135-
const editingGroupIndex = ref<number | null>(null)
136-
const groupNameInputRef = ref()
137-
137+
const GroupFieldDialogRef = ref()
138138
139139
const form = {
140140
strategy: 'first_non_null',
141141
group_list: [
142142
{
143143
id: randomId(),
144-
group_name: 'Group1',
144+
label: 'Group1',
145+
field: 'Group1',
145146
variable_list: [
146147
{
147148
v_id: randomId(),
@@ -165,68 +166,53 @@ const form_data = computed({
165166
}
166167
})
167168
168-
const isGroupNameValid = ref<boolean>(true)
169-
const groupNameErrMsg = ref('')
170-
const tempGroupName = ref('')
169+
const inputFieldList = ref<any[]>([])
171170
172-
const editGroupName = async (gIndex: number) => {
173-
editingGroupIndex.value = gIndex
174-
tempGroupName.value = form_data.value.group_list[gIndex].group_name
175-
isGroupNameValid.value = true
176-
groupNameErrMsg.value = ''
177-
await nextTick()
178-
if (groupNameInputRef.value) {
179-
groupNameInputRef.value.focus()
171+
function openAddOrEditDialog(group?: any, index?: any) {
172+
let data = null
173+
if (group && index !== undefined) {
174+
data = {
175+
field: group.field,
176+
label: group.label,
177+
}
180178
}
179+
GroupFieldDialogRef.value.open(data,index)
181180
}
182181
183-
const groupNameRules = (gIndex: number) => [
184-
{
185-
required: true,
186-
message: t('views.applicationWorkflow.nodes.variableAggregationNode.group.noneError'),
187-
trigger: 'blur'
188-
},
189-
{
190-
validator: (rule: any, value: string, callback: any) => {
191-
const trimmedValue = value?.trim() || ''
192-
193-
const hasDuplicate = form_data.value.group_list.some((item: any, index: number) =>
194-
index !== gIndex && item.group_name.trim() === trimmedValue
195-
)
196-
197-
if (hasDuplicate) {
198-
callback(new Error(t('views.applicationWorkflow.nodes.variableAggregationNode.group.dupError')))
199-
} else {
200-
callback()
201-
}
202-
},
203-
trigger: 'change' // 实时触发
182+
function refreshFieldList(data: any, index: any) {
183+
for (let i = 0; i < inputFieldList.value.length; i++) {
184+
if (inputFieldList.value[i].field === data.field && index !== i) {
185+
MsgError(t('views.applicationWorkflow.tip.paramErrorMessage') + data.field)
186+
return
187+
}
204188
}
205-
]
206-
207-
208-
const validateGroupNameField = debounce((gIndex: number) => {
209-
VariableAggregationRef.value?.validateField(`group_list.${gIndex}.group_name`)
210-
}, 500)
211-
212-
const finishEditGroupName = async (gIndex: number) => {
213-
try {
214-
await VariableAggregationRef.value?.validateField(`group_list.${gIndex}.group_name`)
215-
const c_group_list = cloneDeep(form_data.value.group_list)
216-
const fields = c_group_list.map((item:any) => ({ label: item.group_name, value: item.group_name}))
217-
set(props.nodeModel.properties.config, 'fields', fields)
218-
editingGroupIndex.value = null
219-
} catch (error) {
220-
form_data.value.group_list[gIndex].group_name = tempGroupName.value
221-
editingGroupIndex.value = null
189+
if ([undefined, null].includes(index)) {
190+
inputFieldList.value.push(data)
191+
addGroup(data)
192+
} else {
193+
inputFieldList.value.splice(index, 1, data)
194+
editGroupDesc(data, index)
222195
}
196+
GroupFieldDialogRef.value.close()
197+
const fields = [
198+
...inputFieldList.value.map((item) => ({ label: item.label, value: item.field })),
199+
]
200+
set(props.nodeModel.properties.config, 'fields', fields)
201+
}
202+
203+
const editGroupDesc = (data: any, gIndex: any) => {
204+
const c_group_list = cloneDeep(form_data.value.group_list)
205+
c_group_list[gIndex].field = data.field
206+
c_group_list[gIndex].label = data.label
207+
form_data.value.group_list = c_group_list
223208
}
224209
225210
const deleteGroup = (gIndex: number) => {
226211
const c_group_list = cloneDeep(form_data.value.group_list)
227212
c_group_list.splice(gIndex,1)
228213
form_data.value.group_list = c_group_list
229-
const fields = c_group_list.map((item:any) => ({ label: item.group_name, value: item.group_name}))
214+
inputFieldList.value.splice(gIndex, 1)
215+
const fields = c_group_list.map((item:any) => ({ label: item.label, value: item.field}))
230216
set(props.nodeModel.properties.config, 'fields', fields)
231217
}
232218
@@ -245,32 +231,22 @@ const deleteVariable = (gIndex: number,vIndex: number) => {
245231
form_data.value.group_list = c_group_list
246232
}
247233
248-
const addGroup = () => {
249-
let group_number = form_data.value.group_list.length + 1
250-
let group_name = `Group${group_number}`
251-
252-
while (form_data.value.group_list.some((item: any) => item.group_name === group_name)) {
253-
group_number++
254-
group_name = `Group${group_number}`
255-
}
256-
234+
const addGroup = (data: any) => {
257235
const c_group_list = cloneDeep(form_data.value.group_list)
258236
c_group_list.push({
259237
id: randomId(),
260-
group_name: group_name,
238+
field: data.field,
239+
label: data.label,
261240
variable_list: [{
262241
v_id: randomId(),
263242
variable: []
264243
}]
265244
})
266245
form_data.value.group_list = c_group_list
267-
const fields = c_group_list.map((item:any) => ({ label: item.group_name, value: item.group_name}))
268-
set(props.nodeModel.properties.config, 'fields', fields)
269246
}
270247
271248
272249
273-
274250
const validate = async () => {
275251
const validate_list = [
276252
...nodeCascaderRef.value.map((item:any)=>item.validate()),
@@ -288,7 +264,10 @@ onMounted(() => {
288264
}
289265
}
290266
set(props.nodeModel, 'validate', validate)
291-
const fields = form_data.value.group_list.map((item:any) => ({ label: item.group_name, value: item.group_name}))
267+
if (props.nodeModel.properties.node_data.group_list) {
268+
inputFieldList.value = form_data.value.group_list.map((item:any) => ({ label: item.label, field: item.field}))
269+
}
270+
const fields = form_data.value.group_list.map((item: any) => ({ label: item.label, value: item.field }))
292271
set(props.nodeModel.properties.config, 'fields', fields)
293272
})
294273

0 commit comments

Comments
 (0)