feat(web): 更新审批中心、审计、政策制度页面及对应的业务脚本,增强前端交互逻辑

This commit is contained in:
caoxiaozhu
2026-05-15 06:57:07 +00:00
parent 344ac126b3
commit 244b3a58f7
7 changed files with 1142 additions and 325 deletions

View File

@@ -3,14 +3,17 @@ import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import ConfirmDialog from '../../components/shared/ConfirmDialog.vue'
import { useSystemState } from '../../composables/useSystemState.js'
import { useToast } from '../../composables/useToast.js'
import {
deleteKnowledgeDocument,
fetchKnowledgeDocument,
fetchKnowledgeDocumentBlob,
fetchKnowledgeLibrary,
fetchKnowledgeOnlyOfficeConfig,
uploadKnowledgeDocument
} from '../../services/knowledge.js'
import {
deleteKnowledgeDocument,
fetchKnowledgeDocument,
fetchKnowledgeDocumentBlob,
fetchLlmWikiDocumentDetail,
fetchKnowledgeLibrary,
fetchKnowledgeOnlyOfficeConfig,
syncKnowledgeDocumentToLlmWiki,
updateLlmWikiDocumentSummary,
uploadKnowledgeDocument
} from '../../services/knowledge.js'
import { loadOnlyOfficeApi } from '../../services/onlyoffice.js'
import { isManagerUser } from '../../utils/accessControl.js'
import {
@@ -97,6 +100,7 @@ export default {
const uploadInput = ref(null)
const uploading = ref(false)
const deletingId = ref('')
const ingestingId = ref('')
const deleteDialogOpen = ref(false)
const deleteTargetDocument = ref(null)
const previewLoading = ref(false)
@@ -110,6 +114,13 @@ export default {
const onlyOfficeReadyTimeoutId = ref(0)
const currentPreviewPageIndex = ref(0)
const previewDialogPanel = ref(null)
const llmWikiDialogOpen = ref(false)
const llmWikiDialogPanel = ref(null)
const llmWikiLoading = ref(false)
const llmWikiSaving = ref(false)
const llmWikiError = ref('')
const llmWikiDocument = ref(null)
const llmWikiSummaryDraft = ref('')
const isAdmin = computed(() => isManagerUser(currentUser.value))
const uploadHint = computed(() =>
@@ -275,7 +286,13 @@ export default {
closePreview()
}
}
} catch (error) {
if (options.preserveSelection && llmWikiDocument.value?.document_id) {
const exists = documents.value.some((doc) => doc.id === llmWikiDocument.value.document_id)
if (!exists) {
closeLlmWikiSummary()
}
}
} catch (error) {
emit('summary-change', { totalDocuments: 0 })
toast(error.message || '知识库加载失败。')
} finally {
@@ -314,18 +331,167 @@ export default {
}
}
async function handleDownload(document) {
try {
const blob = await fetchKnowledgeDocumentBlob(document.id, 'attachment')
triggerFileDownload(blob, document.name)
async function handleDownload(document) {
try {
const blob = await fetchKnowledgeDocumentBlob(document.id, 'attachment')
triggerFileDownload(blob, document.name)
} catch (error) {
toast(error.message || '下载失败。')
}
}
function triggerUpload() {
if (!isAdmin.value || uploading.value) {
return
}
}
function patchDocumentState(documentId, patch) {
documents.value = documents.value.map((doc) =>
doc.id === documentId ? { ...doc, ...patch } : doc
)
if (selectedDocument.value?.id === documentId) {
selectedDocument.value = {
...selectedDocument.value,
...patch
}
}
}
function resolveIngestActionLabel(document) {
if (ingestingId.value === document.id) {
return '归纳中'
}
return Number(document?.stateCode || 0) === 3 ? '重新归纳' : '归纳'
}
function resolveIngestActionTitle(document) {
const action = resolveIngestActionLabel(document)
if (action === '归纳中') {
return 'Hermes 正在将当前文档归纳到 LLM Wiki'
}
if (action === '重新归纳') {
return '重新使用 Hermes 归纳当前文档到 LLM Wiki'
}
return '使用 Hermes 归纳当前文档到 LLM Wiki'
}
function canViewLlmWiki(document) {
return isAdmin.value && Number(document?.stateCode || 0) === 3
}
function resolveViewLlmWikiTitle(document) {
if (!isAdmin.value) {
return '仅管理员可查看 LLM Wiki 归纳内容'
}
if (Number(document?.stateCode || 0) === 2) {
return 'Hermes 正在归纳当前文档,完成后可查看 LLM Wiki 知识总结'
}
if (Number(document?.stateCode || 0) === 4) {
return '当前文档上次归纳失败,请重新归纳后再查看'
}
if (Number(document?.stateCode || 0) !== 3) {
return '文档尚未完成归纳,暂无可查看的 LLM Wiki 知识总结'
}
return '查看并编辑当前文档的 LLM Wiki 归纳内容'
}
async function handleManualIngest(document) {
if (!isAdmin.value || ingestingId.value || !document?.id) {
return
}
ingestingId.value = document.id
patchDocumentState(document.id, {
stateCode: 2,
state: '正归纳',
stateTone: 'warning'
})
try {
const payload = await syncKnowledgeDocumentToLlmWiki({
folder: document.folder,
documentId: document.id
})
await loadLibrary({ preserveSelection: true })
if (selectedDocument.value?.id === document.id) {
await selectDocument(document.id)
}
toast(payload.summary || 'Hermes 已完成文档归纳。')
} catch (error) {
patchDocumentState(document.id, {
stateCode: 4,
state: '归纳失败',
stateTone: 'danger'
})
toast(error.message || 'Hermes 归纳文档失败。')
} finally {
ingestingId.value = ''
}
}
async function openLlmWikiSummary(document) {
if (!canViewLlmWiki(document) || llmWikiLoading.value || !document?.id) {
return
}
llmWikiDialogOpen.value = true
llmWikiLoading.value = true
llmWikiError.value = ''
llmWikiDocument.value = null
llmWikiSummaryDraft.value = ''
try {
const payload = await fetchLlmWikiDocumentDetail(document.id)
llmWikiDocument.value = payload
llmWikiSummaryDraft.value = payload.knowledge_summary_markdown || ''
await nextTick()
llmWikiDialogPanel.value?.focus?.()
} catch (error) {
llmWikiError.value = error.message || 'LLM Wiki 归纳内容加载失败。'
toast(llmWikiError.value)
} finally {
llmWikiLoading.value = false
}
}
function closeLlmWikiSummary() {
if (llmWikiSaving.value) {
return
}
llmWikiDialogOpen.value = false
llmWikiLoading.value = false
llmWikiError.value = ''
llmWikiDocument.value = null
llmWikiSummaryDraft.value = ''
}
async function saveLlmWikiSummary() {
if (!isAdmin.value || !llmWikiDocument.value?.document_id || llmWikiSaving.value) {
return
}
const summaryText = String(llmWikiSummaryDraft.value || '').trim()
if (!summaryText) {
toast('知识总结不能为空。')
return
}
llmWikiSaving.value = true
try {
const payload = await updateLlmWikiDocumentSummary(llmWikiDocument.value.document_id, {
knowledge_summary_markdown: summaryText
})
llmWikiDocument.value = payload
llmWikiError.value = ''
llmWikiSummaryDraft.value = payload.knowledge_summary_markdown || summaryText
toast('LLM Wiki 知识总结已保存。')
} catch (error) {
toast(error.message || 'LLM Wiki 知识总结保存失败。')
} finally {
llmWikiSaving.value = false
}
}
function triggerUpload() {
if (!isAdmin.value || uploading.value) {
return
}
uploadInput.value?.click()
}
@@ -403,6 +569,9 @@ export default {
if (selectedDocument.value?.id === document.id) {
closePreview()
}
if (llmWikiDocument.value?.document_id === document.id) {
closeLlmWikiSummary()
}
await loadLibrary()
toast('知识库文件已删除。')
} catch (error) {
@@ -431,6 +600,10 @@ export default {
}
function handleWindowKeydown(event) {
if (event.key === 'Escape' && llmWikiDialogOpen.value) {
closeLlmWikiSummary()
return
}
if (event.key === 'Escape' && selectedDocument.value) {
closePreview()
}
@@ -451,14 +624,21 @@ export default {
watch(activeFolder, () => {
closePreview()
closeLlmWikiSummary()
})
watch(
() => previewLayoutState.value.isPreviewModalOpen,
async (isPreviewModalOpen) => {
setBodyScrollLocked(isPreviewModalOpen)
() => previewLayoutState.value.isPreviewModalOpen || llmWikiDialogOpen.value,
async (isAnyOverlayOpen) => {
setBodyScrollLocked(isAnyOverlayOpen)
if (isPreviewModalOpen) {
if (llmWikiDialogOpen.value) {
await nextTick()
llmWikiDialogPanel.value?.focus?.()
return
}
if (previewLayoutState.value.isPreviewModalOpen) {
await nextTick()
previewDialogPanel.value?.focus?.()
}
@@ -483,6 +663,8 @@ export default {
changePageSize,
closePreview,
closeDeleteDialog,
closeLlmWikiSummary,
canViewLlmWiki,
confirmDeleteDocument,
excelPreviewTable,
currentPage,
@@ -490,14 +672,24 @@ export default {
deleteDialogOpen,
deleteTargetDocument,
deletingId,
documentSearch,
filteredFolders,
handleDelete,
handleDownload,
handleDrop,
handleFileInput,
isAdmin,
loading,
documentSearch,
filteredFolders,
handleDelete,
handleDownload,
handleDrop,
handleFileInput,
handleManualIngest,
ingestingId,
isAdmin,
llmWikiDialogOpen,
llmWikiDialogPanel,
llmWikiDocument,
llmWikiError,
llmWikiLoading,
llmWikiSaving,
llmWikiSummaryDraft,
loading,
openLlmWikiSummary,
pageSize,
pageSizeOpen,
pageSizes,
@@ -515,12 +707,16 @@ export default {
shouldRenderOnlyOffice,
shouldRenderOnlyOfficeHostNode,
selectDocument,
selectPreviewPage,
selectedDocument,
totalCount,
totalPages,
triggerUpload,
uploadHint,
selectPreviewPage,
selectedDocument,
resolveIngestActionLabel,
resolveIngestActionTitle,
resolveViewLlmWikiTitle,
saveLlmWikiSummary,
totalCount,
totalPages,
triggerUpload,
uploadHint,
uploadInput,
uploading,
visibleDocuments