feat(web): file manager in chat page

This commit is contained in:
Acbox
2026-03-01 14:34:51 +08:00
parent b2349fab13
commit 05e8e66bb2
6 changed files with 52 additions and 7 deletions
@@ -28,21 +28,25 @@ import { pathSegments, joinPath } from './utils'
import FileList from './file-list.vue'
import FileViewer from './file-viewer.vue'
const props = defineProps<{
const props = withDefaults(defineProps<{
botId: string
}>()
syncUrl?: boolean
}>(), {
syncUrl: true,
})
const { t } = useI18n()
const route = useRoute()
const router = useRouter()
const currentPath = useSyncedQueryParam('path', '/data')
const currentPath = props.syncUrl ? useSyncedQueryParam('path', '/data') : ref('/data')
const entries = ref<HandlersFsFileInfo[]>([])
const listLoading = ref(false)
const openFile = ref<HandlersFsFileInfo | null>(null)
function syncFileToUrl(filePath: string | null) {
if (!props.syncUrl) return
const current = route.query.file as string | undefined
const next = filePath || undefined
if (current !== next) {
@@ -51,6 +55,7 @@ function syncFileToUrl(filePath: string | null) {
}
function restoreFileFromUrl() {
if (!props.syncUrl) return
const filePath = route.query.file as string | undefined
if (filePath && !openFile.value) {
const name = filePath.split('/').pop() ?? ''
@@ -39,7 +39,7 @@ function resolveLanguage(): string {
}
function resolveTheme(): string {
return settings.theme === 'dark' ? 'vs-dark' : 'vs'
return settings.theme === 'dark' ? 'vitesse-dark' : 'vitesse-light'
}
onMounted(() => {
+2 -1
View File
@@ -135,7 +135,8 @@
"toolRunning": "Running",
"toolInput": "Input",
"toolResult": "Result",
"unknownUser": "{platform} User"
"unknownUser": "{platform} User",
"files": "Files"
},
"models": {
"title": "Models",
+2 -1
View File
@@ -131,7 +131,8 @@
"toolRunning": "运行中",
"toolInput": "输入",
"toolResult": "结果",
"unknownUser": "{platform}用户"
"unknownUser": "{platform}用户",
"files": "文件管理"
},
"models": {
"title": "模型",
+2
View File
@@ -54,6 +54,7 @@ import {
faVideo,
faEnvelope,
faChartLine,
faFolderOpen,
} from '@fortawesome/free-solid-svg-icons'
import {
faRectangleList,
@@ -110,6 +111,7 @@ library.add(
faMicrosoft,
faEnvelope,
faChartLine,
faFolderOpen,
faYandex,
...customSearchIcons,
)
@@ -153,28 +153,64 @@
class="size-3.5 animate-spin"
/>
</Button>
<Button
type="button"
size="sm"
variant="ghost"
:disabled="!currentBotId"
:aria-label="$t('chat.files')"
@click="fileManagerOpen = true"
>
<FontAwesomeIcon
:icon="['fas', 'folder-open']"
class="size-3.5"
/>
</Button>
</InputGroupAddon>
</InputGroup>
</section>
</div>
</div>
</template>
<!-- File manager sheet -->
<Sheet v-model:open="fileManagerOpen">
<SheetContent
side="right"
class="sm:max-w-2xl w-full p-0 flex flex-col"
>
<SheetHeader class="px-4 pt-4 pb-0">
<SheetTitle>{{ $t('chat.files') }}</SheetTitle>
<SheetDescription class="sr-only">
{{ $t('chat.files') }}
</SheetDescription>
</SheetHeader>
<FileManager
v-if="currentBotId"
:bot-id="currentBotId"
:sync-url="false"
class="flex-1 min-h-0"
/>
</SheetContent>
</Sheet>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch, nextTick, onMounted } from 'vue'
import { Textarea, Button, Avatar, AvatarImage, AvatarFallback, Badge, InputGroup, InputGroupAddon, InputGroupButton, InputGroupText, InputGroupTextarea } from '@memoh/ui'
import { Textarea, Button, Avatar, AvatarImage, AvatarFallback, Badge, InputGroup, InputGroupAddon, InputGroupButton, InputGroupText, InputGroupTextarea, Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription } from '@memoh/ui'
import { useChatStore } from '@/store/chat-list'
import { storeToRefs } from 'pinia'
import MessageItem from './message-item.vue'
import MediaGalleryLightbox from './media-gallery-lightbox.vue'
import FileManager from '@/components/file-manager/index.vue'
import { useMediaGallery } from '../composables/useMediaGallery'
import type { ChatAttachment } from '@/composables/api/useChat'
const chatStore = useChatStore()
const fileInput = ref<HTMLInputElement | null>(null)
const pendingFiles = ref<File[]>([])
const fileManagerOpen = ref(false)
const {
messages,
streaming,