perf: User input interaction style optimization
This commit is contained in:
parent
b8960d57c8
commit
a09f5c0577
@ -1,7 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="ai-chat__operate p-16-24">
|
<div class="ai-chat__operate p-16-24">
|
||||||
<slot name="operateBefore" />
|
<slot name="operateBefore" />
|
||||||
|
|
||||||
<div class="operate-textarea">
|
<div class="operate-textarea">
|
||||||
<el-scrollbar max-height="136">
|
<el-scrollbar max-height="136">
|
||||||
<div
|
<div
|
||||||
|
|||||||
@ -4,20 +4,16 @@
|
|||||||
(inputFieldList.length > 0 || (type === 'debug-ai-chat' && apiInputFieldList.length > 0)) &&
|
(inputFieldList.length > 0 || (type === 'debug-ai-chat' && apiInputFieldList.length > 0)) &&
|
||||||
type !== 'log'
|
type !== 'log'
|
||||||
"
|
"
|
||||||
class="mb-16"
|
class="mb-16 w-full"
|
||||||
style="padding: 0 24px"
|
style="padding: 0 24px; max-width: 400px"
|
||||||
>
|
>
|
||||||
<el-card shadow="always" class="border-r-8" style="--el-card-padding: 16px 8px">
|
<el-card shadow="always" class="border-r-8" style="--el-card-padding: 16px 8px">
|
||||||
<div
|
<div class="flex align-center cursor w-full" style="padding: 0 8px">
|
||||||
class="flex align-center cursor w-full"
|
<!-- <el-icon class="mr-8 arrow-icon" :class="showUserInput ? 'rotate-90' : ''"
|
||||||
style="padding: 0 8px"
|
|
||||||
@click="showUserInput = !showUserInput"
|
|
||||||
>
|
|
||||||
<el-icon class="mr-8 arrow-icon" :class="showUserInput ? 'rotate-90' : ''"
|
|
||||||
><CaretRight
|
><CaretRight
|
||||||
/></el-icon>
|
/></el-icon> -->
|
||||||
<span class="break-all ellipsis-1 mr-16" :title="inputFieldConfig.title">
|
<span class="break-all ellipsis-1 mr-16" :title="inputFieldConfig.title">
|
||||||
{{ inputFieldConfig.title }}
|
{{ inputFieldConfig.title }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<el-scrollbar max-height="160">
|
<el-scrollbar max-height="160">
|
||||||
@ -44,6 +40,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-collapse-transition>
|
</el-collapse-transition>
|
||||||
</el-scrollbar>
|
</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>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -60,6 +65,7 @@ const props = defineProps<{
|
|||||||
type: 'log' | 'ai-chat' | 'debug-ai-chat'
|
type: 'log' | 'ai-chat' | 'debug-ai-chat'
|
||||||
api_form_data: any
|
api_form_data: any
|
||||||
form_data: any
|
form_data: any
|
||||||
|
first: boolean
|
||||||
}>()
|
}>()
|
||||||
// 用于刷新动态表单
|
// 用于刷新动态表单
|
||||||
const dynamicsFormRefresh = ref(0)
|
const dynamicsFormRefresh = ref(0)
|
||||||
@ -67,7 +73,7 @@ const inputFieldList = ref<FormField[]>([])
|
|||||||
const apiInputFieldList = ref<FormField[]>([])
|
const apiInputFieldList = ref<FormField[]>([])
|
||||||
const inputFieldConfig = ref({ title: t('chat.userInput') })
|
const inputFieldConfig = ref({ title: t('chat.userInput') })
|
||||||
const showUserInput = ref(true)
|
const showUserInput = ref(true)
|
||||||
const emit = defineEmits(['update:api_form_data', 'update:form_data'])
|
const emit = defineEmits(['update:api_form_data', 'update:form_data', 'confirm', 'cancel'])
|
||||||
|
|
||||||
const api_form_data_context = computed({
|
const api_form_data_context = computed({
|
||||||
get: () => {
|
get: () => {
|
||||||
@ -324,6 +330,14 @@ const decodeQuery = (query: string) => {
|
|||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const confirmHandle = () => {
|
||||||
|
if (checkInputParam()) {
|
||||||
|
emit('confirm')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const cancelHandle = () => {
|
||||||
|
emit('cancel')
|
||||||
|
}
|
||||||
defineExpose({ checkInputParam })
|
defineExpose({ checkInputParam })
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
handleInputFieldList()
|
handleInputFieldList()
|
||||||
|
|||||||
@ -1,56 +1,76 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="aiChatRef" class="ai-chat" :class="type">
|
<div ref="aiChatRef" class="ai-chat" :class="type">
|
||||||
<UserForm
|
<div
|
||||||
v-model:api_form_data="api_form_data"
|
v-show="(isUserInput && firsUserInput) || showUserInput"
|
||||||
v-model:form_data="form_data"
|
:class="firsUserInput ? 'firstUserInput' : 'popperUserInput'"
|
||||||
:application="applicationDetails"
|
|
||||||
:type="type"
|
|
||||||
ref="userFormRef"
|
|
||||||
></UserForm>
|
|
||||||
<el-scrollbar ref="scrollDiv" @scroll="handleScrollTop">
|
|
||||||
<div ref="dialogScrollbar" class="ai-chat__content p-24">
|
|
||||||
<PrologueContent
|
|
||||||
:type="type"
|
|
||||||
:application="applicationDetails"
|
|
||||||
:available="available"
|
|
||||||
:send-message="sendMessage"
|
|
||||||
></PrologueContent>
|
|
||||||
|
|
||||||
<template v-for="(item, index) in chatList" :key="index">
|
|
||||||
<!-- 问题 -->
|
|
||||||
<QuestionContent
|
|
||||||
:type="type"
|
|
||||||
:application="applicationDetails"
|
|
||||||
:chat-record="item"
|
|
||||||
></QuestionContent>
|
|
||||||
<!-- 回答 -->
|
|
||||||
<AnswerContent
|
|
||||||
:application="applicationDetails"
|
|
||||||
:loading="loading"
|
|
||||||
v-model:chat-record="chatList[index]"
|
|
||||||
:type="type"
|
|
||||||
:send-message="sendMessage"
|
|
||||||
:chat-management="ChatManagement"
|
|
||||||
></AnswerContent>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</el-scrollbar>
|
|
||||||
|
|
||||||
<ChatInputOperate
|
|
||||||
:app-id="appId"
|
|
||||||
:application-details="applicationDetails"
|
|
||||||
:is-mobile="isMobile"
|
|
||||||
:type="type"
|
|
||||||
:send-message="sendMessage"
|
|
||||||
:open-chat-id="openChatId"
|
|
||||||
:chat-management="ChatManagement"
|
|
||||||
v-model:chat-id="chartOpenId"
|
|
||||||
v-model:loading="loading"
|
|
||||||
v-if="type !== 'log'"
|
|
||||||
>
|
>
|
||||||
<template #operateBefore> <slot name="operateBefore" /> </template>
|
<UserForm
|
||||||
</ChatInputOperate>
|
v-model:api_form_data="api_form_data"
|
||||||
<Control></Control>
|
v-model:form_data="form_data"
|
||||||
|
:application="applicationDetails"
|
||||||
|
:type="type"
|
||||||
|
:first="firsUserInput"
|
||||||
|
@confirm="UserFormConfirm"
|
||||||
|
@cancel="() => (showUserInput = false)"
|
||||||
|
ref="userFormRef"
|
||||||
|
></UserForm>
|
||||||
|
</div>
|
||||||
|
<template v-if="!firsUserInput">
|
||||||
|
<el-scrollbar ref="scrollDiv" @scroll="handleScrollTop">
|
||||||
|
<div ref="dialogScrollbar" class="ai-chat__content p-24">
|
||||||
|
<PrologueContent
|
||||||
|
:type="type"
|
||||||
|
:application="applicationDetails"
|
||||||
|
:available="available"
|
||||||
|
:send-message="sendMessage"
|
||||||
|
></PrologueContent>
|
||||||
|
|
||||||
|
<template v-for="(item, index) in chatList" :key="index">
|
||||||
|
<!-- 问题 -->
|
||||||
|
<QuestionContent
|
||||||
|
:type="type"
|
||||||
|
:application="applicationDetails"
|
||||||
|
:chat-record="item"
|
||||||
|
></QuestionContent>
|
||||||
|
<!-- 回答 -->
|
||||||
|
<AnswerContent
|
||||||
|
:application="applicationDetails"
|
||||||
|
:loading="loading"
|
||||||
|
v-model:chat-record="chatList[index]"
|
||||||
|
:type="type"
|
||||||
|
:send-message="sendMessage"
|
||||||
|
:chat-management="ChatManagement"
|
||||||
|
></AnswerContent>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
|
||||||
|
<ChatInputOperate
|
||||||
|
:app-id="appId"
|
||||||
|
:application-details="applicationDetails"
|
||||||
|
:is-mobile="isMobile"
|
||||||
|
:type="type"
|
||||||
|
:send-message="sendMessage"
|
||||||
|
:open-chat-id="openChatId"
|
||||||
|
:chat-management="ChatManagement"
|
||||||
|
v-model:chat-id="chartOpenId"
|
||||||
|
v-model:loading="loading"
|
||||||
|
v-if="type !== 'log'"
|
||||||
|
>
|
||||||
|
<template #operateBefore>
|
||||||
|
<div class="flex-between">
|
||||||
|
<slot name="operateBefore">
|
||||||
|
<span></span>
|
||||||
|
</slot>
|
||||||
|
<el-button class="user-input-button mb-8" type="primary" text @click="toggleUserInput">
|
||||||
|
<AppIcon iconName="app-user-input"></AppIcon>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ChatInputOperate>
|
||||||
|
|
||||||
|
<Control></Control>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@ -62,7 +82,7 @@ import { ChatManagement, type chatType } from '@/api/type/application'
|
|||||||
import { randomId } from '@/utils/utils'
|
import { randomId } from '@/utils/utils'
|
||||||
import useStore from '@/stores'
|
import useStore from '@/stores'
|
||||||
import { isWorkFlow } from '@/utils/application'
|
import { isWorkFlow } from '@/utils/application'
|
||||||
import { debounce } from 'lodash'
|
import { debounce, first } from 'lodash'
|
||||||
import AnswerContent from '@/components/ai-chat/component/answer-content/index.vue'
|
import AnswerContent from '@/components/ai-chat/component/answer-content/index.vue'
|
||||||
import QuestionContent from '@/components/ai-chat/component/question-content/index.vue'
|
import QuestionContent from '@/components/ai-chat/component/question-content/index.vue'
|
||||||
import ChatInputOperate from '@/components/ai-chat/component/chat-input-operate/index.vue'
|
import ChatInputOperate from '@/components/ai-chat/component/chat-input-operate/index.vue'
|
||||||
@ -106,13 +126,25 @@ const chatList = ref<any[]>([])
|
|||||||
const form_data = ref<any>({})
|
const form_data = ref<any>({})
|
||||||
const api_form_data = ref<any>({})
|
const api_form_data = ref<any>({})
|
||||||
const userFormRef = ref<InstanceType<typeof UserForm>>()
|
const userFormRef = ref<InstanceType<typeof UserForm>>()
|
||||||
|
// 用户输入
|
||||||
|
const firsUserInput = ref(true)
|
||||||
|
const showUserInput = ref(false)
|
||||||
|
|
||||||
|
const isUserInput = computed(
|
||||||
|
() =>
|
||||||
|
props.applicationDetails.work_flow?.nodes?.filter((v: any) => v.id === 'base-node')[0]
|
||||||
|
.properties.user_input_field_list.length > 0
|
||||||
|
)
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.chatId,
|
() => props.chatId,
|
||||||
(val) => {
|
(val) => {
|
||||||
if (val && val !== 'new') {
|
if (val && val !== 'new') {
|
||||||
chartOpenId.value = val
|
chartOpenId.value = val
|
||||||
|
firsUserInput.value = false
|
||||||
} else {
|
} else {
|
||||||
chartOpenId.value = ''
|
chartOpenId.value = ''
|
||||||
|
firsUserInput.value = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ deep: true }
|
{ deep: true }
|
||||||
@ -136,6 +168,15 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const toggleUserInput = () => {
|
||||||
|
showUserInput.value = !showUserInput.value
|
||||||
|
}
|
||||||
|
|
||||||
|
function UserFormConfirm() {
|
||||||
|
firsUserInput.value = false
|
||||||
|
showUserInput.value = false
|
||||||
|
}
|
||||||
|
|
||||||
function sendMessage(val: string, other_params_data?: any, chat?: chatType) {
|
function sendMessage(val: string, other_params_data?: any, chat?: chatType) {
|
||||||
if (!userFormRef.value?.checkInputParam()) {
|
if (!userFormRef.value?.checkInputParam()) {
|
||||||
return
|
return
|
||||||
@ -467,4 +508,18 @@ defineExpose({
|
|||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import './index.scss';
|
@import './index.scss';
|
||||||
|
.firstUserInput {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.popperUserInput {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 999;
|
||||||
|
right: 50px;
|
||||||
|
bottom: 80px;
|
||||||
|
width: calc(100% - 50px);
|
||||||
|
max-width: 400px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1394,5 +1394,26 @@ export const iconMap: any = {
|
|||||||
)
|
)
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
'app-user-input': {
|
||||||
|
iconReader: () => {
|
||||||
|
return h('i', [
|
||||||
|
h(
|
||||||
|
'svg',
|
||||||
|
{
|
||||||
|
style: { height: '100%', width: '100%' },
|
||||||
|
viewBox: '0 0 1024 1024',
|
||||||
|
version: '1.1',
|
||||||
|
xmlns: 'http://www.w3.org/2000/svg'
|
||||||
|
},
|
||||||
|
[
|
||||||
|
h('path', {
|
||||||
|
d: 'M85.333333 234.666667a149.333333 149.333333 0 0 1 292.48-42.666667H917.333333a21.333333 21.333333 0 0 1 21.333334 21.333333v42.666667a21.333333 21.333333 0 0 1-21.333334 21.333333H377.813333A149.418667 149.418667 0 0 1 85.333333 234.666667z m21.333334 320a21.333333 21.333333 0 0 1-21.333334-21.333334v-42.666666a21.333333 21.333333 0 0 1 21.333334-21.333334h262.186666a149.418667 149.418667 0 0 1 286.293334 0H917.333333a21.333333 21.333333 0 0 1 21.333334 21.333334v42.666666a21.333333 21.333333 0 0 1-21.333334 21.333334h-262.186666a149.418667 149.418667 0 0 1-286.293334 0H106.666667z m405.333333 21.333333a64 64 0 1 0 0-128 64 64 0 0 0 0 128z m-405.333333 256A21.333333 21.333333 0 0 1 85.333333 810.666667v-42.666667a21.333333 21.333333 0 0 1 21.333334-21.333333h539.52a149.418667 149.418667 0 0 1 292.48 42.666666 149.333333 149.333333 0 0 1-292.48 42.666667H106.666667z m682.666666-106.666667a64 64 0 1 0 0 128 64 64 0 0 0 0-128zM234.666667 298.666667a64 64 0 1 0 0-128 64 64 0 0 0 0 128z',
|
||||||
|
fill: 'currentColor'
|
||||||
|
})
|
||||||
|
]
|
||||||
|
)
|
||||||
|
])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,8 @@ export default {
|
|||||||
oppose: 'Dislike',
|
oppose: 'Dislike',
|
||||||
cancelOppose: 'Undo Dislike',
|
cancelOppose: 'Undo Dislike',
|
||||||
continue: 'Continue',
|
continue: 'Continue',
|
||||||
stopChat: 'Stop Response'
|
stopChat: 'Stop Response',
|
||||||
|
startChat: 'Start Response',
|
||||||
},
|
},
|
||||||
tip: {
|
tip: {
|
||||||
error500Message: 'Sorry, the service is currently under maintenance. Please try again later!',
|
error500Message: 'Sorry, the service is currently under maintenance. Please try again later!',
|
||||||
|
|||||||
@ -23,7 +23,8 @@ export default {
|
|||||||
oppose: '反对',
|
oppose: '反对',
|
||||||
cancelOppose: '取消反对',
|
cancelOppose: '取消反对',
|
||||||
continue: '继续',
|
continue: '继续',
|
||||||
stopChat: '停止回答'
|
stopChat: '停止回答',
|
||||||
|
startChat: '开始回答',
|
||||||
},
|
},
|
||||||
tip: {
|
tip: {
|
||||||
error500Message: '抱歉,当前正在维护,无法提供服务,请稍后再试!',
|
error500Message: '抱歉,当前正在维护,无法提供服务,请稍后再试!',
|
||||||
|
|||||||
@ -23,7 +23,8 @@ export default {
|
|||||||
oppose: '反對',
|
oppose: '反對',
|
||||||
cancelOppose: '取消反對',
|
cancelOppose: '取消反對',
|
||||||
continue: '繼續',
|
continue: '繼續',
|
||||||
stopChat: '停止回答'
|
stopChat: '停止回答',
|
||||||
|
startChat: '開始回答',
|
||||||
},
|
},
|
||||||
tip: {
|
tip: {
|
||||||
error500Message: '抱歉,當前正在維護,無法提供服務,請稍後再試!',
|
error500Message: '抱歉,當前正在維護,無法提供服務,請稍後再試!',
|
||||||
|
|||||||
@ -156,8 +156,8 @@
|
|||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<EditTitleDialog ref="EditTitleDialogRef" @refresh="refreshFieldTitle" />
|
||||||
</div>
|
</div>
|
||||||
<EditTitleDialog ref="EditTitleDialogRef" @refresh="refreshFieldTitle" />
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user