Add support for file attachments in equipment status changes
- Introduced functionality for uploading and managing attachments in the ChangeEquipmentStatus module. - Added new endpoints for uploading and deleting attachments, as well as for downloading them. - Updated the ChangeEquipmentStatusService to handle attachment storage and retrieval using the new storage service methods. - Enhanced the ChangeEquipmentStatusEdit and ChangeEquipmentStatusShow components to support attachment input and display. - Removed deprecated attachment handling from Equipment module to streamline functionality. - Updated Prisma schema to reflect changes in attachment management.
This commit is contained in:
@@ -2,7 +2,6 @@ import Alert from '@mui/material/Alert';
|
||||
import Box from '@mui/material/Box';
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
import CssBaseline from '@mui/material/CssBaseline';
|
||||
import Link from '@mui/material/Link';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import Table from '@mui/material/Table';
|
||||
import TableBody from '@mui/material/TableBody';
|
||||
@@ -11,12 +10,12 @@ import TableContainer from '@mui/material/TableContainer';
|
||||
import TableHead from '@mui/material/TableHead';
|
||||
import TableRow from '@mui/material/TableRow';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { ThemeProvider, createTheme } from '@mui/material/styles';
|
||||
import { ThemeProvider } from '@mui/material/styles';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useEmbeddedParentTheme } from '../embed/useEmbeddedParentTheme';
|
||||
import { buildToirMuiTheme } from '../theme/toirMuiTheme';
|
||||
import { env } from '../config/env';
|
||||
import { ensureFreshToken, getAccessToken } from '../auth/keycloak';
|
||||
import { downloadEquipmentAttachmentFile } from '../resources/equipment/attachmentDownload';
|
||||
|
||||
type EquipmentRecord = {
|
||||
id: string;
|
||||
@@ -24,10 +23,6 @@ type EquipmentRecord = {
|
||||
serialNumber: string;
|
||||
dateOfInspection: string | null;
|
||||
commissionedAt: string | null;
|
||||
attachment?: {
|
||||
objectKey?: string;
|
||||
originalFileName?: string | null;
|
||||
} | null;
|
||||
};
|
||||
|
||||
function formatDate(value: string | null) {
|
||||
@@ -46,19 +41,7 @@ function formatDate(value: string | null) {
|
||||
export function EmbeddedActiveEquipmentPage() {
|
||||
const paletteMode = useEmbeddedParentTheme();
|
||||
const muiTheme = useMemo(
|
||||
() =>
|
||||
createTheme({
|
||||
palette: { mode: paletteMode },
|
||||
components: {
|
||||
MuiPaper: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundImage: 'none',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
() => buildToirMuiTheme(paletteMode),
|
||||
[paletteMode],
|
||||
);
|
||||
|
||||
@@ -132,13 +115,6 @@ export function EmbeddedActiveEquipmentPage() {
|
||||
};
|
||||
}, []);
|
||||
|
||||
const pageBg =
|
||||
paletteMode === 'dark' ? 'linear-gradient(180deg, #0d1117 0%, #0a0c10 100%)' : '#f3f6fa';
|
||||
const headerBg = paletteMode === 'dark' ? '#161b22' : '#fff';
|
||||
const headerBorder = paletteMode === 'dark' ? '1px solid #30363d' : '1px solid #d7e0ea';
|
||||
const titleColor = paletteMode === 'dark' ? '#e6edf3' : '#10233a';
|
||||
const subtitleColor = paletteMode === 'dark' ? '#8b949e' : '#5b7087';
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={muiTheme}>
|
||||
<CssBaseline />
|
||||
@@ -147,23 +123,34 @@ export function EmbeddedActiveEquipmentPage() {
|
||||
minHeight: '100vh',
|
||||
boxSizing: 'border-box',
|
||||
p: { xs: 2, md: 3 },
|
||||
bgcolor: pageBg,
|
||||
background:
|
||||
paletteMode === 'dark'
|
||||
? 'radial-gradient(circle at 10% 10%, rgba(201, 122, 61, 0.18), transparent 40%), radial-gradient(circle at 90% 90%, rgba(212, 165, 116, 0.14), transparent 42%), #0a0d12'
|
||||
: 'radial-gradient(circle at 12% 12%, rgba(182, 130, 81, 0.20), transparent 42%), radial-gradient(circle at 88% 88%, rgba(214, 188, 157, 0.26), transparent 44%), #f7f0e5',
|
||||
}}
|
||||
>
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
overflow: 'hidden',
|
||||
borderRadius: 3,
|
||||
border: headerBorder,
|
||||
bgcolor: paletteMode === 'dark' ? '#161b22' : '#fff',
|
||||
borderRadius: 4,
|
||||
}}
|
||||
>
|
||||
<Box sx={{ px: 3, py: 2, borderBottom: headerBorder, bgcolor: headerBg }}>
|
||||
<Typography variant="h5" sx={{ fontWeight: 700, color: titleColor }}>
|
||||
<Box
|
||||
sx={{
|
||||
px: 3,
|
||||
py: 2.25,
|
||||
borderBottom: (theme) => `1px solid ${theme.palette.divider}`,
|
||||
background:
|
||||
paletteMode === 'dark'
|
||||
? 'linear-gradient(145deg, rgba(255,255,255,0.06), rgba(0,0,0,0.1))'
|
||||
: 'linear-gradient(145deg, rgba(255,255,255,0.9), rgba(255,255,255,0.62))',
|
||||
}}
|
||||
>
|
||||
<Typography variant="h5" sx={{ fontWeight: 600, letterSpacing: '-0.02em' }}>
|
||||
Оборудование в эксплуатации
|
||||
</Typography>
|
||||
<Typography variant="body2" sx={{ mt: 0.5, color: subtitleColor }}>
|
||||
<Typography variant="body2" sx={{ mt: 0.5, opacity: 0.85 }}>
|
||||
Отображаются записи со статусом 'Active'
|
||||
{typeof total === 'number' ? `: ${total}` : ''}
|
||||
</Typography>
|
||||
@@ -186,7 +173,6 @@ export function EmbeddedActiveEquipmentPage() {
|
||||
<TableCell sx={{ fontWeight: 700 }}>Заводской номер</TableCell>
|
||||
<TableCell sx={{ fontWeight: 700 }}>Дата изготовления</TableCell>
|
||||
<TableCell sx={{ fontWeight: 700 }}>Дата поверки</TableCell>
|
||||
<TableCell sx={{ fontWeight: 700 }}>Файл</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
@@ -196,26 +182,6 @@ export function EmbeddedActiveEquipmentPage() {
|
||||
<TableCell>{item.serialNumber}</TableCell>
|
||||
<TableCell>{formatDate(item.commissionedAt)}</TableCell>
|
||||
<TableCell>{formatDate(item.dateOfInspection)}</TableCell>
|
||||
<TableCell>
|
||||
{item?.attachment?.objectKey ? (
|
||||
<Link
|
||||
component="button"
|
||||
type="button"
|
||||
underline="hover"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const label = item.attachment?.originalFileName?.trim() || 'файл';
|
||||
void downloadEquipmentAttachmentFile(item.id, label).catch(() => {});
|
||||
}}
|
||||
sx={{ cursor: 'pointer', verticalAlign: 'inherit' }}
|
||||
>
|
||||
{item.attachment?.originalFileName?.trim() || 'Скачать'}
|
||||
</Link>
|
||||
) : (
|
||||
'—'
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
|
||||
Reference in New Issue
Block a user