maxkb/ui/src/components/ai-chat/component/user-form/index.vue

358 lines
11 KiB
Vue

<template>
<div
v-if="
(inputFieldList.length > 0 || (type === 'debug-ai-chat' && apiInputFieldList.length > 0)) &&
type !== 'log'
"
class="mb-16 w-full"
style="padding: 0 24px; max-width: 400px"
>
<el-card shadow="always" class="border-r-8" style="--el-card-padding: 16px 8px">
<div class="flex align-center cursor w-full" style="padding: 0 8px">
<!-- <el-icon class="mr-8 arrow-icon" :class="showUserInput ? 'rotate-90' : ''"
><CaretRight
/></el-icon> -->
<span class="break-all ellipsis-1 mr-16" :title="inputFieldConfig.title">
{{ inputFieldConfig.title }}
</span>
</div>
<el-scrollbar max-height="160">
<el-collapse-transition>
<div v-show="showUserInput" class="mt-16" style="padding: 0 8px">
<DynamicsForm
:key="dynamicsFormRefresh"
v-model="form_data_context"
:model="form_data_context"
label-position="top"
require-asterisk-position="right"
:render_data="inputFieldList"
ref="dynamicsFormRef"
/>
<DynamicsForm
v-if="type === 'debug-ai-chat'"
v-model="api_form_data_context"
:model="api_form_data_context"
label-position="top"
require-asterisk-position="right"
:render_data="apiInputFieldList"
ref="dynamicsFormRef2"
/>
</div>
</el-collapse-transition>
</el-scrollbar>
<div class="text-right mr-8">
<el-button type="primary" v-if="first" @click="confirmHandle">{{
$t('chat.operation.startChat')
}}</el-button>
<el-button v-if="!first" @click="cancelHandle">{{ $t('common.cancel') }}</el-button>
<el-button type="primary" v-if="!first" @click="confirmHandle">{{
$t('common.confirm')
}}</el-button>
</div>
</el-card>
</div>
</template>
<script setup lang="ts">
import { ref, watch, computed, onMounted } from 'vue'
import DynamicsForm from '@/components/dynamics-form/index.vue'
import type { FormField } from '@/components/dynamics-form/type'
import { useRoute } from 'vue-router'
import { MsgWarning } from '@/utils/message'
import { t } from '@/locales'
const route = useRoute()
const props = defineProps<{
application: any
type: 'log' | 'ai-chat' | 'debug-ai-chat'
api_form_data: any
form_data: any
first: boolean
}>()
// 用于刷新动态表单
const dynamicsFormRefresh = ref(0)
const inputFieldList = ref<FormField[]>([])
const apiInputFieldList = ref<FormField[]>([])
const inputFieldConfig = ref({ title: t('chat.userInput') })
const showUserInput = ref(true)
const emit = defineEmits(['update:api_form_data', 'update:form_data', 'confirm', 'cancel'])
const api_form_data_context = computed({
get: () => {
return props.api_form_data
},
set: (data) => {
emit('update:api_form_data', data)
}
})
const form_data_context = computed({
get: () => {
return props.form_data
},
set: (data) => {
emit('update:form_data', data)
}
})
watch(
() => props.application,
() => {
handleInputFieldList()
}
)
function handleInputFieldList() {
dynamicsFormRefresh.value++
let default_value: any = {}
props.application.work_flow?.nodes
?.filter((v: any) => v.id === 'base-node')
.map((v: any) => {
inputFieldList.value = v.properties.user_input_field_list
? v.properties.user_input_field_list.map((v: any) => {
switch (v.type) {
case 'input':
return {
field: v.variable,
input_type: 'TextInput',
label: v.name,
default_value: default_value[v.variable],
required: v.is_required
}
case 'select':
return {
field: v.variable,
input_type: 'SingleSelect',
label: v.name,
default_value: default_value[v.variable],
required: v.is_required,
option_list: v.optionList.map((o: any) => {
return { key: o, value: o }
})
}
case 'date':
return {
field: v.variable,
input_type: 'DatePicker',
label: v.name,
default_value: default_value[v.variable],
required: v.is_required,
attrs: {
format: 'YYYY-MM-DD HH:mm:ss',
'value-format': 'YYYY-MM-DD HH:mm:ss',
type: 'datetime'
}
}
default:
return v
}
})
: v.properties.input_field_list
? v.properties.input_field_list
.filter((v: any) => v.assignment_method === 'user_input')
.map((v: any) => {
switch (v.type) {
case 'input':
return {
field: v.variable,
input_type: 'TextInput',
label: v.name,
default_value: default_value[v.variable],
required: v.is_required
}
case 'select':
return {
field: v.variable,
input_type: 'SingleSelect',
label: v.name,
default_value: default_value[v.variable],
required: v.is_required,
option_list: v.optionList.map((o: any) => {
return { key: o, value: o }
})
}
case 'date':
return {
field: v.variable,
input_type: 'DatePicker',
label: v.name,
default_value: default_value[v.variable],
required: v.is_required,
attrs: {
format: 'YYYY-MM-DD HH:mm:ss',
'value-format': 'YYYY-MM-DD HH:mm:ss',
type: 'datetime'
}
}
default:
break
}
})
: []
apiInputFieldList.value = v.properties.api_input_field_list
? v.properties.api_input_field_list.map((v: any) => {
switch (v.type) {
case 'input':
return {
field: v.variable,
input_type: 'TextInput',
label: v.variable,
default_value: v.default_value || default_value[v.variable],
required: v.is_required
}
case 'select':
return {
field: v.variable,
input_type: 'SingleSelect',
label: v.variable,
default_value: v.default_value || default_value[v.variable],
required: v.is_required,
option_list: v.optionList.map((o: any) => {
return { key: o, value: o }
})
}
case 'date':
return {
field: v.variable,
input_type: 'DatePicker',
label: v.variable,
default_value: v.default_value || default_value[v.variable],
required: v.is_required,
attrs: {
format: 'YYYY-MM-DD HH:mm:ss',
'value-format': 'YYYY-MM-DD HH:mm:ss',
type: 'datetime'
}
}
default:
break
}
})
: v.properties.input_field_list
? v.properties.input_field_list
.filter((v: any) => v.assignment_method === 'api_input')
.map((v: any) => {
switch (v.type) {
case 'input':
return {
field: v.variable,
input_type: 'TextInput',
label: v.name,
default_value: default_value[v.variable],
required: v.is_required
}
case 'select':
return {
field: v.variable,
input_type: 'SingleSelect',
label: v.name,
default_value: default_value[v.variable],
required: v.is_required,
option_list: v.optionList.map((o: any) => {
return { key: o, value: o }
})
}
case 'date':
return {
field: v.variable,
input_type: 'DatePicker',
label: v.name,
default_value: default_value[v.variable],
required: v.is_required,
attrs: {
format: 'YYYY-MM-DD HH:mm:ss',
'value-format': 'YYYY-MM-DD HH:mm:ss',
type: 'datetime'
}
}
default:
break
}
})
: []
//
inputFieldConfig.value = v.properties.user_input_config?.title
? v.properties.user_input_config
: { title: t('chat.userInput') }
})
}
const getRouteQueryValue = (field: string) => {
let _value = route.query[field]
if (_value != null) {
if (_value instanceof Array) {
_value = _value
.map((item) => {
if (item != null) {
return decodeQuery(item)
}
return null
})
.filter((item) => item != null)
} else {
_value = decodeQuery(_value)
}
return _value
}
return null
}
/**
* 校验参数
*/
const checkInputParam = () => {
// 检查inputFieldList是否有未填写的字段
for (let i = 0; i < inputFieldList.value.length; i++) {
if (
inputFieldList.value[i].required &&
!form_data_context.value[inputFieldList.value[i].field]
) {
MsgWarning(t('chat.tip.requiredMessage'))
return false
}
}
// 浏览器query参数找到接口传参
let msg = []
for (let f of apiInputFieldList.value) {
if (!api_form_data_context.value[f.field]) {
let _value = getRouteQueryValue(f.field)
if (_value != null) {
api_form_data_context.value[f.field] = _value
}
}
if (f.required && !api_form_data_context.value[f.field]) {
msg.push(f.field)
}
}
if (!api_form_data_context.value['asker']) {
api_form_data_context.value['asker'] = getRouteQueryValue('asker')
}
if (msg.length > 0) {
MsgWarning(
`${t('chat.tip.inputParamMessage1')} ${msg.join('、')}${t('chat.tip.inputParamMessage2')}`
)
return false
}
return true
}
const decodeQuery = (query: string) => {
try {
return decodeURIComponent(query)
} catch (e) {
return query
}
}
const confirmHandle = () => {
if (checkInputParam()) {
emit('confirm')
}
}
const cancelHandle = () => {
emit('cancel')
}
defineExpose({ checkInputParam })
onMounted(() => {
handleInputFieldList()
})
</script>
<style lang="scss" scoped></style>