194 lines
5.3 KiB
JavaScript
194 lines
5.3 KiB
JavaScript
import { Box, CircularProgress, Modal, Tab, Tabs, Typography } from '@mui/material';
|
||
import { useEffect, useState } from 'react';
|
||
import { EVENT_CONFIGS, EVENT_CONFIGS_MULT_DEPENDENTS } from '../constants/configEvent';
|
||
import { VALUE_TRANSFORMERS } from '../utils/transformers';
|
||
|
||
const JsonViewModal = ({ open, onClose, jsonData, eventType }) => {
|
||
const [extractedInfo, setExtractedInfo] = useState();
|
||
const [activeTab, setActiveTab] = useState(1);
|
||
|
||
const handleTabChange = (event, newValue) => {
|
||
setActiveTab(newValue);
|
||
};
|
||
|
||
useEffect(() => {
|
||
if (!open) {
|
||
setExtractedInfo(undefined);
|
||
setActiveTab(1);
|
||
}
|
||
}, [open]);
|
||
|
||
useEffect(() => {
|
||
if (!open) return;
|
||
extractInfo(jsonData, eventType).then((data) => {
|
||
setExtractedInfo(data);
|
||
});
|
||
}, [jsonData, eventType, open]);
|
||
|
||
// Основная универсальная функция
|
||
async function extractInfo(data, type) {
|
||
data = JSON.parse(data);
|
||
const config = EVENT_CONFIGS[type] || {};
|
||
const configForMultDependents = EVENT_CONFIGS_MULT_DEPENDENTS[type] || {};
|
||
const result = {};
|
||
|
||
// Функция для рекурсивного обхода всех узлов
|
||
async function traverseAndExtract(obj, path = '') {
|
||
if (!obj || typeof obj !== 'object') return;
|
||
|
||
for (const key in obj) {
|
||
const currentPath = path ? `${path}.${key}` : key;
|
||
|
||
if (config[currentPath] || config[key]) {
|
||
let value = obj[key];
|
||
const configKey = config[currentPath] || config[key];
|
||
|
||
// Применяем преобразование, если есть функция для этого ключа
|
||
if (VALUE_TRANSFORMERS[configKey] && value !== null && value !== undefined) {
|
||
try {
|
||
// Собираем зависимости для трансформера
|
||
// По умолчанию передаём только текущее значение
|
||
const dependents = [value];
|
||
|
||
// Если для этого ключа есть дополнительные зависимости (другие поля)
|
||
if (configForMultDependents[configKey] || configForMultDependents[configKey]) {
|
||
configForMultDependents[configKey].forEach((d) => {
|
||
// Добавляем значения из зависимых полей (в корне data)
|
||
dependents.push(data[d]);
|
||
});
|
||
}
|
||
|
||
const transformer = VALUE_TRANSFORMERS[configKey];
|
||
if (transformer.constructor.name === 'AsyncFunction') {
|
||
value = await transformer(...dependents);
|
||
} else {
|
||
value = transformer(...dependents);
|
||
}
|
||
} catch (error) {
|
||
console.error(`Ошибка в трансформере для ключа "${configKey}":`, error);
|
||
value = '—';
|
||
}
|
||
}
|
||
|
||
result[configKey] = value ?? '—';
|
||
}
|
||
|
||
// Если значение - объект или массив, рекурсивно обходим его
|
||
if (obj[key] && typeof obj[key] === 'object') {
|
||
await traverseAndExtract(obj[key], currentPath);
|
||
}
|
||
}
|
||
}
|
||
|
||
try {
|
||
await traverseAndExtract(data);
|
||
} catch (error) {
|
||
return JSON.stringify({ error: 'Ошибка при извлечении данных' }, null, 2);
|
||
}
|
||
|
||
return JSON.stringify(result, null, 2);
|
||
}
|
||
|
||
if (!open) return null;
|
||
|
||
return (
|
||
<Modal
|
||
open={open}
|
||
onClose={onClose}
|
||
aria-labelledby='json-view-modal'
|
||
aria-describedby='json-details-modal'
|
||
sx={{
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
}}>
|
||
<Box
|
||
sx={{
|
||
border: '1px solid #e5e7eb',
|
||
borderRadius: '0.63rem',
|
||
padding: '1.06rem 1.06rem 0.06rem',
|
||
width: 'max-content',
|
||
bgcolor: 'background.paper',
|
||
outline: 'none',
|
||
position: 'relative',
|
||
}}>
|
||
<Box
|
||
sx={{
|
||
display: 'flex',
|
||
justifyContent: 'space-between',
|
||
alignItems: 'center',
|
||
mb: '.75rem',
|
||
}}>
|
||
<Typography variant='subtitle1' sx={{ fontWeight: 'medium' }}>
|
||
Детали события:
|
||
</Typography>
|
||
</Box>
|
||
|
||
{/* Вкладки */}
|
||
<Tabs
|
||
value={activeTab}
|
||
onChange={handleTabChange}
|
||
sx={{
|
||
borderBottom: '1px solid #e5e7eb',
|
||
mb: '1rem',
|
||
'& .MuiTab-root': {
|
||
textTransform: 'none',
|
||
fontSize: '0.875rem',
|
||
},
|
||
}}>
|
||
<Tab label='Данные события' />
|
||
<Tab label='Форматированные данные события' />
|
||
</Tabs>
|
||
|
||
<Box
|
||
sx={{
|
||
maxHeight: '300px',
|
||
overflow: 'auto',
|
||
mb: '1rem',
|
||
backgroundColor: '#F9FAFB',
|
||
border: '1px solid #e5e7eb',
|
||
padding: '0.8rem',
|
||
borderRadius: '0.25rem',
|
||
}}>
|
||
{activeTab === 0 ? (
|
||
<Typography
|
||
variant='body2'
|
||
component='pre'
|
||
sx={{
|
||
fontFamily: 'monospace',
|
||
fontSize: '0.75rem',
|
||
whiteSpace: 'pre-wrap',
|
||
m: 0,
|
||
lineHeight: 1.4,
|
||
}}>
|
||
{jsonData}
|
||
</Typography>
|
||
) : (
|
||
<Box
|
||
sx={{
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
}}>
|
||
<Typography
|
||
variant='body2'
|
||
component='pre'
|
||
sx={{
|
||
fontFamily: 'monospace',
|
||
fontSize: '0.75rem',
|
||
whiteSpace: 'pre-wrap',
|
||
m: 0,
|
||
lineHeight: 1.4,
|
||
}}>
|
||
{extractedInfo || <CircularProgress />}
|
||
</Typography>
|
||
</Box>
|
||
)}
|
||
</Box>
|
||
</Box>
|
||
</Modal>
|
||
);
|
||
};
|
||
|
||
export default JsonViewModal;
|