feat: 对话框

This commit is contained in:
wangdan-fit2cloud 2023-11-28 17:39:35 +08:00
parent 4c3dbbf6af
commit f669ac2b35
4 changed files with 88 additions and 30 deletions

View File

@ -7,4 +7,9 @@ interface ApplicationFormType {
example?: string[] example?: string[]
dataset_id_list: string[] dataset_id_list: string[]
} }
export type { ApplicationFormType } interface chatType {
id: string
problem_text: string
answer_text: string
}
export type { ApplicationFormType, chatType }

View File

@ -1,15 +1,12 @@
<template> <template>
<div class="ai-dialog p-24"> <div class="ai-dialog p-24">
<el-scrollbar> <el-scrollbar ref="scrollDiv">
<div class="ai-dialog__content"> <div ref="dialogScrollbar" class="ai-dialog__content">
<div class="item-content mb-16"> <div class="item-content mb-16">
<div class="avatar"> <div class="avatar">
<AppAvatar class="avatar-gradient"> <AppAvatar class="avatar-gradient">
<img src="@/assets/icon_robot.svg" style="width: 54%" alt="" /> <img src="@/assets/icon_robot.svg" style="width: 54%" alt="" />
</AppAvatar> </AppAvatar>
<!-- <AppAvatar>
<img src="@/assets/user-icon.svg" style="width: 54%" alt="" />
</AppAvatar> -->
</div> </div>
<div class="content"> <div class="content">
@ -36,28 +33,35 @@
</el-card> </el-card>
</div> </div>
</div> </div>
<div class="item-content mb-16"> <template v-for="(item, index) in chatList" :key="index">
<div class="avatar"> <!-- 问题 -->
<AppAvatar> <div class="item-content mb-16 lighter">
<img src="@/assets/user-icon.svg" style="width: 54%" alt="" /> <div class="avatar">
</AppAvatar> <AppAvatar>
</div> <img src="@/assets/user-icon.svg" style="width: 54%" alt="" />
<div class="content"> </AppAvatar>
<div class="text"> </div>
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX <div class="content">
<div class="text">
{{ item.problem_text }}
</div>
</div> </div>
</div> </div>
</div> <!-- 回答 -->
<div class="item-content mb-16"> <div class="item-content mb-16 lighter">
<div class="avatar"> <div class="avatar">
<AppAvatar class="avatar-gradient"> <AppAvatar class="avatar-gradient">
<img src="@/assets/icon_robot.svg" style="width: 54%" alt="" /> <img src="@/assets/icon_robot.svg" style="width: 54%" alt="" />
</AppAvatar> </AppAvatar>
</div>
<div class="content">
<div class="flex" v-if="!item.answer_text">
<el-card shadow="always" class="dialog-card"> {{ '回答中...' }} </el-card>
</div>
<el-card v-else shadow="always" class="dialog-card"> {{ item.answer_text }} </el-card>
</div>
</div> </div>
<div class="content"> </template>
<el-card shadow="always" class="dialog-card"> XXXXXXXXX </el-card>
</div>
</div>
</div> </div>
</el-scrollbar> </el-scrollbar>
<div class="ai-dialog__operate p-24"> <div class="ai-dialog__operate p-24">
@ -67,13 +71,15 @@
type="textarea" type="textarea"
placeholder="请输入" placeholder="请输入"
:autosize="{ minRows: 1, maxRows: 8 }" :autosize="{ minRows: 1, maxRows: 8 }"
@keydown.enter="sendChatHandle($event)"
:disabled="loading"
/> />
<div class="operate" v-loading="loading"> <div class="operate" v-loading="loading">
<el-button <el-button
text text
class="sent-button" class="sent-button"
:disabled="!(inputValue && data?.name && data?.model_id)" :disabled="!(inputValue && data?.name && data?.model_id)"
@click="chatMessage" @click="sendChatHandle"
> >
<img <img
v-show="!(inputValue && data?.name && data?.model_id)" v-show="!(inputValue && data?.name && data?.model_id)"
@ -85,7 +91,6 @@
src="@/assets/icon_send_colorful.svg" src="@/assets/icon_send_colorful.svg"
alt="" alt=""
/> />
<!-- <AppIcon iconName="app-send"></AppIcon> -->
</el-button> </el-button>
</div> </div>
</div> </div>
@ -93,22 +98,40 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { ref, nextTick, onUpdated } from 'vue'
import applicationApi from '@/api/application' import applicationApi from '@/api/application'
import type { chatType } from '@/api/type/application'
import { randomId } from '@/utils/utils'
const props = defineProps({ const props = defineProps({
data: { data: {
type: Object, type: Object,
default: () => {} default: () => {}
} }
}) })
const scrollDiv = ref()
const dialogScrollbar = ref()
const loading = ref(false) const loading = ref(false)
const inputValue = ref('') const inputValue = ref('')
const chartOpenId = ref('') const chartOpenId = ref('')
const chatList = ref<chatType[]>([])
function quickProblemHandel(val: string) { function quickProblemHandel(val: string) {
inputValue.value = val inputValue.value = val
} }
function sendChatHandle(event: any) {
if (!event.ctrlKey) {
// ctrl
event.preventDefault()
chatMessage()
} else {
// ctrl+
inputValue.value += '\n'
}
}
/** /**
* 对话 * 对话
*/ */
@ -131,10 +154,18 @@ function getChartOpenId() {
} }
function chatMessage() { function chatMessage() {
loading.value = true
if (!chartOpenId.value) { if (!chartOpenId.value) {
getChartOpenId() getChartOpenId()
} else { } else {
applicationApi.postChatMessage(chartOpenId.value, inputValue.value).then(async (response) => { applicationApi.postChatMessage(chartOpenId.value, inputValue.value).then(async (response) => {
const randomNum = randomId()
chatList.value.push({
id: randomNum,
problem_text: inputValue.value,
answer_text: ''
})
inputValue.value = ''
const reader = response.body.getReader() const reader = response.body.getReader()
while (true) { while (true) {
const { done, value } = await reader.read() const { done, value } = await reader.read()
@ -144,11 +175,26 @@ function chatMessage() {
} }
const decoder = new TextDecoder('utf-8') const decoder = new TextDecoder('utf-8')
const str = decoder.decode(value, { stream: true }) const str = decoder.decode(value, { stream: true })
console.log('value', JSON.parse(str.replace('data:', ''))) // console.log(JSON?.parse(str.replace('data:', '')))
const content = JSON?.parse(str.replace('data:', ''))?.content
if (content) {
chatList.value[chatList.value.findIndex((v) => v.id === randomNum)].answer_text += content
}
} }
}) })
} }
} }
//
function handleScrollBottom() {
nextTick(() => {
scrollDiv.value.setScrollTop(dialogScrollbar.value.scrollHeight)
})
}
onUpdated(() => {
handleScrollBottom()
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.ai-dialog { .ai-dialog {
@ -160,6 +206,7 @@ function chatMessage() {
position: relative; position: relative;
padding-right: 20px; padding-right: 20px;
padding-top: 0; padding-top: 0;
color: var(--app-text-color);
&__content { &__content {
width: 99%; width: 99%;
padding-bottom: 96px; padding-bottom: 96px;

View File

@ -38,7 +38,6 @@ instance.interceptors.request.use(
//设置响应拦截器 //设置响应拦截器
instance.interceptors.response.use( instance.interceptors.response.use(
(response: any) => { (response: any) => {
console.log('instance_response', response)
if (response.data) { if (response.data) {
if (response.status !== 200 && !(response.data instanceof Blob)) { if (response.status !== 200 && !(response.data instanceof Blob)) {
MsgError(response.data.message) MsgError(response.data.message)

View File

@ -19,6 +19,13 @@ export function filesize(size: number) {
return (size / Math.pow(num, 4)).toFixed(2) + 'T' //T return (size / Math.pow(num, 4)).toFixed(2) + 'T' //T
} }
/*
id
*/
export const randomId = function () {
return Math.floor(Math.random() * 10000) + ''
}
/* /*
*/ */