parent
06f41c3758
commit
c98a2a3cb8
|
@ -8,6 +8,7 @@ import { useChat } from './hooks/useChat'
|
||||||
import { fetchChatAPI } from '@/api'
|
import { fetchChatAPI } from '@/api'
|
||||||
import { HoverButton, SvgIcon } from '@/components/common'
|
import { HoverButton, SvgIcon } from '@/components/common'
|
||||||
import { useHistoryStore } from '@/store'
|
import { useHistoryStore } from '@/store'
|
||||||
|
import { useBasicLayout } from '@/hooks/useBasicLayout'
|
||||||
|
|
||||||
let controller = new AbortController()
|
let controller = new AbortController()
|
||||||
|
|
||||||
|
@ -15,6 +16,8 @@ const ms = useMessage()
|
||||||
|
|
||||||
const historyStore = useHistoryStore()
|
const historyStore = useHistoryStore()
|
||||||
|
|
||||||
|
const { isMobile } = useBasicLayout()
|
||||||
|
|
||||||
let messageReactive: MessageReactive | null = null
|
let messageReactive: MessageReactive | null = null
|
||||||
|
|
||||||
const scrollRef = ref<HTMLDivElement>()
|
const scrollRef = ref<HTMLDivElement>()
|
||||||
|
@ -30,6 +33,12 @@ const heartbeat = computed(() => historyStore.heartbeat)
|
||||||
const list = computed<Chat.Chat[]>(() => historyStore.getCurrentChat)
|
const list = computed<Chat.Chat[]>(() => historyStore.getCurrentChat)
|
||||||
const chatList = computed<Chat.Chat[]>(() => list.value.filter(item => (!item.reversal && !item.error)))
|
const chatList = computed<Chat.Chat[]>(() => list.value.filter(item => (!item.reversal && !item.error)))
|
||||||
|
|
||||||
|
const footerMobileStyle = computed(() => {
|
||||||
|
if (isMobile.value)
|
||||||
|
return ['pl-2', 'pt-2', 'pb-6', 'fixed', 'bottom-0', 'left-0', 'right-0', 'z-30']
|
||||||
|
return []
|
||||||
|
})
|
||||||
|
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
if (loading.value)
|
if (loading.value)
|
||||||
return
|
return
|
||||||
|
@ -143,7 +152,11 @@ watch(
|
||||||
<Layout>
|
<Layout>
|
||||||
<div class="flex flex-col h-full">
|
<div class="flex flex-col h-full">
|
||||||
<main class="flex-1 overflow-hidden">
|
<main class="flex-1 overflow-hidden">
|
||||||
<div ref="scrollRef" class="h-full p-4 overflow-hidden overflow-y-auto">
|
<div
|
||||||
|
ref="scrollRef"
|
||||||
|
class="h-full p-4 overflow-hidden overflow-y-auto"
|
||||||
|
:class="[{ 'p-2': isMobile }]"
|
||||||
|
>
|
||||||
<template v-if="!list.length">
|
<template v-if="!list.length">
|
||||||
<div class="flex items-center justify-center mt-4 text-center text-neutral-300">
|
<div class="flex items-center justify-center mt-4 text-center text-neutral-300">
|
||||||
<SvgIcon icon="ri:bubble-chart-fill" class="mr-2 text-3xl" />
|
<SvgIcon icon="ri:bubble-chart-fill" class="mr-2 text-3xl" />
|
||||||
|
@ -153,21 +166,32 @@ watch(
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div>
|
<div>
|
||||||
<Message
|
<Message
|
||||||
v-for="(item, index) of list" :key="index" :date-time="item.dateTime" :message="item.message"
|
v-for="(item, index) of list"
|
||||||
:reversal="item.reversal" :error="item.error"
|
:key="index"
|
||||||
|
:date-time="item.dateTime"
|
||||||
|
:message="item.message"
|
||||||
|
:reversal="item.reversal"
|
||||||
|
:error="item.error"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<footer class="p-4">
|
<footer
|
||||||
|
class="p-4"
|
||||||
|
:class="footerMobileStyle"
|
||||||
|
>
|
||||||
<div class="flex items-center justify-between space-x-2">
|
<div class="flex items-center justify-between space-x-2">
|
||||||
<HoverButton tooltip="Clear conversations">
|
<HoverButton tooltip="Clear conversations">
|
||||||
<span class="text-xl text-[#4f555e]" @click="handleClear">
|
<span class="text-xl text-[#4f555e]" @click="handleClear">
|
||||||
<SvgIcon icon="ri:delete-bin-line" />
|
<SvgIcon icon="ri:delete-bin-line" />
|
||||||
</span>
|
</span>
|
||||||
</HoverButton>
|
</HoverButton>
|
||||||
<NInput v-model:value="prompt" placeholder="Type a message..." @keypress="handleEnter" />
|
<NInput
|
||||||
|
v-model:value="prompt"
|
||||||
|
placeholder="Type a message..."
|
||||||
|
@keypress="handleEnter"
|
||||||
|
/>
|
||||||
<NButton type="primary" :disabled="loading" @click="handleSubmit">
|
<NButton type="primary" :disabled="loading" @click="handleSubmit">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<SvgIcon icon="ri:send-plane-fill" />
|
<SvgIcon icon="ri:send-plane-fill" />
|
||||||
|
|
|
@ -22,13 +22,14 @@ const getContainerClass = computed(() => {
|
||||||
return [
|
return [
|
||||||
'h-full',
|
'h-full',
|
||||||
{ 'pt-14': isMobile.value },
|
{ 'pt-14': isMobile.value },
|
||||||
|
{ 'pb-[70px]': isMobile.value },
|
||||||
{ 'pl-[260px]': !isMobile.value && !collapsed.value },
|
{ 'pl-[260px]': !isMobile.value && !collapsed.value },
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="h-screen p-4" :class="[{ 'p-0': isMobile }]">
|
<div class="h-screen" :class="[isMobile ? 'p-0' : 'p-4']">
|
||||||
<div class="h-full overflow-hidden" :class="getMobileClass">
|
<div class="h-full overflow-hidden" :class="getMobileClass">
|
||||||
<NLayout class="z-40 transition" :class="getContainerClass" has-sider>
|
<NLayout class="z-40 transition" :class="getContainerClass" has-sider>
|
||||||
<Sider />
|
<Sider />
|
||||||
|
|
|
@ -23,7 +23,7 @@ function handleUpdateCollapsed() {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<header class="fixed top-0 left-0 right-0 z-50 border-b bg-white/80 backdrop-blur">
|
<header class="fixed top-0 left-0 right-0 z-50 border-b bg-white/80 backdrop-blur">
|
||||||
<div class="relative flex items-center justify-between px-4 h-14">
|
<div class="relative flex items-center justify-between h-14">
|
||||||
<button class="flex items-center justify-center w-11 h-11" @click="handleUpdateCollapsed">
|
<button class="flex items-center justify-center w-11 h-11" @click="handleUpdateCollapsed">
|
||||||
<SvgIcon v-if="collapsed" class="text-2xl" icon="ri:align-justify" />
|
<SvgIcon v-if="collapsed" class="text-2xl" icon="ri:align-justify" />
|
||||||
<SvgIcon v-else class="text-2xl" icon="ri:align-right" />
|
<SvgIcon v-else class="text-2xl" icon="ri:align-right" />
|
||||||
|
|
|
@ -29,7 +29,10 @@ watch(
|
||||||
(val) => {
|
(val) => {
|
||||||
appStore.setSiderCollapsed(val)
|
appStore.setSiderCollapsed(val)
|
||||||
},
|
},
|
||||||
{ flush: 'post' },
|
{
|
||||||
|
immediate: true,
|
||||||
|
flush: 'post',
|
||||||
|
},
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -42,6 +45,7 @@ watch(
|
||||||
collapse-mode="transform"
|
collapse-mode="transform"
|
||||||
position="absolute"
|
position="absolute"
|
||||||
bordered
|
bordered
|
||||||
|
style="z-index: 50;"
|
||||||
@update-collapsed="handleUpdateCollapsed"
|
@update-collapsed="handleUpdateCollapsed"
|
||||||
>
|
>
|
||||||
<div class="flex flex-col h-full" :class="[{ 'pt-14': isMobile }]">
|
<div class="flex flex-col h-full" :class="[{ 'pt-14': isMobile }]">
|
||||||
|
@ -63,4 +67,7 @@ watch(
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</NLayoutSider>
|
</NLayoutSider>
|
||||||
|
<template v-if="isMobile">
|
||||||
|
<div v-show="!collapsed" class="absolute inset-0 z-40 bg-black/40" @click="handleUpdateCollapsed" />
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
Loading…
Reference in New Issue