Skip to content

Commit d268835

Browse files
authored
feat: Form nodes support file upload and multi-line text (#3879)
1 parent 31d71d1 commit d268835

File tree

14 files changed

+736
-50
lines changed

14 files changed

+736
-50
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,11 @@ def reset_field(self, field):
6969
reset_field = ['field', 'label', 'default_value']
7070
for f in reset_field:
7171
_value = field[f]
72+
if _value is None:
73+
continue
7274
if isinstance(_value, str):
7375
field[f] = self.workflow_manage.generate_prompt(_value)
74-
else:
76+
elif f == 'label':
7577
_label_value = _value.get('label')
7678
_value['label'] = self.workflow_manage.generate_prompt(_label_value)
7779
tooltip = _value.get('attrs').get('tooltip')

ui/src/components/ai-chat/index.vue

Lines changed: 98 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,92 @@
11
<template>
2-
<div ref="aiChatRef" class="ai-chat" :class="type" :style="{
3-
height: firsUserInput ? '100%' : undefined,
4-
paddingBottom: applicationDetails.disclaimer ? '20px' : 0,
5-
}">
6-
<div v-show="showUserInputContent" :class="firsUserInput ? 'firstUserInput' : 'popperUserInput'">
7-
<UserForm v-model:api_form_data="api_form_data" v-model:form_data="form_data" :application="applicationDetails"
8-
:type="type" :first="firsUserInput" @confirm="UserFormConfirm" @cancel="UserFormCancel" ref="userFormRef">
2+
<div
3+
ref="aiChatRef"
4+
class="ai-chat"
5+
:class="type"
6+
:style="{
7+
height: firsUserInput ? '100%' : undefined,
8+
paddingBottom: applicationDetails.disclaimer ? '20px' : 0,
9+
}"
10+
>
11+
<div
12+
v-show="showUserInputContent"
13+
:class="firsUserInput ? 'firstUserInput' : 'popperUserInput'"
14+
>
15+
<UserForm
16+
v-model:api_form_data="api_form_data"
17+
v-model:form_data="form_data"
18+
:application="applicationDetails"
19+
:type="type"
20+
:first="firsUserInput"
21+
@confirm="UserFormConfirm"
22+
@cancel="UserFormCancel"
23+
ref="userFormRef"
24+
>
925
</UserForm>
1026
</div>
1127
<template v-if="!(isUserInput || isAPIInput) || !firsUserInput || type === 'log'">
1228
<el-scrollbar ref="scrollDiv" @scroll="handleScrollTop">
1329
<div ref="dialogScrollbar" class="ai-chat__content p-16">
14-
<PrologueContent :type="type" :application="applicationDetails" :available="available"
15-
:send-message="sendMessage"></PrologueContent>
30+
<PrologueContent
31+
:type="type"
32+
:application="applicationDetails"
33+
:available="available"
34+
:send-message="sendMessage"
35+
></PrologueContent>
1636

1737
<template v-for="(item, index) in chatList" :key="index">
1838
<!-- 问题 -->
19-
<QuestionContent :type="type" :application="applicationDetails" :chat-record="item"></QuestionContent>
39+
<QuestionContent
40+
:type="type"
41+
:application="applicationDetails"
42+
:chat-record="item"
43+
></QuestionContent>
2044
<!-- 回答 -->
21-
<AnswerContent :application="applicationDetails" :loading="loading" v-model:chat-record="chatList[index]"
22-
:type="type" :send-message="sendMessage" :chat-management="ChatManagement"
45+
<AnswerContent
46+
:application="applicationDetails"
47+
:loading="loading"
48+
v-model:chat-record="chatList[index]"
49+
:type="type"
50+
:send-message="sendMessage"
51+
:chat-management="ChatManagement"
2352
:executionIsRightPanel="props.executionIsRightPanel"
2453
@open-execution-detail="emit('openExecutionDetail', chatList[index])"
2554
@openParagraph="emit('openParagraph', chatList[index])"
2655
@openParagraphDocument="
2756
(val: any) => emit('openParagraphDocument', chatList[index], val)
28-
"></AnswerContent>
57+
"
58+
></AnswerContent>
2959
</template>
30-
<TransitionContent v-if="transcribing" :text="t('chat.transcribing')" :type="type"
31-
:application="applicationDetails">
60+
<TransitionContent
61+
v-if="transcribing"
62+
:text="t('chat.transcribing')"
63+
:type="type"
64+
:application="applicationDetails"
65+
>
3266
</TransitionContent>
3367
</div>
3468
</el-scrollbar>
3569

