From 558cf8eaba69f05554548a4c319c566f4eec56a0 Mon Sep 17 00:00:00 2001 From: DmitriyA Date: Tue, 21 Oct 2025 09:14:20 -0400 Subject: [PATCH] added formula --- .../SettingsComponents/FormulaEditor.jsx | 482 ++++++++++++++++++ src/Components/Layout/SettingsModal.jsx | 21 +- 2 files changed, 502 insertions(+), 1 deletion(-) create mode 100644 src/Components/Layout/SettingsComponents/FormulaEditor.jsx diff --git a/src/Components/Layout/SettingsComponents/FormulaEditor.jsx b/src/Components/Layout/SettingsComponents/FormulaEditor.jsx new file mode 100644 index 0000000..206a843 --- /dev/null +++ b/src/Components/Layout/SettingsComponents/FormulaEditor.jsx @@ -0,0 +1,482 @@ +import React, { useState, useEffect, useCallback } from 'react'; +import { + TextField, Box, Typography, IconButton, Divider, + CircularProgress, Alert, Collapse, Tooltip, Button, + Card, CardContent, Chip, Dialog, DialogTitle, + DialogContent, DialogActions, Snackbar +} from '@mui/material'; +import RefreshIcon from '@mui/icons-material/Refresh'; +import SearchIcon from '@mui/icons-material/Search'; +import EditIcon from '@mui/icons-material/Edit'; +import SaveIcon from '@mui/icons-material/Save'; +import axios from 'axios'; + +const FormulaItem = React.memo(({ data, onEdit }) => { + const formatValue = (value) => { + if (typeof value === 'object' && value !== null) { + return JSON.stringify(value, null, 2); + } + return String(value); + }; + + const getValueColor = (value) => { + if (typeof value === 'boolean') return 'primary'; + if (typeof value === 'number') return 'secondary'; + if (value === null) return 'default'; + return 'info'; + }; + + return ( + + + + + ID: {data.id || 'Без ID'} + + + + + + {data.data.name} + + + + {data.data.desription} + + + + + Параметры: + + + + + + {JSON.stringify(data.data.values?.statusarr, null, 2)} + + + + + + + {JSON.stringify(data.data.values?.warr, null, 2)} + + + + + + + {data.data.formula} + + + + + + + + + + + ); +}); + +const EditFormulaDialog = ({ open, formula, onClose, onSave }) => { + const [editedFormula, setEditedFormula] = useState(''); + + useEffect(() => { + if (formula) { + setEditedFormula(formula.data.formula || ''); + } + }, [formula]); + + const handleSave = () => { + if (formula && editedFormula.trim()) { + onSave(formula.id, editedFormula.trim()); + } + }; + + return ( + + + Редактирование формулы: {formula?.data.name} + + + + {formula?.data.desription} + + + + + Доступные переменные: + + + + + + + + setEditedFormula(e.target.value)} + multiline + rows={6} + fullWidth + variant="outlined" + placeholder="Введите формулу..." + sx={{ mt: 2 }} + /> + + + + + + + ); +}; + +const FormulaEditor = () => { + const [formulas, setFormulas] = useState([]); + const [filter, setFilter] = useState(''); + const [formulaId, setFormulaId] = useState(''); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [refreshing, setRefreshing] = useState(false); + const [editingFormula, setEditingFormula] = useState(null); + const [saveLoading, setSaveLoading] = useState(false); + const [snackbar, setSnackbar] = useState({ open: false, message: '', severity: 'success' }); + + const showSnackbar = (message, severity = 'success') => { + setSnackbar({ open: true, message, severity }); + }; + + const loadFormulas = useCallback(async (id = null) => { + try { + setLoading(true); + setError(null); + + const targetId = id || formulaId; + const res = await axios.get(`http://192.168.2.39:3000/api/formula/7777/options`); + + console.log('Полученные данные:', res.data); + + let formattedData; + + if (Array.isArray(res.data)) { + formattedData = res.data.map((item, index) => ({ + id: item.id || `formula_${index + 1}`, + data: item + })); + } else if (typeof res.data === 'object' && res.data !== null) { + formattedData = [{ + id: targetId, + data: res.data + }]; + } else { + formattedData = [{ + id: targetId, + data: { value: res.data } + }]; + } + + console.log('Форматированные данные:', formattedData); + setFormulas(formattedData); + + } catch (err) { + console.error('Ошибка при загрузке формул:', err); + setError(`Ошибка загрузки: ${err.message}`); + } finally { + setLoading(false); + setRefreshing(false); + } + }, [formulaId]); + + const handleEditFormula = (formula) => { + setEditingFormula(formula); + }; + + const handleSaveFormula = async (formulaId, newFormula) => { + try { + setSaveLoading(true); + + // Обновляем формулу в локальном состоянии + const updatedFormulas = formulas.map(formula => + formula.id === formulaId + ? { ...formula, data: { ...formula.data, formula: newFormula } } + : formula + ); + + setFormulas(updatedFormulas); + setEditingFormula(null); + + showSnackbar('Формула успешно обновлена!'); + + } catch (err) { + console.error('Ошибка при сохранении формулы:', err); + showSnackbar('Ошибка при сохранении формулы', 'error'); + } finally { + setSaveLoading(false); + } + }; + + const handleSendAllFormulas = async () => { + try { + setSaveLoading(true); + + // Преобразуем данные обратно в исходный формат для отправки + const dataToSend = formulas.map(formula => ({ + id: formula.data.id, + name: formula.data.name, + desription: formula.data.desription, + values: formula.data.values, + formula: formula.data.formula + })); + + console.log('Отправляемые данные:', dataToSend); + + const response = await axios.post( + 'http://192.168.2.39:9999/api/integration/3333', + dataToSend, + { + headers: { + 'Content-Type': 'application/json' + } + } + ); + + console.log('Ответ сервера:', response.data); + showSnackbar('Данные успешно отправлены на сервер!'); + + } catch (err) { + console.error('Ошибка при отправке данных:', err); + showSnackbar(`Ошибка отправки: ${err.message}`, 'error'); + } finally { + setSaveLoading(false); + } + }; + + const refreshData = useCallback(() => { + setRefreshing(true); + loadFormulas(); + }, [loadFormulas]); + + const handleFormulaIdChange = (e) => { + setFormulaId(e.target.value); + }; + + const handleLoadClick = () => { + if (formulaId.trim()) { + loadFormulas(formulaId); + } + }; + + const filteredFormulas = formulas.filter(formula => + formula.id.toLowerCase().includes(filter.toLowerCase()) || + JSON.stringify(formula.data).toLowerCase().includes(filter.toLowerCase()) + ); + + useEffect(() => { + loadFormulas(); + }, []); + + return ( + + {/* Загрузка */} + {(loading || refreshing) && ( + + + + )} + + {/* Ошибки */} + + + Повторить + + } + > + {error} + + + + {/* Панель управления */} + + + + Редактор формул + + + + + + + + + + + + + setFilter(e.target.value)} + variant="standard" + placeholder="Введите текст для поиска..." + /> + + + + + + + {/* Список формул */} + + {filteredFormulas.map((formula, index) => ( + + ))} + + {filteredFormulas.length === 0 && !loading && ( + + {filter ? 'Формулы не найдены' : 'Загрузите формулы по ID'} + + )} + + + {/* Статус бар */} + + + Всего формул: {formulas.length} • Отфильтровано: {filteredFormulas.length} + + + + + {/* Диалог редактирования */} + setEditingFormula(null)} + onSave={handleSaveFormula} + /> + + {/* Уведомления */} + setSnackbar({ ...snackbar, open: false })} + > + setSnackbar({ ...snackbar, open: false })} + severity={snackbar.severity} + > + {snackbar.message} + + + + ); +}; + +export default React.memo(FormulaEditor); \ No newline at end of file diff --git a/src/Components/Layout/SettingsModal.jsx b/src/Components/Layout/SettingsModal.jsx index f52cf56..c8ec7a6 100644 --- a/src/Components/Layout/SettingsModal.jsx +++ b/src/Components/Layout/SettingsModal.jsx @@ -21,7 +21,8 @@ import CloseIcon from '@mui/icons-material/Close'; import SaveIcon from '@mui/icons-material/Save'; import MetricRangeEditor from './SettingsComponents/MetricRangeEditor'; import UserManagement from './SettingsComponents/UserManagement'; -import MenuEditor from './SettingsComponents/MenuEditor' +import MenuEditor from './SettingsComponents/MenuEditor'; +import FormulaEditor from './SettingsComponents/FormulaEditor'; const Transition = React.forwardRef(function Transition(props, ref) { return ; @@ -69,6 +70,10 @@ const SettingsModal = ({ open, onClose, onMenuUpdate }) => { hasChanges: false, save: () => Promise.resolve(true) }); + const [formulaEditorState, setFormulaEditorState] = useState({ + hasChanges: false, + save: () => Promise.resolve(true) + }); const handleTabChange = (event, newValue) => { if (hasChanges) { @@ -96,6 +101,10 @@ const SettingsModal = ({ open, onClose, onMenuUpdate }) => { success = success && await metricEditorState.save(); } + if (tabValue === 3 && formulaEditorState.hasChanges) { + success = success && await formulaEditorState.save(); + } + if (success) { setShowSuccess(true); setHasChanges(false); @@ -113,6 +122,11 @@ const SettingsModal = ({ open, onClose, onMenuUpdate }) => { setHasChanges(hasChanges); }; + const handleFormulaEditorChange = ({ hasChanges, saveChanges }) => { + setFormulaEditorState({ hasChanges, save: saveChanges }); + setHasChanges(hasChanges); + }; + const handleClose = () => { if (hasChanges) { setShowConfirmClose(true); @@ -163,6 +177,7 @@ const SettingsModal = ({ open, onClose, onMenuUpdate }) => { + {/* Добавить новые вкладки здесь */} @@ -180,6 +195,10 @@ const SettingsModal = ({ open, onClose, onMenuUpdate }) => { + + + + {/* Добавляйте новые TabPanel для новых вкладок */}