'use client' import type { FC } from 'react' import { useState } from 'react' import { RiFileHistoryLine, RiFilterLine, RiRefreshLine, } from '@remixicon/react' import Modal from '@/app/components/base/modal' import Button from '@/app/components/base/button' import { DocumentOperationType } from '@/models/operation-log' import type { OperationLog, OperationLogQueryParams } from '@/models/operation-log' import { useDocumentOperationLogs } from '@/service/knowledge/use-operation-log' import Loading from '@/app/components/base/loading' type OperationLogsModalProps = { isOpen: boolean onClose: () => void datasetId: string documentId: string documentName: string } const OperationLogsModal: FC = ({ isOpen, onClose, datasetId, documentId, documentName, }) => { const [params, setParams] = useState({ page: 1, per_page: 20, }) const { data, isLoading, refetch } = useDocumentOperationLogs( datasetId, documentId, params, ) const [actionFilter, setActionFilter] = useState('') const handleFilterByAction = (action: string) => { const newAction = action === actionFilter ? '' : action setActionFilter(newAction) setParams({ ...params, action: newAction || undefined, page: 1, }) } const handlePageChange = (page: number) => { setParams({ ...params, page }) } const getOperationTypeLabel = (action: string) => { const labels: Record = { [DocumentOperationType.DOCUMENT_ENABLE]: '启用', [DocumentOperationType.DOCUMENT_DISABLE]: '禁用', [DocumentOperationType.DOCUMENT_ARCHIVE]: '归档', [DocumentOperationType.DOCUMENT_UNARCHIVE]: '取消归档', [DocumentOperationType.DOCUMENT_BATCH_ENABLE]: '批量启用', [DocumentOperationType.DOCUMENT_BATCH_DISABLE]: '批量禁用', [DocumentOperationType.DOCUMENT_BATCH_ARCHIVE]: '批量归档', [DocumentOperationType.DOCUMENT_BATCH_UNARCHIVE]: '批量取消归档', [DocumentOperationType.DOCUMENT_SCHEDULE_CREATE]: '创建定时任务', [DocumentOperationType.DOCUMENT_SCHEDULE_CANCEL]: '取消定时任务', [DocumentOperationType.DOCUMENT_SCHEDULE_EXECUTE]: '执行定时任务', [DocumentOperationType.DOCUMENT_CREATE]: '创建', [DocumentOperationType.DOCUMENT_UPDATE]: '更新', [DocumentOperationType.DOCUMENT_DELETE]: '删除', [DocumentOperationType.DOCUMENT_RENAME]: '重命名', } return labels[action] || action } const getOperationTypeBadge = (action: string) => { const config: Record = { [DocumentOperationType.DOCUMENT_ENABLE]: { bg: 'bg-util-colors-teal-teal-100', text: 'text-util-colors-teal-teal-600' }, [DocumentOperationType.DOCUMENT_DISABLE]: { bg: 'bg-util-colors-orange-orange-100', text: 'text-util-colors-orange-orange-600' }, [DocumentOperationType.DOCUMENT_ARCHIVE]: { bg: 'bg-util-colors-gray-gray-100', text: 'text-util-colors-gray-gray-600' }, [DocumentOperationType.DOCUMENT_SCHEDULE_CREATE]: { bg: 'bg-util-colors-blue-blue-100', text: 'text-util-colors-blue-blue-600' }, [DocumentOperationType.DOCUMENT_SCHEDULE_EXECUTE]: { bg: 'bg-util-colors-purple-purple-100', text: 'text-util-colors-purple-purple-600' }, } const style = config[action] || { bg: 'bg-util-colors-gray-gray-100', text: 'text-util-colors-gray-gray-600' } return ( {getOperationTypeLabel(action)} ) } const renderChangesSummary = (log: OperationLog) => { const { changes, metadata } = log.content if (!changes && !metadata) return null return (
{changes && (
{changes.old && (
修改前: {JSON.stringify(changes.old)}
)} {changes.new && (
修改后: {JSON.stringify(changes.new)}
)}
)} {metadata?.scheduled && (
定时执行 {metadata.schedule_id && ( ID: {metadata.schedule_id.substring(0, 16)}... )}
)} {metadata?.batch && (
批量操作: {metadata.batch_size} 个文档
)}
) } const logs = data?.logs || [] const hasLogs = logs.length > 0 // Quick action filters const quickFilters = [ DocumentOperationType.DOCUMENT_ENABLE, DocumentOperationType.DOCUMENT_DISABLE, DocumentOperationType.DOCUMENT_ARCHIVE, DocumentOperationType.DOCUMENT_SCHEDULE_CREATE, DocumentOperationType.DOCUMENT_SCHEDULE_EXECUTE, ] return ( 操作历史 } className="!w-[800px] !max-w-[90vw]" >
{/* Document Name */}
文档: {documentName}
{/* Toolbar */}
{/* Quick Filters */}
快速筛选:
{quickFilters.map(action => ( ))} {actionFilter && ( )}
{/* Refresh Button */}
{/* Logs List */}
{isLoading ? (
) : !hasLogs ? (
暂无操作历史
) : (
{logs.map((log: OperationLog) => (
{/* Operation Type */}
{getOperationTypeBadge(log.action)}
{/* Timestamp */}
{new Date(log.created_at).toLocaleString('zh-CN')}
{/* IP Address */}
来自: {log.created_ip}
{/* Changes Summary */} {renderChangesSummary(log)}
))}
)}
{/* Pagination */} {data && data.total > params.per_page! && (
显示 {(params.page! - 1) * params.per_page! + 1}-{Math.min(params.page! * params.per_page!, data.total)} 条,共 {data.total} 条
{params.page} / {data.pages}
)}
{/* Footer */}
) } export default OperationLogsModal