Files
protoc-frontend/src/component/StandardsElement/definition.tsx
2025-07-23 16:55:35 +03:00

224 lines
7.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Badge } from '@/component/ui/badge'
import { Button } from '@/component/ui/button'
import { Label } from '@/component/ui/label'
import { ElementDefinition } from '@/entitiy/element/model/interface'
import { CellTarget } from '@/type/template'
import { Settings, Weight, Wrench } from 'lucide-react'
import { useEffect, useState } from 'react'
import { StandardsEditor } from './StandardsEditor'
import { StandardsPreview } from './StandardsPreview'
import { StandardsSelector } from './StandardsSelector'
// Моковые данные для эталонов (такие же как в 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 StandardsConfig {
sheet: string // Лист Excel
startCell: string // Первая ячейка (например "A10")
maxItems: number // Обычно 7
targetCells: CellTarget[]
}
export const standardsDefinition: ElementDefinition<StandardsConfig, string[]> =
{
type: 'standards',
label: 'Измерительные эталоны',
icon: <Weight className="h-4 w-4" />,
version: 1,
defaultConfig: {
sheet: 'L',
startCell: 'A1',
maxItems: 7,
targetCells: [],
},
Editor: StandardsEditor,
Preview: StandardsPreview,
Render: ({ config, value, onChange }) => {
const [isStandardsDialogOpen, setIsStandardsDialogOpen] = useState(false)
const [selectedStandardIds, setSelectedStandardIds] = useState<string[]>(
[]
)
// Если value содержит названия эталонов, находим соответствующие ID
useEffect(() => {
if (Array.isArray(value) && value.length > 0) {
const ids = value
.map(name => {
const standard = mockStandards.find(s => s.name === name)
return standard?.id || ''
})
.filter(Boolean)
setSelectedStandardIds(ids)
}
}, [value])
const selectedStandardsData = selectedStandardIds
.map(id => getStandardById(id))
.filter(Boolean)
return (
<div className="space-y-2">
{/* Блок с измерительными эталонами */}
<div>
<div className="mb-2 flex items-center justify-between">
<Label className="text-sm font-medium">Эталоны</Label>
<Button
variant="outline"
size="sm"
onClick={() => setIsStandardsDialogOpen(true)}
className="h-7 px-2"
>
<Settings className="mr-1 h-3 w-3" />
Настроить
</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 rounded-md bg-muted/30 p-2 text-sm"
>
<div className="flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-primary/10">
<span className="text-xs font-medium text-primary">
{index + 1}
</span>
</div>
<div className="min-w-0 flex-1">
<div className="truncate text-xs font-medium text-foreground">
{standard.shortName}
</div>
<div className="text-xs text-muted-foreground">
{standard.accuracy} {standard.range}
</div>
</div>
<Badge
variant="secondary"
className="shrink-0 text-xs"
>
<Wrench className="mr-1 h-3 w-3" />
{getStandardTypeBadge(standard.type)}
</Badge>
</div>
)
)}
</div>
) : (
<div className="rounded-md border border-dashed bg-muted/30 p-3 text-center text-sm text-muted-foreground">
<Settings className="mx-auto mb-1 h-4 w-4 opacity-50" />
Эталоны не выбраны
</div>
)}
</div>
</div>
<StandardsSelector
isOpen={isStandardsDialogOpen}
onClose={() => setIsStandardsDialogOpen(false)}
value={selectedStandardIds}
onChange={standardIds => {
setSelectedStandardIds(standardIds)
// Преобразуем ID эталонов в их названия для сохранения в ячейки
const standardNames = standardIds.map(
id => getStandardById(id)?.name || ''
)
onChange?.(standardNames)
}}
/>
</div>
)
},
mapToCells: cfg => {
// Используем только ячейки, указанные пользователем в targetCells
return cfg.targetCells || []
},
mapToCellValues: (cfg, value) => {
// Используем targetCells из конфигурации
const cells = cfg.targetCells || []
// Сопоставляем значения с ячейками
const standardNames = Array.isArray(value) ? value : []
return cells.map((target, idx) => ({
target,
value: standardNames[idx] || '', // Берем значение по индексу или пустую строку
}))
},
}