Skip to content

Commit a85c36f

Browse files
authored
feat: Workflow form nodes support reference assignment (#3866) #2439
1 parent f780278 commit a85c36f

File tree

9 files changed

+301
-75
lines changed

9 files changed

+301
-75
lines changed

apps/application/flow/step_node/form_node/impl/base_form_node.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,19 @@
1717
from application.flow.step_node.form_node.i_form_node import IFormNode
1818

1919

20+
def get_default_option(option_list, _type, value_field):
21+
if option_list is not None and len(option_list) > 0:
22+
default_value_list = [o.get(value_field) for o in option_list if o.get('default')]
23+
if len(default_value_list) == 0:
24+
return option_list[0].get(value_field)
25+
else:
26+
if _type == 'MultiSelect':
27+
return default_value_list
28+
else:
29+
return default_value_list[0]
30+
return []
31+
32+
2033
def write_context(step_variable: Dict, global_variable: Dict, node, workflow):
2134
if step_variable is not None:
2235
for key in step_variable:
@@ -44,6 +57,28 @@ def save_context(self, details, workflow_manage):
4457
for key in form_data:
4558
self.context[key] = form_data[key]
4659

60+
def reset_field(self, field):
61+
if ['SingleSelect', 'MultiSelect', 'RadioCard'].__contains__(field.get('input_type')):
62+
if field.get('assignment_method') == 'ref_variables':
63+
option_list = self.workflow_manage.get_reference_field(field.get('option_list')[0],
64+
field.get('option_list')[1:])
65+
field['option_list'] = option_list
66+
field['default_value'] = get_default_option(option_list, field.get('input_type'),
67+
field.get('value_field'))
68+
69+
reset_field = ['field', 'label', 'default_value']
70+
for f in reset_field:
71+
_value = field[f]
72+
if isinstance(_value, str):
73+
field[f] = self.workflow_manage.generate_prompt(_value)
74+
else:
75+
_label_value = _value.get('label')
76+
_value['label'] = self.workflow_manage.generate_prompt(_label_value)
77+
tooltip = _value.get('attrs').get('tooltip')
78+
if tooltip is not None:
79+
_value.get('attrs')['tooltip'] = self.workflow_manage.generate_prompt(tooltip)
80+
return field
81+
4782
def execute(self, form_field_list, form_content_format, form_data, **kwargs) -> NodeResult:
4883
if form_data is not None:
4984
self.context['is_submit'] = True
@@ -52,6 +87,7 @@ def execute(self, form_field_list, form_content_format, form_data, **kwargs) ->
5287
self.context[key] = form_data.get(key)
5388
else:
5489
self.context['is_submit'] = False
90+
form_field_list = [self.reset_field(field) for field in form_field_list]
5591
form_setting = {"form_field_list": form_field_list, "runtime_node_id": self.runtime_node_id,
5692
"chat_record_id": self.flow_params_serializer.data.get("chat_record_id"),
5793
"is_submit": self.context.get("is_submit", False)}
@@ -60,6 +96,7 @@ def execute(self, form_field_list, form_content_format, form_data, **kwargs) ->
6096
form_content_format = self.workflow_manage.reset_prompt(form_content_format)
6197
prompt_template = PromptTemplate.from_template(form_content_format, template_format='jinja2')
6298
value = prompt_template.format(form=form, context=context)
99+
63100
return NodeResult(
64101
{'result': value, 'form_field_list': form_field_list, 'form_content_format': form_content_format}, {},
65102
_write_context=write_context)

ui/src/components/dynamics-form/constructor/items/MultiSelectConstructor.vue

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,28 @@
11
<template>
2-
<el-form-item>
2+
<el-form-item v-if="getModel">
3+
<template #label>
4+
<div class="flex-between">
5+
{{ $t('dynamicsForm.AssignmentMethod.label', '赋值方式') }}
6+
</div>
7+
</template>
8+
9+
<el-row style="width: 100%" :gutter="10">
10+
<el-radio-group v-model="formValue.assignment_method">
11+
<el-radio :value="item.value" size="large" v-for="item in assignment_method_option_list">{{
12+
item.label
13+
}}</el-radio>
14+
</el-radio-group>
15+
</el-row>
16+
</el-form-item>
17+
<NodeCascader
18+
v-if="formValue.assignment_method == 'ref_variables'"
19+
ref="nodeCascaderRef"
20+
:nodeModel="model"
21+
class="w-full"
22+
:placeholder="$t('views.applicationWorkflow.variable.placeholder')"
23+
v-model="formValue.option_list"
24+
/>
25+
<el-form-item v-if="formValue.assignment_method == 'custom'">
326
<template #label>
427
<div class="flex-between">
528
{{ $t('dynamicsForm.Select.label') }}
@@ -51,6 +74,7 @@
5174
</el-row>
5275
</el-form-item>
5376
<el-form-item
77+
v-if="formValue.assignment_method == 'custom'"
5478
class="defaultValueItem"
5579
:label="$t('dynamicsForm.default.label')"
5680
:required="formValue.required"
@@ -92,8 +116,34 @@
92116
</el-form-item>
93117
</template>
94118
<script setup lang="ts">
95-
import { computed, onMounted } from 'vue'
119+
import { computed, onMounted, inject } from 'vue'
120+
import NodeCascader from '@/workflow/common/NodeCascader.vue'
121+
import { t } from '@/locales'
122+
const getModel = inject('getModel') as any
123+
124+
const assignment_method_option_list = computed(() => {
125+
const option_list = [
126+
{
127+
label: t('dynamicsForm.AssignmentMethod.custom.label', '自定义'),
128+
value: 'custom',
129+
},
130+
]
131+
if (getModel) {
132+
option_list.push({
133+
label: t('dynamicsForm.AssignmentMethod.ref_variables.label', '引用变量'),
134+
value: 'ref_variables',
135+
})
136+
}
137+
return option_list
138+
})
96139
140+
const model = computed(() => {
141+
if (getModel) {
142+
return getModel()
143+
} else {
144+
return null
145+
}
146+
})
97147
const props = defineProps<{
98148
modelValue: any
99149
}>()
@@ -128,17 +178,20 @@ const getData = () => {
128178
text_field: 'label',
129179
value_field: 'value',
130180
option_list: formValue.value.option_list,
181+
assignment_method: formValue.value.assignment_method || 'custom',
131182
}
132183
}
133184
const rander = (form_data: any) => {
134185
formValue.value.option_list = form_data.option_list || []
135186
formValue.value.default_value = form_data.default_value
187+
formValue.value.assignment_method = form_data.assignment_method || 'custom'
136188
}
137189
138190
defineExpose({ getData, rander })
139191
onMounted(() => {
140192
formValue.value.option_list = []
141193
formValue.value.default_value = ''
194+
formValue.value.assignment_method = 'custom'
142195
if (formValue.value.show_default_value === undefined) {
143196
formValue.value.show_default_value = true
144197
}

ui/src/components/dynamics-form/constructor/items/RadioCardConstructor.vue

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,28 @@
11
<template>
2-
<el-form-item>
2+
<el-form-item v-if="getModel">
3+
<template #label>
4+
<div class="flex-between">
5+
{{ $t('dynamicsForm.AssignmentMethod.label', '赋值方式') }}
6+
</div>
7+
</template>
8+
9+
<el-row style="width: 100%" :gutter="10">
10+
<el-radio-group v-model="formValue.assignment_method">
11+
<el-radio :value="item.value" size="large" v-for="item in assignment_method_option_list">{{
12+
item.label
13+
}}</el-radio>
14+
</el-radio-group>
15+
</el-row>
16+
</el-form-item>
17+
<NodeCascader
18+
v-if="formValue.assignment_method == 'ref_variables'"
19+
ref="nodeCascaderRef"
20+
:nodeModel="model"
21+
class="w-full"
22+
:placeholder="$t('views.applicationWorkflow.variable.placeholder')"
23+
v-model="formValue.option_list"
24+
/>
25+
<el-form-item v-if="formValue.assignment_method === 'custom'">
326
<template #label>
427
<div class="flex-between">
528
{{ $t('dynamicsForm.Select.label') }}
@@ -51,7 +74,9 @@
5174
</el-col>
5275
</el-row>
5376
</el-form-item>
77+
5478
<el-form-item
79+
v-if="formValue.assignment_method === 'custom'"
5580
class="defaultValueItem"
5681
:label="$t('dynamicsForm.default.label')"
5782
:required="formValue.required"
@@ -83,8 +108,35 @@
83108
</el-form-item>
84109
</template>
85110
<script setup lang="ts">
86-
import { computed, onMounted } from 'vue'
111+
import { computed, onMounted, inject, ref } from 'vue'
87112
import RadioCard from '@/components/dynamics-form/items/radio/RadioCard.vue'
113+
import NodeCascader from '@/workflow/common/NodeCascader.vue'
114+
import { t } from '@/locales'
115+
const getModel = inject('getModel') as any
116+
117+
const assignment_method_option_list = computed(() => {
118+
const option_list = [
119+
{
120+
label: t('dynamicsForm.AssignmentMethod.custom.label', '自定义'),
121+
value: 'custom',
122+
},
123+
]
124+
if (getModel) {
125+
option_list.push({
126+
label: t('dynamicsForm.AssignmentMethod.ref_variables.label', '引用变量'),
127+
value: 'ref_variables',
128+
})
129+
}
130+
return option_list
131+
})
132+
133+
const model = computed(() => {
134+
if (getModel) {
135+
return getModel()
136+
} else {
137+
return null
138+
}
139+
})
88140
const props = defineProps<{
89141
modelValue: any
90142
}>()
@@ -121,17 +173,20 @@ const getData = () => {
121173
text_field: 'label',
122174
value_field: 'value',
123175
option_list: formValue.value.option_list,
176+
assignment_method: formValue.value.assignment_method || 'custom',
124177
}
125178
}
126179
const rander = (form_data: any) => {
127180
formValue.value.option_list = form_data.option_list || []
128181
formValue.value.default_value = form_data.default_value
182+
formValue.value.assignment_method = form_data.assignment_method || 'custom'
129183
}
130184
131185
defineExpose({ getData, rander })
132186
onMounted(() => {
133187
formValue.value.option_list = []
134188
formValue.value.default_value = ''
189+
formValue.value.assignment_method = 'custom'
135190
if (formValue.value.show_default_value === undefined) {
136191
formValue.value.show_default_value = true
137192
}

ui/src/components/dynamics-form/constructor/items/SingleSelectConstructor.vue

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,28 @@
11
<template>
2-
<el-form-item>
2+
<el-form-item v-if="getModel">
3+
<template #label>
4+
<div class="flex-between">
5+
{{ $t('dynamicsForm.AssignmentMethod.label', '赋值方式') }}
6+
</div>
7+
</template>
8+
9+
<el-row style="width: 100%" :gutter="10">
10+
<el-radio-group v-model="formValue.assignment_method">
11+
<el-radio :value="item.value" size="large" v-for="item in assignment_method_option_list">{{
12+
item.label
13+
}}</el-radio>
14+
</el-radio-group>
15+
</el-row>
16+
</el-form-item>
17+
<NodeCascader
18+
v-if="formValue.assignment_method == 'ref_variables'"
19+
ref="nodeCascaderRef"
20+
:nodeModel="model"
21+
class="w-full"
22+
:placeholder="$t('views.applicationWorkflow.variable.placeholder')"
23+
v-model="formValue.option_list"
24+
/>
25+
<el-form-item v-if="formValue.assignment_method == 'custom'">
326
<template #label>
427
<div class="flex-between">
528
{{ $t('dynamicsForm.Select.label') }}
@@ -52,6 +75,7 @@
5275
</el-row>
5376
</el-form-item>
5477
<el-form-item
78+
v-if="formValue.assignment_method == 'custom'"
5579
class="defaultValueItem"
5680
:required="formValue.required"
5781
prop="default_value"
@@ -85,8 +109,34 @@
85109
</el-form-item>
86110
</template>
87111
<script setup lang="ts">
88-
import { computed, onMounted } from 'vue'
112+
import { computed, onMounted, inject } from 'vue'
113+
import NodeCascader from '@/workflow/common/NodeCascader.vue'
114+
import { t } from '@/locales'
115+
const getModel = inject('getModel') as any
116+
117+
const assignment_method_option_list = computed(() => {
118+
const option_list = [
119+
{
120+
label: t('dynamicsForm.AssignmentMethod.custom.label', '自定义'),
121+
value: 'custom',
122+
},
123+
]
124+
if (getModel) {
125+
option_list.push({
126+
label: t('dynamicsForm.AssignmentMethod.ref_variables.label', '引用变量'),
127+
value: 'ref_variables',
128+
})
129+
}
130+
return option_list
131+
})
89132
133+
const model = computed(() => {
134+
if (getModel) {
135+
return getModel()
136+
} else {
137+
return null
138+
}
139+
})
90140
const props = defineProps<{
91141
modelValue: any
92142
}>()
@@ -121,18 +171,21 @@ const getData = () => {
121171
text_field: 'label',
122172
value_field: 'value',
123173
option_list: formValue.value.option_list,
174+
assignment_method: formValue.value.assignment_method || 'custom',
124175
}
125176
}
126177
const rander = (form_data: any) => {
127178
formValue.value.option_list = form_data.option_list || []
128179
formValue.value.default_value = form_data.default_value
129180
formValue.value.show_default_value = form_data.show_default_value
181+
formValue.value.assignment_method = form_data.assignment_method || 'custom'
130182
}
131183
132184
defineExpose({ getData, rander })
133185
onMounted(() => {
134186
formValue.value.option_list = []
135187
formValue.value.default_value = ''
188+
formValue.value.assignment_method = 'custom'
136189
if (formValue.value.show_default_value === undefined) {
137190
formValue.value.show_default_value = true
138191
}

ui/src/components/dynamics-form/items/radio/RadioCard.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010
style="--el-card-padding: 12px 16px"
1111
:class="[
1212
inputDisabled ? 'is-disabled' : '',
13-
modelValue == item[valueField] ? 'active' : ''
13+
modelValue == item[valueField] ? 'active' : '',
1414
]"
1515
@click="inputDisabled ? () => {} : selected(item[valueField])"
16+
:innerHTML="item[textField]"
1617
>
17-
{{ item[textField] }}
1818
</el-card>
1919
</el-col>
2020
</template>

0 commit comments

Comments
 (0)