Compare commits
4 Commits
daf9cab8ac
...
e5e4d75637
| Author | SHA1 | Date |
|---|---|---|
|
|
e5e4d75637 | |
|
|
3a142185a2 | |
|
|
0b600095ce | |
|
|
33a88d2a1a |
|
|
@ -0,0 +1,206 @@
|
|||
// components/SettingsComponents/Licensing.jsx
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Paper,
|
||||
Typography,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Divider,
|
||||
Chip,
|
||||
Button,
|
||||
TextField,
|
||||
InputAdornment,
|
||||
IconButton,
|
||||
Alert,
|
||||
Stack,
|
||||
Grid
|
||||
} from '@mui/material';
|
||||
import {
|
||||
CheckCircle as CheckCircleIcon,
|
||||
Cancel as CancelIcon,
|
||||
VpnKey as VpnKeyIcon,
|
||||
Refresh as RefreshIcon,
|
||||
Api as ApiIcon,
|
||||
Devices as DevicesIcon,
|
||||
Storage as StorageIcon,
|
||||
Security as SecurityIcon,
|
||||
ContentCopy as ContentCopyIcon
|
||||
} from '@mui/icons-material';
|
||||
import { styled } from '@mui/material/styles';
|
||||
|
||||
const StyledPaper = styled(Paper)(({ theme }) => ({
|
||||
padding: theme.spacing(3),
|
||||
marginBottom: theme.spacing(3),
|
||||
backgroundColor: theme.palette.background.default,
|
||||
}));
|
||||
|
||||
const LicenseKeyBox = styled(Box)(({ theme }) => ({
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
padding: theme.spacing(2),
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
fontFamily: 'monospace',
|
||||
fontSize: '1.1rem',
|
||||
letterSpacing: '0.5px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
marginTop: theme.spacing(2),
|
||||
}));
|
||||
|
||||
const Licensing = ({ onSave }) => {
|
||||
const [hasChanges, setHasChanges] = useState(false);
|
||||
const [licenseKey, setLicenseKey] = useState('ABCDE-FGHIJ-KLMNO-PQRST-UVWXY');
|
||||
const [showCopySuccess, setShowCopySuccess] = useState(false);
|
||||
|
||||
// Текущий состав лицензии (заглушка)
|
||||
const licenseFeatures = [
|
||||
{ name: 'Модуль API', active: true, icon: ApiIcon, description: 'Полный доступ к API' },
|
||||
{ name: 'Подключение устройств', active: true, icon: DevicesIcon, value: '', description: '' },
|
||||
{ name: 'Модуль контроля параметров устойчивого функционирования компонентов, доверенного ПАК', active: true, icon: StorageIcon, value: '', description: '' },
|
||||
//{ name: 'Расширенная безопасность', active: false, icon: SecurityIcon, description: '' },
|
||||
];
|
||||
|
||||
// Уведомляем родительский компонент об изменениях
|
||||
useEffect(() => {
|
||||
if (onSave) {
|
||||
onSave({
|
||||
hasChanges,
|
||||
saveChanges: handleSave
|
||||
});
|
||||
}
|
||||
}, [hasChanges]);
|
||||
|
||||
const handleSave = async () => {
|
||||
// Здесь будет логика сохранения
|
||||
console.log('Сохранение лицензионных настроек');
|
||||
setHasChanges(false);
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleRefreshLicense = () => {
|
||||
// Заглушка для обновления лицензии
|
||||
const newKey = generateLicenseKey();
|
||||
setLicenseKey(newKey);
|
||||
setHasChanges(true);
|
||||
};
|
||||
|
||||
const generateLicenseKey = () => {
|
||||
// Заглушка для генерации ключа
|
||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
const segments = [];
|
||||
for (let i = 0; i < 5; i++) {
|
||||
let segment = '';
|
||||
for (let j = 0; j < 5; j++) {
|
||||
segment += chars[Math.floor(Math.random() * chars.length)];
|
||||
}
|
||||
segments.push(segment);
|
||||
}
|
||||
return segments.join('-');
|
||||
};
|
||||
|
||||
const handleCopyKey = () => {
|
||||
navigator.clipboard.writeText(licenseKey);
|
||||
setShowCopySuccess(true);
|
||||
setTimeout(() => setShowCopySuccess(false), 2000);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
{/* Текущий состав лицензии */}
|
||||
<StyledPaper elevation={0}>
|
||||
<Typography variant="h6" gutterBottom sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
<VpnKeyIcon color="primary" />
|
||||
Текущий состав лицензии
|
||||
</Typography>
|
||||
|
||||
<List>
|
||||
{licenseFeatures.map((feature, index) => {
|
||||
const IconComponent = feature.icon;
|
||||
return (
|
||||
<React.Fragment key={feature.name}>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<IconComponent color={feature.active ? "primary" : "disabled"} />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
<Typography variant="body1">{feature.name}</Typography>
|
||||
{feature.value && (
|
||||
<Chip
|
||||
label={feature.value}
|
||||
size="small"
|
||||
color={feature.active ? "success" : "default"}
|
||||
variant="outlined"
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
}
|
||||
secondary={feature.description}
|
||||
/>
|
||||
<ListItemIcon>
|
||||
{feature.active ? (
|
||||
<CheckCircleIcon color="success" />
|
||||
) : (
|
||||
<CancelIcon color="error" />
|
||||
)}
|
||||
</ListItemIcon>
|
||||
</ListItem>
|
||||
{index < licenseFeatures.length - 1 && <Divider variant="inset" component="li" />}
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
</StyledPaper>
|
||||
|
||||
{/* Идентификатор лицензии */}
|
||||
<StyledPaper elevation={0}>
|
||||
<Grid container spacing={2} alignItems="center">
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Идентификатор лицензии
|
||||
</Typography>
|
||||
<Typography variant="body2" color="textSecondary" paragraph>
|
||||
Этот ключ используется для активации и обновления лицензии
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<LicenseKeyBox>
|
||||
<Typography variant="body1" sx={{ fontFamily: 'monospace' }}>
|
||||
{licenseKey}
|
||||
</Typography>
|
||||
<Box>
|
||||
<IconButton onClick={handleCopyKey} size="small" title="Копировать">
|
||||
<ContentCopyIcon />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</LicenseKeyBox>
|
||||
{showCopySuccess && (
|
||||
<Alert severity="success" sx={{ mt: 1 }}>Ключ скопирован в буфер обмена</Alert>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'flex-end', mt: 2 }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
//onClick={handleRefreshLicense}
|
||||
//startIcon={<RefreshIcon />}
|
||||
>
|
||||
Обновить лицензию
|
||||
</Button>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</StyledPaper>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default Licensing;
|
||||
|
|
@ -23,6 +23,7 @@ import MetricRangeEditor from './SettingsComponents/MetricRangeEditor';
|
|||
import UserManagement from './SettingsComponents/UserManagement';
|
||||
import MenuEditor from './SettingsComponents/MenuEditor';
|
||||
import FormulaEditor from './SettingsComponents/FormulaEditor';
|
||||
import Licensing from './SettingsComponents/Licensing';
|
||||
|
||||
const Transition = React.forwardRef(function Transition(props, ref) {
|
||||
return <Slide direction="up" ref={ref} {...props} />;
|
||||
|
|
@ -74,6 +75,10 @@ const SettingsModal = ({ open, onClose, onMenuUpdate }) => {
|
|||
hasChanges: false,
|
||||
save: () => Promise.resolve(true)
|
||||
});
|
||||
const [licensingState, setLicensingState] = useState({
|
||||
hasChanges: false,
|
||||
save: () => Promise.resolve(true)
|
||||
});
|
||||
|
||||
const handleTabChange = (event, newValue) => {
|
||||
if (hasChanges) {
|
||||
|
|
@ -105,6 +110,10 @@ const SettingsModal = ({ open, onClose, onMenuUpdate }) => {
|
|||
success = success && await formulaEditorState.save();
|
||||
}
|
||||
|
||||
if (tabValue === 4 && licensingState.hasChanges) {
|
||||
success = success && await licensingState.save();
|
||||
}
|
||||
|
||||
if (success) {
|
||||
setShowSuccess(true);
|
||||
setHasChanges(false);
|
||||
|
|
@ -127,6 +136,11 @@ const SettingsModal = ({ open, onClose, onMenuUpdate }) => {
|
|||
setHasChanges(hasChanges);
|
||||
};
|
||||
|
||||
const handleLicensingChange = ({ hasChanges, saveChanges }) => {
|
||||
setLicensingState({ hasChanges, save: saveChanges });
|
||||
setHasChanges(hasChanges);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
if (hasChanges) {
|
||||
setShowConfirmClose(true);
|
||||
|
|
@ -178,6 +192,7 @@ const SettingsModal = ({ open, onClose, onMenuUpdate }) => {
|
|||
<Tab label="Границы метрик" id="settings-tab-1" aria-controls="settings-tabpanel-1" />
|
||||
<Tab label="Управление пользователями" id="settings-tab-2" aria-controls="settings-tabpanel-2" />
|
||||
<Tab label="Настройка формул" id="settings-tab-3" aria-controls="settings-tabpanel-3" />
|
||||
<Tab label="Лицензирование" id="settings-tab-4" aria-controls="settings-tabpanel-4" />
|
||||
{/* Добавить новые вкладки здесь */}
|
||||
</Tabs>
|
||||
</Box>
|
||||
|
|
@ -199,6 +214,10 @@ const SettingsModal = ({ open, onClose, onMenuUpdate }) => {
|
|||
<FormulaEditor onSave={handleFormulaEditorChange} />
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel value={tabValue} index={4}>
|
||||
<Licensing onSave={handleLicensingChange} />
|
||||
</TabPanel>
|
||||
|
||||
{/* Добавляйте новые TabPanel для новых вкладок */}
|
||||
</DialogContent>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue