224 lines
7.8 KiB
TypeScript
224 lines
7.8 KiB
TypeScript
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] || '', // Берем значение по индексу или пустую строку
|
||
}))
|
||
},
|
||
}
|