142 lines
3.5 KiB
Vue
142 lines
3.5 KiB
Vue
<template>
|
|
<div class="document-panel" :class="{ 'document-panel--collapsed': collapsed }">
|
|
<div class="document-panel__header" @click="toggleCollapsed">
|
|
<div class="document-panel__title">
|
|
<FolderOpenOutlined />
|
|
<span>文档列表</span>
|
|
<a-badge v-if="documents.length > 0" :count="documents.length" :number-style="{ backgroundColor: '#1890ff' }" />
|
|
</div>
|
|
<a-button type="text" size="small" class="document-panel__toggle">
|
|
<LeftOutlined v-if="!collapsed" />
|
|
<RightOutlined v-else />
|
|
</a-button>
|
|
</div>
|
|
|
|
<div v-show="!collapsed" class="document-panel__body">
|
|
<a-spin v-if="loading" size="small" />
|
|
<a-empty
|
|
v-else-if="documents.length === 0"
|
|
description="暂无文档"
|
|
:image="simpleImage"
|
|
/>
|
|
<div v-else class="document-panel__list">
|
|
<div
|
|
v-for="doc in documents"
|
|
:key="doc.id"
|
|
class="document-panel__item"
|
|
>
|
|
<DocumentCard :document="doc" />
|
|
<div class="document-panel__item-time">{{ formatTime(doc.created_at) }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, watch, ref } from 'vue'
|
|
import { FolderOpenOutlined, LeftOutlined, RightOutlined } from '@ant-design/icons-vue'
|
|
import { Empty } from 'ant-design-vue'
|
|
import DocumentCard from './messages/DocumentCard.vue'
|
|
import { useDocumentsStore } from '@/stores/documents'
|
|
|
|
interface Props {
|
|
conversationId: string
|
|
}
|
|
|
|
const props = defineProps<Props>()
|
|
const documentsStore = useDocumentsStore()
|
|
|
|
const collapsed = ref(false)
|
|
|
|
const documents = computed(() => documentsStore.getDocuments(props.conversationId))
|
|
const loading = computed(() => documentsStore.loadingConversations.has(props.conversationId))
|
|
|
|
const simpleImage = Empty.PRESENTED_IMAGE_SIMPLE
|
|
|
|
function toggleCollapsed() {
|
|
collapsed.value = !collapsed.value
|
|
}
|
|
|
|
function formatTime(iso: string): string {
|
|
if (!iso) return ''
|
|
const d = new Date(iso)
|
|
return d.toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' })
|
|
}
|
|
|
|
// Fetch documents when conversation changes
|
|
watch(
|
|
() => props.conversationId,
|
|
(newId) => {
|
|
if (newId) {
|
|
documentsStore.fetchDocuments(newId)
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
)
|
|
</script>
|
|
|
|
<style scoped>
|
|
.document-panel {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 280px;
|
|
border-left: 1px solid var(--border-color);
|
|
background: var(--bg-primary);
|
|
flex-shrink: 0;
|
|
transition: width var(--transition-fast);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.document-panel--collapsed {
|
|
width: 44px;
|
|
}
|
|
|
|
.document-panel__header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: var(--space-2) var(--space-3);
|
|
border-bottom: 1px solid var(--border-color);
|
|
cursor: pointer;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.document-panel__title {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--space-2);
|
|
font-size: var(--font-sm);
|
|
font-weight: var(--font-weight-medium);
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.document-panel--collapsed .document-panel__title span {
|
|
display: none;
|
|
}
|
|
|
|
.document-panel__body {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
padding: var(--space-2);
|
|
}
|
|
|
|
.document-panel__list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-2);
|
|
}
|
|
|
|
.document-panel__item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
}
|
|
|
|
.document-panel__item-time {
|
|
font-size: var(--font-xs);
|
|
color: var(--text-tertiary);
|
|
padding-left: var(--space-1);
|
|
}
|
|
</style>
|