feat: 侧边栏切换取消上次请求

This commit is contained in:
ChenZhaoYu 2023-02-14 16:57:11 +08:00
parent d2ae2c4f54
commit 4458e744cc
4 changed files with 40 additions and 24 deletions

View File

@ -1,17 +1,16 @@
import type { GenericAbortSignal } from 'axios'
import { post } from '@/utils/request'
export const controller = new AbortController()
export function fetchChatAPI<T = any>(
prompt: string,
options?: { conversationId?: string; parentMessageId?: string },
signal?: GenericAbortSignal,
) {
return post<T>({
url: '/chat',
data: { prompt, options },
})
}
export function clearConversations<T = any>() {
return post<T>({
url: '/clear',
signal,
})
}

View File

@ -1,5 +1,5 @@
<script setup lang='ts'>
import { computed, nextTick, ref, watch } from 'vue'
import { computed, nextTick, onMounted, ref, watch } from 'vue'
import { NButton, NInput, useMessage } from 'naive-ui'
import { Message } from './components'
import { Layout } from './layout'
@ -9,13 +9,15 @@ import { HoverButton, SvgIcon } from '@/components/common'
import { useHistoryStore } from '@/store'
import { isNumber } from '@/utils/is'
let controller = new AbortController()
const ms = useMessage()
const historyStore = useHistoryStore()
const scrollRef = ref<HTMLDivElement>()
const { addChat, clearChat } = useChat()
const { addChat, clearChat: handleClear } = useChat()
const prompt = ref('')
const loading = ref(false)
@ -47,11 +49,12 @@ async function handleSubmit() {
try {
loading.value = true
const { data } = await fetchChatAPI(message, options)
const { data } = await fetchChatAPI(message, options, controller.signal)
addMessage(data?.text ?? '', { options: { conversationId: data.conversationId, parentMessageId: data.id } })
}
catch (error: any) {
addMessage(`Error: ${error.message ?? 'Request failed, please try again later.'}`, { error: true })
if (error.message !== 'cancelled')
addMessage(`Error: ${error.message ?? 'Request failed, please try again later.'}`, { error: true })
}
finally {
loading.value = false
@ -69,22 +72,32 @@ function addMessage(
uuid?: number | null,
) {
addChat(message, args, uuid)
scrollToBottom()
}
function scrollToBottom() {
nextTick(() => scrollRef.value && (scrollRef.value.scrollTop = scrollRef.value.scrollHeight))
}
function handleClear() {
clearChat()
function handleCancel() {
//
controller.abort()
controller = new AbortController()
loading.value = false
}
onMounted(() => {
scrollToBottom()
})
watch(
currentActive,
(active: number | null) => {
(active) => {
if (isNumber(active)) {
loading.value = false
nextTick(() => scrollRef.value && (scrollRef.value.scrollTop = scrollRef.value.scrollHeight))
handleCancel()
scrollToBottom()
}
},
{ immediate: true },
)
</script>
@ -109,7 +122,7 @@ watch(
</span>
</HoverButton>
<NInput v-model:value="prompt" placeholder="Type a message..." @keypress="handleEnter" />
<NButton type="primary" :loading="loading" @click="handleSubmit">
<NButton type="primary" :loading="loading" @click="handleCancel">
<template #icon>
<SvgIcon icon="ri:send-plane-fill" />
</template>

View File

@ -1,7 +1,6 @@
import { defineStore } from 'pinia'
import type { HistoryState } from './helper'
import { getLocalHistory, setLocalHistory } from './helper'
export const useHistoryStore = defineStore('history-store', {
state: (): HistoryState => getLocalHistory(),
getters: {
@ -65,6 +64,8 @@ export const useHistoryStore = defineStore('history-store', {
},
chooseHistory(index: number) {
if (this.active === index)
return
this.active = index
setLocalHistory(this.$state)
},

View File

@ -1,4 +1,4 @@
import type { AxiosResponse } from 'axios'
import type { AxiosResponse, GenericAbortSignal } from 'axios'
import request from './axios'
export interface HttpOption {
@ -6,6 +6,7 @@ export interface HttpOption {
data?: any
method?: string
headers?: any
signal?: GenericAbortSignal
beforeRequest?: () => void
afterRequest?: () => void
}
@ -20,7 +21,7 @@ export interface Response<T = any> {
status: string
}
function http<T = any>({ url, data, method, headers, beforeRequest, afterRequest }: HttpOption) {
function http<T = any>({ url, data, method, headers, signal, beforeRequest, afterRequest }: HttpOption) {
const successHandler = (res: AxiosResponse<Response<T>>) => {
if (res.data.status === 'Success')
return res.data
@ -40,30 +41,32 @@ function http<T = any>({ url, data, method, headers, beforeRequest, afterRequest
const params = Object.assign(typeof data === 'function' ? data() : data ?? {}, {})
return method === 'GET'
? request.get(url, { params }).then(successHandler, failHandler)
: request.post(url, params, { headers }).then(successHandler, failHandler)
? request.get(url, { params, signal }).then(successHandler, failHandler)
: request.post(url, params, { headers, signal }).then(successHandler, failHandler)
}
export function get<T = any>(
{ url, data, method = 'GET', beforeRequest, afterRequest }: HttpOption,
{ url, data, method = 'GET', signal, beforeRequest, afterRequest }: HttpOption,
): Promise<Response<T>> {
return http<T>({
url,
method,
data,
signal,
beforeRequest,
afterRequest,
})
}
export function post<T = any>(
{ url, data, method = 'POST', headers, beforeRequest, afterRequest }: HttpOption,
{ url, data, method = 'POST', headers, signal, beforeRequest, afterRequest }: HttpOption,
): Promise<Response<T>> {
return http<T>({
url,
method,
data,
headers,
signal,
beforeRequest,
afterRequest,
})