From bc8ec9aeeacfa548e5124092c80a0104403f9b48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B9=20=D0=A1=D0=B0?= =?UTF-8?q?=D0=B1=D0=B8=D0=BB=D0=B8=D0=BD?= Date: Mon, 13 Jul 2026 17:54:25 +0300 Subject: [PATCH] =?UTF-8?q?fix(ws):=20=D0=BC=D0=B0=D1=80=D1=88=D1=80=D1=83?= =?UTF-8?q?=D1=82=D1=8B=20=D1=81=D1=83=D1=89=D0=BD=D0=BE=D1=81=D1=82=D0=B5?= =?UTF-8?q?=D0=B9=20=D0=B8=20=D0=BB=D0=BE=D0=BA=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=BD=D1=8B=D0=B5=20=D1=83=D0=B2=D0=B5?= =?UTF-8?q?=D0=B4=D0=BE=D0=BC=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Клик по WS-уведомлению ведёт на детальную страницу, тексты через i18n. Co-authored-by: Cursor --- src/layouts/AdminLayout.tsx | 54 ++++++++++++++++--------------------- src/utils/entityRoutes.ts | 14 ++++++++++ 2 files changed, 37 insertions(+), 31 deletions(-) create mode 100644 src/utils/entityRoutes.ts diff --git a/src/layouts/AdminLayout.tsx b/src/layouts/AdminLayout.tsx index ab149ea..cc0f69e 100644 --- a/src/layouts/AdminLayout.tsx +++ b/src/layouts/AdminLayout.tsx @@ -24,6 +24,8 @@ import { } from '@ant-design/icons'; import dayjs from 'dayjs'; import { MENU_ITEMS, filterMenuByRole, getMenuSelectedKey, canReceiveWsNotification } from '../config/adminAccess'; +import { getEntityDetailPath } from '../utils/entityRoutes'; +import { useTranslation } from 'react-i18next'; const { Header, Sider, Content } = Layout; const { Text } = Typography; @@ -35,6 +37,7 @@ const AdminLayout: React.FC = () => { const navigate = useNavigate(); const location = useLocation(); const { user, logout } = useAuthStore(); + const { t } = useTranslation(); const { token: { colorBgContainer } } = theme.useToken(); const [collapsed, setCollapsed] = useState(false); @@ -49,26 +52,21 @@ const AdminLayout: React.FC = () => { return; } const { report_id, target_type, target_id, reason } = msg.data || {}; + const targetPath = target_id ? getEntityDetailPath(target_type, target_id) : undefined; notification.info({ - title: 'Новая жалоба', - description: ( - - Жалоба{' '} - {report_id ? ( - { e.preventDefault(); navigate(`/reports/${report_id}`); }} style={{ fontWeight: 600 }}> - #{report_id} - - ) : ('#?')}{' '} - на {target_type || 'неизвестный тип'}{' '} - {target_id ? ( - { e.preventDefault(); navigate(`/${target_type}s/${target_id}`); }} style={{ fontWeight: 600 }}> - {target_id} - - ) : ('?')}{' '} - {reason ? `(${reason})` : ''} - - ), + key: report_id ? `report-${report_id}` : `report-${Date.now()}`, + message: t('ws.newReport'), + description: [ + report_id ? `Жалоба #${report_id}` : 'Жалоба', + target_type ? `на ${target_type}` : '', + target_id ?? '', + reason ? `(${reason})` : '', + ].filter(Boolean).join(' '), placement: 'topRight', + onClick: () => { + if (report_id) navigate(`/reports/${report_id}`); + else if (targetPath) navigate(targetPath); + }, }); } else if (msg.type === 'ticket_created') { if (!canReceiveWsNotification('ticket_created', user?.role)) { @@ -76,25 +74,19 @@ const AdminLayout: React.FC = () => { } const { ticket_id } = msg.data || {}; notification.info({ - title: 'Новый тикет', - description: ( - - Тикет{' '} - {ticket_id ? ( - { e.preventDefault(); navigate(`/tickets/${ticket_id}`); }} style={{ fontWeight: 600 }}> - #{ticket_id} - - ) : ('без ID')}{' '} - создан - - ), + key: ticket_id ? `ticket-${ticket_id}` : `ticket-${Date.now()}`, + message: t('ws.newTicket'), + description: ticket_id ? `Тикет #${ticket_id} создан` : 'Создан новый тикет', placement: 'topRight', + onClick: () => { + if (ticket_id) navigate(`/tickets/${ticket_id}`); + }, }); } }; window.addEventListener('admin-ws-message', handler as EventListener); return () => window.removeEventListener('admin-ws-message', handler as EventListener); - }, [navigate, user?.role]); + }, [navigate, user?.role, t]); const onlineNodes = React.useMemo(() => { const cutoff = dayjs().subtract(NODE_STATS_THRESHOLD, 'minute'); diff --git a/src/utils/entityRoutes.ts b/src/utils/entityRoutes.ts new file mode 100644 index 0000000..d55916f --- /dev/null +++ b/src/utils/entityRoutes.ts @@ -0,0 +1,14 @@ +/** Маршруты к сущностям по target_type (жалобы, WS-уведомления). */ +const ENTITY_PATH: Record = { + event: 'events', + calendar: 'calendars', + review: 'reviews', + user: 'users', + report: 'reports', + ticket: 'tickets', +}; + +export function getEntityDetailPath(type: string | undefined, id: string): string { + const segment = type ? ENTITY_PATH[type] ?? `${type}s` : 'unknown'; + return `/${segment}/${id}`; +}