36-
<ChatInputOperate :app-id="appId" :application-details="applicationDetails" :is-mobile="isMobile" :type="type"
37-
:send-message="sendMessage" :open-chat-id="openChatId" :validate="validate" :chat-management="ChatManagement"
38-
v-model:chat-id="chartOpenId" v-model:loading="loading" v-model:show-user-input="showUserInput"
39-
v-if="type !== 'log'">
70+
<ChatInputOperate
71+
:app-id="appId"
72+
:application-details="applicationDetails"
73+
:is-mobile="isMobile"
74+
:type="type"
75+
:send-message="sendMessage"
76+
:open-chat-id="openChatId"
77+
:validate="validate"
78+
:chat-management="ChatManagement"
79+
v-model:chat-id="chartOpenId"
80+
v-model:loading="loading"
81+
v-model:show-user-input="showUserInput"
82+
v-if="type !== 'log'"
83+
>
4084
<template #userInput>
41-
<el-button v-if="isUserInput || isAPIInput" class="user-input-button mb-8" @click="toggleUserInput">
85+
<el-button
86+
v-if="isUserInput || isAPIInput"
87+
class="user-input-button mb-8"
88+
@click="toggleUserInput"
89+
>
4290
<AppIcon iconName="app-edit" :size="16" class="mr-4"></AppIcon>
4391
<span class="ellipsis">
4492
{{ userInputTitle || $t('chat.userInput') }}
@@ -52,11 +100,21 @@
52100
</div>
53101
</template>
54102
<script setup lang="ts">
55-
import { type Ref, ref, nextTick, computed, watch, reactive, onMounted, onBeforeUnmount } from 'vue'
103+
import {
104+
type Ref,
105+
ref,
106+
nextTick,
107+
computed,
108+
watch,
109+
reactive,
110+
onMounted,
111+
onBeforeUnmount,
112+
provide,
113+
} from 'vue'
56114
import { useRoute } from 'vue-router'
57115
import applicationApi from '@/api/application/application'
58116
import chatAPI from '@/api/chat/chat'
59-
import SystemResourceManagementApplicationAPI from "@/api/system-resource-management/application.ts"
117+
import SystemResourceManagementApplicationAPI from '@/api/system-resource-management/application.ts'
60118
import syetrmResourceManagementChatLogApi from '@/api/system-resource-management/chat-log'
61119
import chatLogApi from '@/api/application/chat-log'
62120
import { ChatManagement, type chatType } from '@/api/type/application'
@@ -72,6 +130,11 @@ import UserForm from '@/components/ai-chat/component/user-form/index.vue'
72130
import Control from '@/components/ai-chat/component/control/index.vue'
73131
import { t } from '@/locales'
74132
import bus from '@/bus'
133+
provide('upload', (file: any, loading?: Ref<boolean>) => {
134+
return props.type === 'debug-ai-chat'
135+
? applicationApi.postUploadFile(file, 'TEMPORARY_120_MINUTE', 'TEMPORARY_120_MINUTE', loading)
136+
: chatAPI.postUploadFile(file, chartOpenId.value, 'CHAT', loading)
137+
})
75138
const transcribing = ref<boolean>(false)
76139
defineOptions({ name: 'AiChat' })
77140
const route = useRoute()
@@ -301,17 +364,25 @@ const getChatRecordDetailsAPI = (row: any) => {
301364
if (row.record_id) {
302365
if (props.type === 'debug-ai-chat') {
303366
if (route.path.includes('resource-management')) {
304-
return syetrmResourceManagementChatLogApi
305-
.getChatRecordDetails(id || props.appId, row.chat_id, row.record_id, loading)
367+
return syetrmResourceManagementChatLogApi.getChatRecordDetails(
368+
id || props.appId,
369+
row.chat_id,
370+
row.record_id,
371+
loading,
372+
)
306373
} else {
307-
return chatLogApi
308-
.getChatRecordDetails(id || props.appId, row.chat_id, row.record_id, loading)
374+
return chatLogApi.getChatRecordDetails(
375+
id || props.appId,
376+
row.chat_id,
377+
row.record_id,
378+
loading,
379+
)
309380
}
310381
} else {
311382
return chatAPI.getChatRecord(row.chat_id, row.record_id, loading)
312383
}
313384
}
314-
return Promise.reject("404")
385+
return Promise.reject('404')
315386
}
316387
/**
317388
* 获取对话详情
@@ -326,7 +397,6 @@ function getSourceDetail(row: any) {
326397
}
327398
})
328399
})
329-
330400
}
331401
/**
332402
* 对话

ui/src/components/dynamics-form/constructor/data.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,51 @@ import { t } from '@/locales'
22
const input_type_list = [
33
{
44
label: t('dynamicsForm.input_type_list.TextInput'),
5-
value: 'TextInput'
5+
value: 'TextInput',
66
},
77
{
88
label: t('dynamicsForm.input_type_list.PasswordInput'),
9-
value: 'PasswordInput'
9+
value: 'PasswordInput',
1010
},
1111
{
1212
label: t('dynamicsForm.input_type_list.Slider'),
13-
value: 'Slider'
13+
value: 'Slider',
1414
},
1515
{
1616
label: t('dynamicsForm.input_type_list.SwitchInput'),
17-
value: 'SwitchInput'
17+
value: 'SwitchInput',
1818
},
1919
{
2020
label: t('dynamicsForm.input_type_list.SingleSelect'),
21-
value: 'SingleSelect'
21+
value: 'SingleSelect',
2222
},
2323
{
2424
label: t('dynamicsForm.input_type_list.MultiSelect'),
25-
value: 'MultiSelect'
25+
value: 'MultiSelect',
2626
},
2727
{
2828
label: t('dynamicsForm.input_type_list.DatePicker'),
29-
value: 'DatePicker'
29+
value: 'DatePicker',
3030
},
3131
{
3232
label: t('dynamicsForm.input_type_list.JsonInput'),
33-
value: 'JsonInput'
33+
value: 'JsonInput',
3434
},
3535
{
3636
label: t('dynamicsForm.input_type_list.RadioCard'),
37-
value: 'RadioCard'
37+
value: 'RadioCard',
3838
},
3939
{
4040
label: t('dynamicsForm.input_type_list.RadioRow'),
41-
value: 'RadioRow'
42-
}
41+
value: 'RadioRow',
42+
},
43+
{
44+
label: t('dynamicsForm.input_type_list.UploadInput'),
45+
value: 'UploadInput',
46+
},
47+
{
48+
label: t('dynamicsForm.input_type_list.TextareaInput'),
49+
value: 'TextareaInput',
50+
},
4351
]
4452
export { input_type_list }

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

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,32 @@
88

99
<el-row style="width: 100%" :gutter="10">
1010
<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>
11+
<el-radio :value="item.value" size="large" v-for="item in assignment_method_option_list"
12+
>{{ item.label }}
13+
<el-popover
14+
width="300px"
15+
v-if="item.value == 'ref_variables'"
16+
class="box-item"
17+
placement="top-start"
18+
>
19+
{{ $t('dynamicsForm.AssignmentMethod.ref_variables.popover') }}:<br />
20+
[<br />
21+
{<br />
22+
"label": "xx",<br />
23+
"value": "xx",<br />
24+
"default": false<br />
25+
}<br />
26+
]<br />
27+
label: {{ $t('dynamicsForm.AssignmentMethod.ref_variables.popover_label') }}
28+
{{ $t('common.required') }}<br />
29+
value: {{ $t('dynamicsForm.AssignmentMethod.ref_variables.popover_value') }}
30+
{{ $t('common.required') }}<br />
31+
default: {{ $t('dynamicsForm.AssignmentMethod.ref_variables.popover_default') }}
32+
<template #reference>
33+
<el-icon><InfoFilled /></el-icon>
34+
</template>
35+
</el-popover>
36+
</el-radio>
1437
</el-radio-group>
1538
</el-row>
1639
</el-form-item>

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

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,32 @@
88

99
<el-row style="width: 100%" :gutter="10">
1010
<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>
11+
<el-radio :value="item.value" size="large" v-for="item in assignment_method_option_list"
12+
>{{ item.label }}
13+
<el-popover
14+
width="300px"
15+
v-if="item.value == 'ref_variables'"
16+
class="box-item"
17+
placement="top-start"
18+
>
19+
{{ $t('dynamicsForm.AssignmentMethod.ref_variables.popover') }}:<br />
20+
[<br />
21+
{<br />
22+
"label": "xx",<br />
23+
"value": "xx",<br />
24+
"default": false<br />
25+
}<br />
26+
]<br />
27+
label: {{ $t('dynamicsForm.AssignmentMethod.ref_variables.popover_label') }}
28+
{{ $t('common.required') }}<br />
29+
value: {{ $t('dynamicsForm.AssignmentMethod.ref_variables.popover_value') }}
30+
{{ $t('common.required') }}<br />
31+
default:{{ $t('dynamicsForm.AssignmentMethod.ref_variables.popover_default') }}
32+
<template #reference>
33+
<el-icon><InfoFilled /></el-icon>
34+
</template>
35+
</el-popover>
36+
</el-radio>
1437
</el-radio-group>
1538
</el-row>
1639
</el-form-item>

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

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,31 @@
88

99
<el-row style="width: 100%" :gutter="10">
1010
<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>
11+
<el-radio :value="item.value" size="large" v-for="item in assignment_method_option_list"
12+
>{{ item.label }}
13+
<el-popover
14+
width="300px"
15+
v-if="item.value == 'ref_variables'"
16+
class="box-item"
17+
placement="top-start"
18+
>
19+
{{ $t('dynamicsForm.AssignmentMethod.ref_variables.popover') }}:<br />
20+
[<br />
21+
{<br />
22+
"label": "xx",<br />
23+
"value": "xx",<br />
24+
"default": false<br />
25+
}<br />
26+
]<br />
27+
label: {{ $t('dynamicsForm.AssignmentMethod.ref_variables.popover_label') }}
28+
{{ $t('common.required') }}<br />
29+
value: {{ $t('dynamicsForm.AssignmentMethod.ref_variables.popover_value') }}
30+
{{ $t('common.required') }}<br />
31+
default: {{ $t('dynamicsForm.AssignmentMethod.ref_variables.popover_default') }}
32+
<template #reference>
33+
<el-icon><InfoFilled /></el-icon>
34+
</template> </el-popover
35+
></el-radio>
1436
</el-radio-group>
1537
</el-row>
1638
</el-form-item>

0 commit comments

Comments
 (0)