feat / AEB-65 generate reports

This commit is contained in:
Timofey
2025-10-07 15:24:22 +03:00
parent 497cd7e292
commit 6e43a8afed
11 changed files with 289 additions and 33 deletions

View File

@@ -7,17 +7,18 @@ import useNavigationStore from '../../store/navigationStore'
import ReportsList from '../../../components/reports/ReportsList'
import ExportMenu from '../../../components/ui/ExportMenu'
import detectorsData from '../../../data/detectors.json'
import axios from 'axios'
const ReportsPage: React.FC = () => {
const router = useRouter()
const searchParams = useSearchParams()
const { currentObject, setCurrentObject } = useNavigationStore()
const urlObjectId = searchParams.get('objectId')
const urlObjectTitle = searchParams.get('objectTitle')
const objectId = currentObject.id || urlObjectId
const objectTitle = currentObject.title || urlObjectTitle
useEffect(() => {
if (urlObjectId && urlObjectTitle && (!currentObject.id || currentObject.id !== urlObjectId)) {
setCurrentObject(urlObjectId, urlObjectTitle)
@@ -28,27 +29,60 @@ const ReportsPage: React.FC = () => {
router.push('/dashboard')
}
const handleExport = (format: 'csv' | 'pdf') => {
// TODO: добавить функционал по экспорту отчетов
console.log(`Exporting reports as ${format}`)
const handleExport = async (format: 'csv' | 'pdf') => {
try {
const response = await axios.post(
`${process.env.NEXT_PUBLIC_API_URL}/account/get-reports/`,
{ report_format: format },
{
responseType: 'blob',
headers: {
'Content-Type': 'application/json',
},
}
)
const contentDisposition = response.headers['content-disposition']
const filenameMatch = contentDisposition?.match(/filename="(.+)"/)
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').replace(/T/g, '_')
const filename = filenameMatch ? filenameMatch[1] : `alerts_report_${timestamp}.${format}`
const url = window.URL.createObjectURL(new Blob([response.data]))
const link = document.createElement('a')
link.href = url
link.download = filename
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
window.URL.revokeObjectURL(url)
} catch (error) {
console.error('Error:', error)
}
}
return (
<div className="flex h-screen bg-[#0e111a]">
<Sidebar
activeItem={9} // Reports
/>
<div className="flex-1 flex flex-col">
<header className="bg-[#161824] border-b border-gray-700 px-6 py-4">
<div className="flex h-screen bg-[#0e111a]">
<Sidebar
activeItem={9} // Reports
/>
<div className="flex flex-1 flex-col">
<header className="border-b border-gray-700 bg-[#161824] px-6 py-4">
<div className="flex items-center gap-4">
<button
<button
onClick={handleBackClick}
className="text-gray-400 hover:text-white transition-colors"
className="text-gray-400 transition-colors hover:text-white"
aria-label="Назад к дашборду"
>
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
<svg className="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M15 19l-7-7 7-7"
/>
</svg>
</button>
<nav className="flex items-center gap-2 text-sm">
@@ -60,19 +94,16 @@ const ReportsPage: React.FC = () => {
</nav>
</div>
</header>
<div className="flex-1 p-6 overflow-auto">
<div className="flex-1 overflow-auto p-6">
<div className="mb-6">
<div className="flex items-center justify-between mb-6">
<h1 className="text-white text-2xl font-semibold">Отчеты по датчикам</h1>
<div className="mb-6 flex items-center justify-between">
<h1 className="text-2xl font-semibold text-white">Отчеты по датчикам</h1>
<ExportMenu onExport={handleExport} />
</div>
<ReportsList
objectId={objectId || undefined}
detectorsData={detectorsData}
/>
<ReportsList objectId={objectId || undefined} detectorsData={detectorsData} />
</div>
</div>
</div>
@@ -80,4 +111,4 @@ const ReportsPage: React.FC = () => {
)
}
export default ReportsPage
export default ReportsPage

View File

@@ -11,7 +11,7 @@
"@babylonjs/core": "^6.44.0",
"@babylonjs/loaders": "^6.49.0",
"@tanstack/react-query": "^5.85.5",
"axios": "^1.11.0",
"axios": "^1.12.2",
"next": "^15.4.3",
"next-auth": "^4.24.11",
"react": "^19.1.0",
@@ -3366,6 +3366,7 @@
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9",

View File

@@ -12,7 +12,7 @@
"@babylonjs/core": "^6.44.0",
"@babylonjs/loaders": "^6.49.0",
"@tanstack/react-query": "^5.85.5",
"axios": "^1.11.0",
"axios": "^1.12.2",
"next": "^15.4.3",
"next-auth": "^4.24.11",
"react": "^19.1.0",