| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- 'use client'
- import { useEffect, useState } from 'react'
- import { useTranslation } from 'react-i18next'
- import Modal from '@/app/components/base/modal'
- import Button from '@/app/components/base/button'
- import Loading from '@/app/components/base/loading'
- import { fetchDownloadLogs } from '@/service/datasets'
- import { useToastContext } from '@/app/components/base/toast'
- type DownloadLog = {
- user_id: string
- user_name: string
- download_time: string
- ip: string
- }
- type DownloadLogsModalProps = {
- datasetId: string
- documentId: string
- documentName: string
- onClose: () => void
- }
- const DownloadLogsModal = ({
- datasetId,
- documentId,
- documentName,
- onClose,
- }: DownloadLogsModalProps) => {
- const { t } = useTranslation()
- const { notify } = useToastContext()
- const [loading, setLoading] = useState(true)
- const [logs, setLogs] = useState<DownloadLog[]>([])
- const [total, setTotal] = useState(0)
- const [uniqueUsers, setUniqueUsers] = useState(0)
- useEffect(() => {
- loadLogs()
- }, [])
- const loadLogs = async () => {
- try {
- const data = await fetchDownloadLogs(datasetId, documentId)
- setLogs(data.logs)
- setTotal(data.total)
- setUniqueUsers(data.unique_users)
- }
- catch (error) {
- notify({ type: 'error', message: t('common.actionMsg.loadFailed') })
- }
- finally {
- setLoading(false)
- }
- }
- return (
- <Modal
- isShow
- onClose={onClose}
- title={
- <div>
- <div className="text-lg font-semibold text-gray-900">
- {t('dataset.downloadLogs.title')}
- </div>
- <div className="text-sm font-normal text-gray-500 mt-1 truncate max-w-[600px]">
- {documentName}
- </div>
- </div>
- }
- className="w-[900px]"
- >
- {loading
- ? (
- <div className="flex items-center justify-center py-12">
- <Loading />
- </div>
- )
- : (
- <>
- {/* Statistics cards */}
- <div className="grid grid-cols-2 gap-4 mb-4">
- <div className="bg-gradient-to-br from-blue-50 to-blue-100 rounded-lg p-4">
- <div className="text-sm text-blue-600 font-medium">
- {t('dataset.downloadLogs.totalDownloads')}
- </div>
- <div className="text-2xl font-bold text-blue-900 mt-1">
- {total}
- </div>
- </div>
- <div className="bg-gradient-to-br from-green-50 to-green-100 rounded-lg p-4">
- <div className="text-sm text-green-600 font-medium">
- {t('dataset.downloadLogs.uniqueUsers')}
- </div>
- <div className="text-2xl font-bold text-green-900 mt-1">
- {uniqueUsers}
- </div>
- </div>
- </div>
- {/* Download logs table */}
- <div className="border border-gray-200 rounded-lg">
- <div className="bg-gray-50 px-4 py-3 border-b border-gray-200">
- <div className="grid grid-cols-12 gap-4 text-xs font-medium text-gray-700">
- <div className="col-span-3">{t('dataset.downloadLogs.user')}</div>
- <div className="col-span-5">{t('dataset.downloadLogs.time')}</div>
- <div className="col-span-4">{t('dataset.downloadLogs.ip')}</div>
- </div>
- </div>
- <div className="max-h-[500px] overflow-y-auto">
- {logs.length === 0
- ? (
- <div className="py-12 text-center text-sm text-gray-500">
- {t('dataset.downloadLogs.noData')}
- </div>
- )
- : (
- <div className="divide-y divide-gray-100">
- {logs.map((log, index) => (
- <div
- key={index}
- className="grid grid-cols-12 gap-4 px-4 py-3 hover:bg-gray-50 transition-colors"
- >
- <div className="col-span-3">
- <div className="text-sm font-medium text-gray-900 truncate">
- {log.user_name}
- </div>
- </div>
- <div className="col-span-5">
- <div className="text-sm text-gray-700">
- {log.download_time}
- </div>
- </div>
- <div className="col-span-4">
- <div className="text-sm text-gray-500 font-mono">
- {log.ip}
- </div>
- </div>
- </div>
- ))}
- </div>
- )}
- </div>
- </div>
- {/* Footer */}
- <div className="flex justify-end pt-4 border-t border-gray-200 mt-4">
- <Button onClick={onClose}>
- {t('common.operation.close')}
- </Button>
- </div>
- </>
- )}
- </Modal>
- )
- }
- export default DownloadLogsModal
|