архитектура добавления элементов, список эталонов

This commit is contained in:
2025-07-18 07:45:43 +03:00
parent dfb4d377d0
commit 7cf319f25d
36 changed files with 2100 additions and 123 deletions

View File

@@ -17,7 +17,12 @@ export const ElementsCreation: FC = () => {
};
const handleElementAdd = (element: TemplateElement) => {
if (!selectedTemplate) return;
console.log('handleElementAdd called with element:', element);
if (!selectedTemplate) {
console.log('No selected template');
return;
}
const updatedTemplate = {
...selectedTemplate,
@@ -25,6 +30,9 @@ export const ElementsCreation: FC = () => {
updatedAt: new Date(),
};
console.log('Updated template:', updatedTemplate);
console.log('Elements count:', updatedTemplate.elements.length);
updateTemplate(updatedTemplate);
setSelectedTemplate(updatedTemplate);
};

View File

@@ -1,11 +1,11 @@
import { FC } from "react";
import { DualSpreadsheet } from "../../../../components";
import { exampleCalculationsData, exampleTemplateData } from "../../../../lib/template-data";
// import { exampleCalculationsData, exampleTemplateData } from "../../../../lib/template-data";
const Home: FC = () => {
const initialData = {
Report: exampleTemplateData,
Calculations: exampleCalculationsData
Report: {},
Calculations: {}
};
return (

View File

@@ -1,17 +1,95 @@
import { ArrowLeft, Download, FileText, Plus, Save } from 'lucide-react';
import { ArrowLeft, Download, FileText, Plus, Save, Settings, Wrench } from 'lucide-react';
import { FC, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { StandardsSelector } from '../../../../components/StandardsElement/StandardsSelector';
import { Badge } from '../../../../components/ui/badge';
import { Button } from '../../../../components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../../../../components/ui/card';
import { Checkbox } from '../../../../components/ui/checkbox';
import { Input } from '../../../../components/ui/input';
import { Label } from '../../../../components/ui/label';
import { RadioGroup, RadioGroupItem } from '../../../../components/ui/radio-group';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../../components/ui/select';
import { Textarea } from '../../../../components/ui/textarea';
import { useTemplateContext } from '../../../../contexts/TemplateContext';
import { Template, TemplateElement } from '../../../../types/template';
// Моковые данные для эталонов (такие же как в StandardsSelector)
const mockStandards = [
{
id: "1",
name: "Эталон массы 1 кг",
shortName: "ЭМ-1кг",
type: "Масса",
registryNumber: "ГРСИ 12345-01",
range: "0.5-2 кг",
accuracy: "±0.001 г",
certificateNumber: "СИ-2024-001",
validUntil: "2025-12-31",
},
{
id: "2",
name: "Эталон длины 1 м",
shortName: "ЭД-1м",
type: "Длина",
registryNumber: "ГРСИ 12345-02",
range: "0.5-2 м",
accuracy: "±0.001 мм",
certificateNumber: "СИ-2024-002",
validUntil: "2025-06-30",
},
{
id: "3",
name: "Эталон температуры 20°C",
shortName: "ЭТ-20°C",
type: "Температура",
registryNumber: "ГРСИ 12345-03",
range: "15-25°C",
accuracy: "±0.01°C",
certificateNumber: "СИ-2024-003",
validUntil: "2025-03-15",
},
{
id: "4",
name: "Эталон давления 1 Па",
shortName: "ЭД-1Па",
type: "Давление",
registryNumber: "ГРСИ 12345-04",
range: "0.5-2 Па",
accuracy: "±0.001 Па",
certificateNumber: "СИ-2024-004",
validUntil: "2025-09-20",
},
{
id: "5",
name: "Эталон времени 1 с",
shortName: "ЭВ-1с",
type: "Время",
registryNumber: "ГРСИ 12345-05",
range: "0.5-2 с",
accuracy: "±0.000001 с",
certificateNumber: "СИ-2024-005",
validUntil: "2025-12-01",
},
];
// Функция для получения данных эталона по ID
const getStandardById = (id: string) => {
return mockStandards.find(standard => standard.id === id);
};
// Функция для получения типа эталона в сокращенном виде
const getStandardTypeBadge = (type: string) => {
switch (type) {
case "Манометр грузопоршневой":
return "МГП";
case "Калибратор давления":
return "КД";
default:
return "МО";
}
};
interface ProtocolFormProps {
template: Template;
onSave: (data: Record<string, any>) => void;
@@ -25,6 +103,8 @@ interface FormElementProps {
}
const FormElement: FC<FormElementProps> = ({ element, value, onChange }) => {
const [isStandardsDialogOpen, setIsStandardsDialogOpen] = useState(false);
const renderInput = () => {
switch (element.type) {
case 'text':
@@ -113,6 +193,76 @@ const FormElement: FC<FormElementProps> = ({ element, value, onChange }) => {
</div>
);
case 'standards':
const selectedStandards = Array.isArray(value) ? value : [];
const selectedStandardsData = selectedStandards
.map(id => getStandardById(id))
.filter(Boolean);
return (
<div className="space-y-2">
{/* Блок с измерительными эталонами */}
<div>
<div className="flex items-center justify-between mb-2">
<Label className="text-sm font-medium">Эталоны</Label>
<Button
variant="outline"
size="sm"
onClick={() => setIsStandardsDialogOpen(true)}
className="h-7 px-2"
>
<Settings className="w-3 h-3 mr-1" />
Настроить
</Button>
</div>
<div className="space-y-2">
{selectedStandardsData.length > 0 ? (
<div className="space-y-1.5">
{selectedStandardsData.map((standard, index) => (
standard && (
<div
key={standard.id}
className="flex items-center gap-2 p-2 bg-muted/30 rounded-md text-sm"
>
<div className="w-5 h-5 rounded-full bg-primary/10 flex items-center justify-center shrink-0">
<span className="text-xs font-medium text-primary">{index + 1}</span>
</div>
<div className="flex-1 min-w-0">
<div className="font-medium text-xs text-foreground truncate">
{standard.shortName}
</div>
<div className="text-xs text-muted-foreground">
{standard.accuracy} {standard.range}
</div>
</div>
<Badge variant="secondary" className="text-xs shrink-0">
<Wrench className="w-3 h-3 mr-1" />
{getStandardTypeBadge(standard.type)}
</Badge>
</div>
)
))}
</div>
) : (
<div className="text-sm text-muted-foreground bg-muted/30 rounded-md p-3 border border-dashed text-center">
<Settings className="w-4 h-4 mx-auto mb-1 opacity-50" />
Эталоны не выбраны
</div>
)}
</div>
</div>
<StandardsSelector
isOpen={isStandardsDialogOpen}
onClose={() => setIsStandardsDialogOpen(false)}
value={selectedStandards}
onChange={onChange}
registryNumber={element.targetCells?.[0]?.displayName || "ГРСИ 12345"}
/>
</div>
);
default:
return null;
}
@@ -125,7 +275,7 @@ const FormElement: FC<FormElementProps> = ({ element, value, onChange }) => {
{element.label}
</label>
{element.required && (
<Badge variant="required" className="text-xs">
<Badge variant="destructive" className="text-xs">
!
</Badge>
)}
@@ -136,7 +286,7 @@ const FormElement: FC<FormElementProps> = ({ element, value, onChange }) => {
{element.targetCells.map((target, index) => (
<Badge
key={index}
variant="excel"
variant="secondary"
className="text-xs font-mono"
title={target.displayName}
>