mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-25 07:00:48 +09:00
feat(web): file manager in chat page
This commit is contained in:
@@ -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(() => {
|
||||
|
||||
@@ -135,7 +135,8 @@
|
||||
"toolRunning": "Running",
|
||||
"toolInput": "Input",
|
||||
"toolResult": "Result",
|
||||
"unknownUser": "{platform} User"
|
||||
"unknownUser": "{platform} User",
|
||||
"files": "Files"
|
||||
},
|
||||
"models": {
|
||||
"title": "Models",
|
||||
|
||||
@@ -131,7 +131,8 @@
|
||||
"toolRunning": "运行中",
|
||||
"toolInput": "输入",
|
||||
"toolResult": "结果",
|
||||
"unknownUser": "{platform}用户"
|
||||
"unknownUser": "{platform}用户",
|
||||
"files": "文件管理"
|
||||
},
|
||||
"models": {
|
||||
"title": "模型",
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user