15.12.25 - Этап 3. Детализации --2
All checks were successful
Mirror frontend to backend repo / mirror (push) Successful in 6s
All checks were successful
Mirror frontend to backend repo / mirror (push) Successful in 6s
This commit is contained in:
@@ -1,15 +1,23 @@
|
||||
import apiClient from './axios';
|
||||
import { ApiResponse, ServerEntity, WorkstationEntity, FiscalEntity, UpdateServerDTO, UpdateWorkstationDTO, UpdateFiscalDTO } from '@/types/api';
|
||||
import {
|
||||
ApiResponse,
|
||||
ServerDetailDTO,
|
||||
WorkstationDetailDTO,
|
||||
FiscalDetailDTO,
|
||||
UpdateServerPayload,
|
||||
UpdateWorkstationPayload,
|
||||
UpdateFiscalPayload
|
||||
} from '@/types/api';
|
||||
|
||||
export const equipmentApi = {
|
||||
// --- Servers ---
|
||||
getServer: async (uuid: string) => {
|
||||
const response = await apiClient.get<ApiResponse<ServerEntity>>(`/servers/${uuid}`);
|
||||
const response = await apiClient.get<ApiResponse<ServerDetailDTO>>(`/servers/${uuid}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
updateServer: async (uuid: string, data: UpdateServerDTO) => {
|
||||
const response = await apiClient.put<ApiResponse<ServerEntity>>(`/servers/${uuid}`, data);
|
||||
updateServer: async (uuid: string, data: UpdateServerPayload) => {
|
||||
const response = await apiClient.put<ApiResponse<ServerDetailDTO>>(`/servers/${uuid}`, data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -20,23 +28,23 @@ export const equipmentApi = {
|
||||
|
||||
// --- Workstations ---
|
||||
getWorkstation: async (uuid: string) => {
|
||||
const response = await apiClient.get<ApiResponse<WorkstationEntity>>(`/workstations/${uuid}`);
|
||||
const response = await apiClient.get<ApiResponse<WorkstationDetailDTO>>(`/workstations/${uuid}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
updateWorkstation: async (uuid: string, data: UpdateWorkstationDTO) => {
|
||||
const response = await apiClient.put<ApiResponse<WorkstationEntity>>(`/workstations/${uuid}`, data);
|
||||
updateWorkstation: async (uuid: string, data: UpdateWorkstationPayload) => {
|
||||
const response = await apiClient.put<ApiResponse<WorkstationDetailDTO>>(`/workstations/${uuid}`, data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
// --- Fiscals ---
|
||||
getFiscal: async (uuid: string) => {
|
||||
const response = await apiClient.get<ApiResponse<FiscalEntity>>(`/fiscals/${uuid}`);
|
||||
const response = await apiClient.get<ApiResponse<FiscalDetailDTO>>(`/fiscals/${uuid}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
updateFiscal: async (uuid: string, data: UpdateFiscalDTO) => {
|
||||
const response = await apiClient.put<ApiResponse<FiscalEntity>>(`/fiscals/${uuid}`, data);
|
||||
updateFiscal: async (uuid: string, data: UpdateFiscalPayload) => {
|
||||
const response = await apiClient.put<ApiResponse<FiscalDetailDTO>>(`/fiscals/${uuid}`, data);
|
||||
return response.data;
|
||||
},
|
||||
};
|
||||
@@ -1,12 +1,12 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { Card, Descriptions, Button, Space, Typography, Spin, Badge, Modal, Form, Input, message } from 'antd';
|
||||
import { Card, Descriptions, Button, Space, Typography, Spin, Badge, Modal, Form, Input, message, Table } from 'antd';
|
||||
import { ArrowLeftOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||
import { equipmentApi } from '@/api/equipment';
|
||||
import { getEntityIcon, getStatusColor } from '@/utils/mappers';
|
||||
import { formatRnm } from '@/utils/formatters';
|
||||
import { UpdateFiscalDTO } from '@/types/api';
|
||||
import { UpdateFiscalPayload } from '@/types/api';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
@@ -25,7 +25,7 @@ const FiscalDetails: React.FC = () => {
|
||||
});
|
||||
|
||||
const updateMutation = useMutation({
|
||||
mutationFn: (values: UpdateFiscalDTO) => equipmentApi.updateFiscal(id!, values),
|
||||
mutationFn: (values: UpdateFiscalPayload) => equipmentApi.updateFiscal(id!, values),
|
||||
onSuccess: () => {
|
||||
message.success('Данные обновлены');
|
||||
queryClient.invalidateQueries({ queryKey: ['fiscal', id] });
|
||||
@@ -39,7 +39,6 @@ const FiscalDetails: React.FC = () => {
|
||||
|
||||
const fiscal = fiscalRes.data;
|
||||
|
||||
// Логика цвета даты окончания ФН
|
||||
const getFnDateColor = (dateStr?: string) => {
|
||||
if (!dateStr) return undefined;
|
||||
const diff = dayjs(dateStr).diff(dayjs(), 'day');
|
||||
@@ -50,11 +49,22 @@ const FiscalDetails: React.FC = () => {
|
||||
|
||||
const handleEdit = () => {
|
||||
form.setFieldsValue({
|
||||
description: fiscal.description,
|
||||
description: fiscal.Description,
|
||||
});
|
||||
setIsEditModalOpen(true);
|
||||
};
|
||||
|
||||
// Преобразуем лицензии из объекта в массив для таблицы
|
||||
const licensesData = fiscal.Licenses
|
||||
? Object.entries(fiscal.Licenses).map(([id, data]) => ({ id, ...data }))
|
||||
: [];
|
||||
|
||||
const licenseColumns = [
|
||||
{ title: 'ID', dataIndex: 'id', width: 60 },
|
||||
{ title: 'Название', dataIndex: 'name' },
|
||||
{ title: 'До', dataIndex: 'dateUntil', render: (d: string) => d ? d.split(' ')[0] : '-' },
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{ marginBottom: 16, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||
@@ -63,11 +73,11 @@ const FiscalDetails: React.FC = () => {
|
||||
<Space>
|
||||
<div style={{ fontSize: 24, color: '#1890ff' }}>{getEntityIcon('FiscalRegister')}</div>
|
||||
<div>
|
||||
<Title level={4} style={{ margin: 0 }}>{fiscal.model_kkt || 'ККТ'}</Title>
|
||||
<Text type="secondary">{fiscal.serial_number}</Text>
|
||||
<Title level={4} style={{ margin: 0 }}>{fiscal.ModelKKT || 'ККТ'}</Title>
|
||||
<Text type="secondary">{fiscal.FRSerialNumber}</Text>
|
||||
</div>
|
||||
</Space>
|
||||
<Badge status={getStatusColor(fiscal.health_status)} text={fiscal.health_status} />
|
||||
<Badge status={getStatusColor(fiscal.HealthStatus)} text={fiscal.HealthStatus} />
|
||||
</Space>
|
||||
|
||||
<Space>
|
||||
@@ -78,24 +88,22 @@ const FiscalDetails: React.FC = () => {
|
||||
|
||||
<Space direction="vertical" size="middle" style={{ width: '100%' }}>
|
||||
|
||||
{/* Main Info */}
|
||||
<Card title="Информация о ККТ" className="glass-panel" size="small">
|
||||
<Descriptions bordered column={2}>
|
||||
<Descriptions.Item label="РНМ">
|
||||
<Text code>{formatRnm(fiscal.rn_kkt)}</Text>
|
||||
<Text code>{formatRnm(fiscal.RNKKT)}</Text>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="Заводской номер">{fiscal.serial_number}</Descriptions.Item>
|
||||
<Descriptions.Item label="Модель">{fiscal.model_kkt}</Descriptions.Item>
|
||||
<Descriptions.Item label="Описание">{fiscal.description || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="Заводской номер">{fiscal.FRSerialNumber}</Descriptions.Item>
|
||||
<Descriptions.Item label="Модель">{fiscal.ModelKKT}</Descriptions.Item>
|
||||
<Descriptions.Item label="Описание">{fiscal.Description || '-'}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</Card>
|
||||
|
||||
{/* FN Info */}
|
||||
<Card title="Фискальный Накопитель" className="glass-panel" size="small">
|
||||
<Descriptions bordered column={2}>
|
||||
<Descriptions.Item label="Номер ФН">{fiscal.fn_number || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="Номер ФН">{fiscal.FNNumber || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="Дата регистрации">
|
||||
{fiscal.fn_registration_date ? dayjs(fiscal.fn_registration_date).format('DD.MM.YYYY') : '-'}
|
||||
{fiscal.kkt_reg_date ? dayjs(fiscal.kkt_reg_date).format('DD.MM.YYYY') : '-'}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="Дата окончания">
|
||||
<Text strong style={{ color: getFnDateColor(fiscal.fn_expire_date) }}>
|
||||
@@ -105,23 +113,33 @@ const FiscalDetails: React.FC = () => {
|
||||
</Descriptions>
|
||||
</Card>
|
||||
|
||||
{/* Firmware Info */}
|
||||
<Card title="Прошивки и ПО" className="glass-panel" size="small">
|
||||
<Descriptions bordered column={3}>
|
||||
<Descriptions.Item label="Прошивка ФР">{fiscal.fr_firmware || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="Загрузчик">{fiscal.fr_downloader || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="Драйвер">{fiscal.driver_version || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="Прошивка ФР">{fiscal.FRFirmware || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="Загрузчик">{fiscal.FRDownloader || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="Драйвер">{fiscal.DriverVersion || '-'}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</Card>
|
||||
|
||||
{/* Legal Info */}
|
||||
<Card title="Юридическое лицо" className="glass-panel" size="small">
|
||||
<Descriptions bordered column={1}>
|
||||
<Descriptions.Item label="Организация">{fiscal.organization_name || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="ИНН">{fiscal.inn || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="Организация">{fiscal.LegalName || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="ИНН">{fiscal.INN || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="Адрес установки">{fiscal.address || '-'}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</Card>
|
||||
|
||||
{licensesData.length > 0 && (
|
||||
<Card title="Лицензии ККТ" className="glass-panel" size="small">
|
||||
<Table
|
||||
dataSource={licensesData}
|
||||
columns={licenseColumns}
|
||||
rowKey="id"
|
||||
pagination={false}
|
||||
size="small"
|
||||
/>
|
||||
</Card>
|
||||
)}
|
||||
</Space>
|
||||
|
||||
<Modal
|
||||
|
||||
@@ -6,7 +6,7 @@ import { ArrowLeftOutlined, EditOutlined, SyncOutlined, DeleteOutlined } from '@
|
||||
import { equipmentApi } from '@/api/equipment';
|
||||
import { getEntityIcon, getStatusColor } from '@/utils/mappers';
|
||||
import { formatDate } from '@/utils/formatters';
|
||||
import { UpdateServerDTO } from '@/types/api';
|
||||
import { UpdateServerPayload } from '@/types/api';
|
||||
|
||||
const { Title, Text, Paragraph } = Typography;
|
||||
|
||||
@@ -24,7 +24,7 @@ const ServerDetails: React.FC = () => {
|
||||
});
|
||||
|
||||
const updateMutation = useMutation({
|
||||
mutationFn: (values: UpdateServerDTO) => equipmentApi.updateServer(id!, values),
|
||||
mutationFn: (values: UpdateServerPayload) => equipmentApi.updateServer(id!, values),
|
||||
onSuccess: () => {
|
||||
message.success('Данные сервера обновлены');
|
||||
queryClient.invalidateQueries({ queryKey: ['server', id] });
|
||||
@@ -46,12 +46,13 @@ const ServerDetails: React.FC = () => {
|
||||
const server = serverRes.data;
|
||||
|
||||
const handleEdit = () => {
|
||||
// Маппинг для формы (PascalCase -> snake_case payload)
|
||||
form.setFieldsValue({
|
||||
device_name: server.device_name,
|
||||
ip: server.ip,
|
||||
anydesk: server.anydesk,
|
||||
teamviewer: server.teamviewer,
|
||||
description: server.description,
|
||||
device_name: server.DeviceName,
|
||||
ip: server.IP,
|
||||
anydesk: server.Anydesk,
|
||||
teamviewer: server.Teamviewer,
|
||||
description: server.Description,
|
||||
});
|
||||
setIsEditModalOpen(true);
|
||||
};
|
||||
@@ -65,12 +66,12 @@ const ServerDetails: React.FC = () => {
|
||||
<Space>
|
||||
<div style={{ fontSize: 24, color: '#1890ff' }}>{getEntityIcon('Server')}</div>
|
||||
<div>
|
||||
<Title level={4} style={{ margin: 0 }}>{server.device_name || server.server_name || 'Server'}</Title>
|
||||
<Text type="secondary">{server.uuid}</Text>
|
||||
<Title level={4} style={{ margin: 0 }}>{server.DeviceName || server.ServerName || 'Server'}</Title>
|
||||
<Text type="secondary">{server.ID}</Text>
|
||||
</div>
|
||||
</Space>
|
||||
<Tag color={getStatusColor(server.operational_status) === 'success' ? 'green' : 'red'}>
|
||||
{server.operational_status?.toUpperCase()}
|
||||
<Tag color={getStatusColor(server.Status) === 'success' ? 'green' : 'red'}>
|
||||
{server.Status?.toUpperCase()}
|
||||
</Tag>
|
||||
</Space>
|
||||
|
||||
@@ -93,23 +94,23 @@ const ServerDetails: React.FC = () => {
|
||||
<Card title="Основная информация" className="glass-panel" size="small">
|
||||
<Descriptions bordered column={2}>
|
||||
<Descriptions.Item label="IP Адрес">
|
||||
<Paragraph copyable={{ text: server.ip }} style={{ margin: 0 }}>{server.ip || '-'}</Paragraph>
|
||||
<Paragraph copyable={{ text: server.IP }} style={{ margin: 0 }}>{server.IP || '-'}</Paragraph>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="Health Status">
|
||||
<Badge status={getStatusColor(server.health_status)} text={server.health_status} />
|
||||
<Badge status={getStatusColor(server.HealthStatus)} text={server.HealthStatus} />
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="Unique ID">{server.unique_id || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="CRM ID">{server.crm_id || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="Описание" span={2}>{server.description || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="Unique ID">{server.UniqueID || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="CRM ID">{server.CRMid || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="Описание" span={2}>{server.Description || '-'}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</Card>
|
||||
|
||||
{/* Software Info */}
|
||||
<Card title="Программное обеспечение" className="glass-panel" size="small">
|
||||
<Descriptions bordered column={2}>
|
||||
<Descriptions.Item label="Версия сервера">{server.server_version || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="Редакция">{server.server_edition || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="Посл. опрос">{formatDate(server.last_polled_at)}</Descriptions.Item>
|
||||
<Descriptions.Item label="Версия сервера">{server.ServerVersion || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="Редакция">{server.ServerEdition || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="Посл. опрос">{formatDate(server.LastPolledAt)}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</Card>
|
||||
</Space>
|
||||
@@ -119,17 +120,17 @@ const ServerDetails: React.FC = () => {
|
||||
<Card title="Удаленный доступ" className="glass-panel" size="small">
|
||||
<Descriptions column={1} layout="vertical">
|
||||
<Descriptions.Item label="AnyDesk">
|
||||
{server.anydesk ? <Paragraph copyable>{server.anydesk}</Paragraph> : <Text type="secondary">-</Text>}
|
||||
{server.Anydesk ? <Paragraph copyable>{server.Anydesk}</Paragraph> : <Text type="secondary">-</Text>}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="TeamViewer">
|
||||
{server.teamviewer ? <Paragraph copyable>{server.teamviewer}</Paragraph> : <Text type="secondary">-</Text>}
|
||||
{server.Teamviewer ? <Paragraph copyable>{server.Teamviewer}</Paragraph> : <Text type="secondary">-</Text>}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="LiteManager">
|
||||
{server.litemanager ? <Paragraph copyable>{server.litemanager}</Paragraph> : <Text type="secondary">-</Text>}
|
||||
<Descriptions.Item label="RDP">
|
||||
{server.RDP ? <Paragraph copyable>{server.RDP}</Paragraph> : <Text type="secondary">-</Text>}
|
||||
</Descriptions.Item>
|
||||
{server.partners_link && (
|
||||
{server.CabinetLink && (
|
||||
<Descriptions.Item label="Кабинет">
|
||||
<Button type="link" href={server.partners_link} target="_blank" style={{ padding: 0 }}>
|
||||
<Button type="link" href={server.CabinetLink} target="_blank" style={{ padding: 0 }}>
|
||||
Перейти в кабинет дилера
|
||||
</Button>
|
||||
</Descriptions.Item>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Card, Descriptions, Button, Space, Typography, Spin, Badge, Modal, Form
|
||||
import { ArrowLeftOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||
import { equipmentApi } from '@/api/equipment';
|
||||
import { getEntityIcon, getStatusColor } from '@/utils/mappers';
|
||||
import { UpdateWorkstationDTO } from '@/types/api';
|
||||
import { UpdateWorkstationPayload } from '@/types/api';
|
||||
|
||||
const { Title, Text, Paragraph } = Typography;
|
||||
|
||||
@@ -23,7 +23,7 @@ const WorkstationDetails: React.FC = () => {
|
||||
});
|
||||
|
||||
const updateMutation = useMutation({
|
||||
mutationFn: (values: UpdateWorkstationDTO) => equipmentApi.updateWorkstation(id!, values),
|
||||
mutationFn: (values: UpdateWorkstationPayload) => equipmentApi.updateWorkstation(id!, values),
|
||||
onSuccess: () => {
|
||||
message.success('Данные обновлены');
|
||||
queryClient.invalidateQueries({ queryKey: ['workstation', id] });
|
||||
@@ -39,10 +39,10 @@ const WorkstationDetails: React.FC = () => {
|
||||
|
||||
const handleEdit = () => {
|
||||
form.setFieldsValue({
|
||||
device_name: ws.device_name,
|
||||
anydesk: ws.anydesk,
|
||||
teamviewer: ws.teamviewer,
|
||||
description: ws.description,
|
||||
device_name: ws.DeviceName,
|
||||
anydesk: ws.Anydesk,
|
||||
teamviewer: ws.Teamviewer,
|
||||
description: ws.Description,
|
||||
});
|
||||
setIsEditModalOpen(true);
|
||||
};
|
||||
@@ -55,11 +55,11 @@ const WorkstationDetails: React.FC = () => {
|
||||
<Space>
|
||||
<div style={{ fontSize: 24, color: '#1890ff' }}>{getEntityIcon('Workstation')}</div>
|
||||
<div>
|
||||
<Title level={4} style={{ margin: 0 }}>{ws.device_name || 'Workstation'}</Title>
|
||||
<Text type="secondary">{ws.uuid}</Text>
|
||||
<Title level={4} style={{ margin: 0 }}>{ws.DeviceName || 'Workstation'}</Title>
|
||||
<Text type="secondary">{ws.ID}</Text>
|
||||
</div>
|
||||
</Space>
|
||||
<Badge status={getStatusColor(ws.health_status)} text={ws.health_status} />
|
||||
<Badge status={getStatusColor(ws.HealthStatus)} text={ws.HealthStatus} />
|
||||
</Space>
|
||||
|
||||
<Space>
|
||||
@@ -71,16 +71,16 @@ const WorkstationDetails: React.FC = () => {
|
||||
<Card title="Детали рабочей станции" className="glass-panel" size="small">
|
||||
<Descriptions bordered column={1}>
|
||||
<Descriptions.Item label="Описание">
|
||||
{ws.description || '-'}
|
||||
{ws.Description || '-'}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="AnyDesk">
|
||||
{ws.anydesk ? <Paragraph copyable>{ws.anydesk}</Paragraph> : '-'}
|
||||
{ws.Anydesk ? <Paragraph copyable>{ws.Anydesk}</Paragraph> : '-'}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="TeamViewer">
|
||||
{ws.teamviewer ? <Paragraph copyable>{ws.teamviewer}</Paragraph> : '-'}
|
||||
{ws.Teamviewer ? <Paragraph copyable>{ws.Teamviewer}</Paragraph> : '-'}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="LiteManager">
|
||||
{ws.litemanager ? <Paragraph copyable>{ws.litemanager}</Paragraph> : '-'}
|
||||
{ws.Litemanager ? <Paragraph copyable>{ws.Litemanager}</Paragraph> : '-'}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</Card>
|
||||
|
||||
107
src/types/api.ts
107
src/types/api.ts
@@ -206,4 +206,111 @@ export interface UpdateWorkstationDTO {
|
||||
export interface UpdateFiscalDTO {
|
||||
description?: string;
|
||||
// ККТ поля обычно read-only, т.к. приходят из железа, но description можно править
|
||||
}
|
||||
|
||||
// --- Detail DTOs (Strictly matching Backend JSON) ---
|
||||
|
||||
export interface LicensesDict {
|
||||
[key: string]: {
|
||||
name: string;
|
||||
dateFrom: string;
|
||||
dateUntil: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface FiscalDetailDTO {
|
||||
ID: string;
|
||||
ModelKKT?: string;
|
||||
RNKKT?: string;
|
||||
LegalName?: string;
|
||||
INN?: string;
|
||||
FRSerialNumber?: string;
|
||||
FNNumber?: string;
|
||||
|
||||
// Внимание: смешанный регистр в JSON
|
||||
kkt_reg_date?: string;
|
||||
fn_expire_date?: string;
|
||||
|
||||
FRFirmware?: string;
|
||||
FRDownloader?: string;
|
||||
DriverVersion?: string;
|
||||
|
||||
HealthStatus?: 'ok' | 'attention_required' | 'locked';
|
||||
|
||||
// Внимание: lowercase в JSON
|
||||
address?: string;
|
||||
Description?: string;
|
||||
|
||||
Licenses?: LicensesDict;
|
||||
}
|
||||
|
||||
export interface WorkstationDetailDTO {
|
||||
ID: string;
|
||||
DeviceName?: string;
|
||||
Teamviewer?: string;
|
||||
Anydesk?: string;
|
||||
Litemanager?: string;
|
||||
Description?: string;
|
||||
HealthStatus?: 'ok' | 'attention_required' | 'locked';
|
||||
}
|
||||
|
||||
export interface ServerDetailDTO {
|
||||
ID: string;
|
||||
UniqueID?: string;
|
||||
IP?: string;
|
||||
DeviceName?: string;
|
||||
ServerName?: string;
|
||||
ServerVersion?: string;
|
||||
ServerEdition?: string;
|
||||
|
||||
// PascalCase
|
||||
LastPolledAt?: string;
|
||||
Status?: 'active' | 'offline' | 'unknown'; // Operational Status
|
||||
HealthStatus?: 'ok' | 'attention_required' | 'locked';
|
||||
|
||||
CabinetLink?: string;
|
||||
CRMid?: string;
|
||||
|
||||
RDP?: string;
|
||||
Teamviewer?: string;
|
||||
Anydesk?: string;
|
||||
Litemanager?: string;
|
||||
Description?: string;
|
||||
}
|
||||
|
||||
// ... (предыдущие TaskDTO и прочее остаются)
|
||||
export interface ApiResponse<T> {
|
||||
status: 'success' | 'error';
|
||||
data: T;
|
||||
meta?: PaginationMeta;
|
||||
error?: {
|
||||
error: string;
|
||||
};
|
||||
}
|
||||
// Необходимо убедиться, что PaginationMeta и другие типы на месте
|
||||
export interface PaginationMeta {
|
||||
total: number;
|
||||
limit: number;
|
||||
offset: number;
|
||||
has_next: boolean;
|
||||
has_prev: boolean;
|
||||
}
|
||||
|
||||
export interface UpdateServerPayload {
|
||||
device_name?: string;
|
||||
ip?: string;
|
||||
anydesk?: string;
|
||||
teamviewer?: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface UpdateWorkstationPayload {
|
||||
device_name?: string;
|
||||
anydesk?: string;
|
||||
teamviewer?: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface UpdateFiscalPayload {
|
||||
description?: string;
|
||||
}
|
||||
Reference in New Issue
Block a user