Files
X-Financial/web/src/views/PoliciesView.vue

303 lines
13 KiB
Vue
Raw Normal View History

<template>
<section class="knowledge-page">
<div class="knowledge-grid" :class="{ 'has-preview': previewLayoutState.usesSplitLayout }">
<section class="knowledge-main">
<article class="library-panel panel">
<header class="panel-title">
<div>
<h2>文档库 / 文件夹</h2>
<p>默认展示文件列表点击具体文件后以弹窗方式展开预览</p>
</div>
<label class="file-search">
<i class="mdi mdi-magnify"></i>
<input v-model="documentSearch" type="search" placeholder="搜索当前文件夹内文件" />
</label>
</header>
<div class="library-body">
<aside class="folder-rail">
<nav class="folder-tree" aria-label="知识库文件夹">
<button
v-for="folder in filteredFolders"
:key="folder.name"
type="button"
:class="{ active: activeFolder === folder.name }"
@click="activeFolder = folder.name"
>
<i :class="folder.icon"></i>
<span>{{ folder.name }}</span>
<b>{{ folder.count }}</b>
</button>
</nav>
<button class="new-folder-btn fixed" type="button" disabled>
<i class="mdi mdi-lock-outline"></i>
<span>固定文件夹</span>
</button>
</aside>
<section class="document-area" :class="{ 'read-only': !isAdmin }">
<div
v-if="isAdmin"
class="upload-zone"
:class="{ busy: uploading }"
@click="triggerUpload"
@dragover.prevent
@drop.prevent="handleDrop"
>
<input
ref="uploadInput"
class="upload-input"
type="file"
multiple
@change="handleFileInput"
/>
<i class="mdi mdi-cloud-upload"></i>
<strong>{{ uploading ? '正在上传文件...' : '拖拽文档到此处,或点击上传' }}</strong>
<span>{{ uploadHint }}</span>
</div>
<div class="doc-table-wrap">
<table>
<thead>
<tr>
<th>文件名称</th>
<th>标签</th>
<th>上传时间 <i class="mdi mdi-arrow-down"></i></th>
<th>版本</th>
<th>状态</th>
<th>上传人</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr
v-for="doc in visibleDocuments"
:key="doc.id"
class="doc-row"
:class="{ selected: selectedDocument?.id === doc.id }"
@click="selectDocument(doc.id)"
>
<td>
<span class="file-name">
<i :class="doc.icon"></i>
{{ doc.name }}
</span>
</td>
<td>
<span class="doc-tag">{{ doc.tag }}</span>
</td>
<td>{{ doc.time }}</td>
<td>{{ doc.version }}</td>
<td><span class="state-tag" :class="doc.stateTone">{{ doc.state }}</span></td>
<td>{{ doc.owner }}</td>
<td>
<div class="row-actions" @click.stop>
<button class="more-btn" type="button" aria-label="下载文件" @click="handleDownload(doc)">
<i class="mdi mdi-download"></i>
</button>
<button
v-if="isAdmin"
class="more-btn danger"
type="button"
:disabled="deletingId === doc.id"
aria-label="删除文件"
@click="handleDelete(doc)"
>
<i class="mdi mdi-delete-outline"></i>
</button>
</div>
</td>
</tr>
<tr v-if="!visibleDocuments.length">
<td colspan="7" class="empty-row">
{{ loading ? '正在加载知识库文件...' : '当前文件夹暂无文件' }}
</td>
</tr>
</tbody>
</table>
</div>
<footer class="list-foot">
<span class="page-summary"> {{ totalCount }} 目前第 {{ currentPage }} </span>
<div class="pager" aria-label="分页">
<button class="page-nav" type="button" :disabled="currentPage === 1" aria-label="上一页" @click="currentPage--">
<i class="mdi mdi-chevron-left"></i>
</button>
<button
v-for="page in totalPages"
:key="page"
class="page-number"
:class="{ active: currentPage === page }"
type="button"
:aria-current="currentPage === page ? 'page' : undefined"
@click="currentPage = page"
>
{{ page }}
</button>
<button class="page-nav" type="button" :disabled="currentPage === totalPages" aria-label="下一页" @click="currentPage++">
<i class="mdi mdi-chevron-right"></i>
</button>
</div>
<div class="page-size-wrap">
<button class="page-size" type="button" @click="pageSizeOpen = !pageSizeOpen">
{{ pageSize }} /<i class="mdi mdi-chevron-down"></i>
</button>
<div v-if="pageSizeOpen" class="page-size-dropdown" role="listbox">
<button
v-for="size in pageSizes"
:key="size"
type="button"
role="option"
:aria-selected="pageSize === size"
:class="{ active: pageSize === size }"
@click="changePageSize(size)"
>
{{ size }} /
</button>
</div>
</div>
</footer>
</section>
</div>
</article>
</section>
<Teleport to="body">
<Transition name="preview-modal">
<div
v-if="previewLayoutState.isPreviewModalOpen"
class="preview-modal-overlay"
role="presentation"
@click.self="closePreview"
>
<aside class="preview-modal-shell" role="dialog" aria-modal="true" aria-labelledby="knowledge-preview-title">
<article
ref="previewDialogPanel"
class="preview-panel preview-modal-panel panel"
tabindex="-1"
@click.stop
>
<header class="preview-head">
<div class="preview-copy">
<h2 id="knowledge-preview-title">{{ selectedDocument.name }}</h2>
<p class="preview-summary-line">
<span v-for="part in previewMetaLine" :key="part">{{ part }}</span>
</p>
<div v-if="previewSecondaryMetaLine.length" class="preview-secondary-line">
<span v-for="part in previewSecondaryMetaLine" :key="part">{{ part }}</span>
</div>
</div>
<div class="preview-actions">
<button type="button" class="mini-action" @click="handleDownload(selectedDocument)">
<i class="mdi mdi-download"></i>
<span>下载</span>
</button>
<button type="button" class="icon-action" aria-label="关闭预览" @click="closePreview">
<i class="mdi mdi-close"></i>
</button>
</div>
</header>
<div class="preview-viewer">
<div v-if="shouldRenderOnlyOffice" class="onlyoffice-preview-wrap">
<div
v-if="shouldRenderOnlyOfficeHostNode"
:id="onlyOfficeHostId"
class="onlyoffice-preview-host"
></div>
<div v-if="onlyOfficeLoading" class="preview-status preview-status-overlay">
正在加载 ONLYOFFICE 预览...
</div>
<div v-else-if="onlyOfficeError" class="preview-status error preview-status-overlay">
{{ onlyOfficeError }}
</div>
</div>
<div v-else-if="previewLoading" class="preview-status">正在加载预览...</div>
<div v-else-if="previewError" class="preview-status error">{{ previewError }}</div>
<div v-else-if="previewMode === 'pdf' && previewBlobUrl" class="preview-embed-wrap">
<iframe :src="previewBlobUrl" class="preview-embed" title="PDF 预览"></iframe>
</div>
<div v-else-if="previewMode === 'image' && previewBlobUrl" class="preview-image-wrap">
<img :src="previewBlobUrl" :alt="selectedDocument.name" class="preview-image" />
</div>
<div v-else-if="previewMode === 'table'" class="excel-preview-wrap">
<div v-if="selectedDocument.previewPages.length > 1" class="excel-sheet-tabs" role="tablist" aria-label="Excel 工作表页签">
<button
v-for="(page, index) in selectedDocument.previewPages"
:key="`${selectedDocument.id}-sheet-${index}`"
type="button"
class="excel-sheet-tab"
:class="{ active: currentPreviewPageIndex === index }"
:aria-selected="currentPreviewPageIndex === index"
@click="selectPreviewPage(index)"
>
{{ page.title }}
</button>
</div>
<div v-if="excelPreviewTable.headers.length" class="excel-preview-scroll">
<table class="excel-preview-table">
<thead>
<tr>
<th v-for="header in excelPreviewTable.headers" :key="header">{{ header }}</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, rowIndex) in excelPreviewTable.rows" :key="`row-${rowIndex}`">
<td v-for="(cell, cellIndex) in row" :key="`cell-${rowIndex}-${cellIndex}`">{{ cell }}</td>
</tr>
</tbody>
</table>
</div>
<div v-else class="preview-status">当前表格暂未提取到可展示内容</div>
</div>
<div v-else class="page-stage">
<article
v-for="(page, index) in selectedDocument.previewPages"
:key="`${selectedDocument.id}-${index}`"
class="page-sheet"
:style="{ '--page-delay': `${index * 70}ms` }"
>
<section class="page-content">
<div v-for="block in page.blocks" :key="block.heading" class="content-block">
<h3>{{ block.heading }}</h3>
<ul>
<li v-for="line in block.lines" :key="line">{{ line }}</li>
</ul>
</div>
</section>
</article>
<div v-if="!selectedDocument.previewPages.length" class="preview-status">
当前文件暂未生成结构化预览请下载后查看
</div>
</div>
</div>
</article>
</aside>
</div>
</Transition>
</Teleport>
</div>
<ConfirmDialog
:open="deleteDialogOpen"
badge="删除文件"
badge-tone="danger"
:title="`确认删除文件“${deleteTargetDocument?.name || ''}”吗?`"
description="删除后该知识库文件及其当前版本记录将不可恢复,请确认本次操作。"
cancel-text="取消"
confirm-text="确认删除"
busy-text="删除中..."
confirm-tone="danger"
confirm-icon="mdi mdi-delete-outline"
:busy="Boolean(deletingId)"
@close="closeDeleteDialog"
@confirm="confirmDeleteDocument"
/>
</section>
</template>
<script src="./scripts/PoliciesView.js"></script>
<style scoped src="../assets/styles/views/policies-view.css"></style>