починка багов

This commit is contained in:
2025-07-23 16:08:50 +03:00
parent 3fc352f8e9
commit 907b3e315e
24 changed files with 1249 additions and 1430 deletions

View File

@@ -2,6 +2,7 @@ import {
getAvailableElementTypes,
getElementDefinition,
} from '@/entitiy/element/model/interface'
import { useToast } from '@/lib/hooks/useToast'
import {
autoArrangeElements,
findFreePosition,
@@ -14,17 +15,7 @@ import {
Template,
TemplateElement,
} from '@/type/template'
import {
Calendar,
Droplets,
Edit3,
Gauge,
Plus,
Radio,
Thermometer,
Trash2,
Zap,
} from 'lucide-react'
import { Plus, Trash2 } from 'lucide-react'
import React, { useState } from 'react'
import { Button } from '../ui/button'
import { Checkbox } from '../ui/checkbox'
@@ -43,7 +34,6 @@ import {
SelectTrigger,
SelectValue,
} from '../ui/select'
import { Textarea } from '../ui/textarea'
import { ElementFormulaBar } from './ElementFormulaBar'
import { VisualLayoutEditor } from './VisualLayoutEditor'
@@ -56,6 +46,8 @@ const CellTargetEditor: React.FC<{
targets: CellTarget[]
onChange: (targets: CellTarget[]) => void
}> = ({ targets, onChange }) => {
const { warning } = useToast()
const handleAddTarget = () => {
onChange([...targets, { sheet: 'L', cell: '' }])
}
@@ -75,6 +67,21 @@ const CellTargetEditor: React.FC<{
onChange(targets.filter((_, i) => i !== index))
}
const handleCellInputChange = (index: number, value: string) => {
// Проверяем на наличие кириллицы
const hasCyrillic = /[а-яё]/i.test(value)
if (hasCyrillic) {
warning('Кириллические символы не разрешены в адресе ячейки', {
title: 'Недопустимый символ',
duration: 3000,
})
return // Не обновляем значение
}
handleUpdateTarget(index, 'cell', value)
}
return (
<div className="space-y-1.5">
<div className="flex items-center justify-between">
@@ -119,9 +126,7 @@ const CellTargetEditor: React.FC<{
<Input
placeholder="A1, B5..."
value={target.cell}
onChange={e =>
handleUpdateTarget(index, 'cell', e.target.value)
}
onChange={e => handleCellInputChange(index, e.target.value)}
className="h-7 text-xs"
/>
</div>
@@ -159,163 +164,7 @@ const ElementPreview: React.FC<{ element: Partial<TemplateElement> }> = ({
return <elementDefinition.Preview config={element as any} />
}
// Fallback для старых элементов
const renderPreviewInput = () => {
switch (element.type) {
case 'text':
return (
<Input
placeholder={element.placeholder || 'Введите текст'}
disabled
className="w-full"
/>
)
case 'textarea':
return (
<Textarea
placeholder={element.placeholder || 'Введите текст'}
disabled
rows={3}
className="w-full resize-none"
/>
)
case 'number':
return (
<Input
type="number"
placeholder={element.placeholder || '0'}
disabled
className="w-full"
/>
)
case 'date':
return <Input type="date" disabled className="w-full" />
case 'select':
return (
<Select disabled>
<SelectTrigger className="w-full">
<span className="text-gray-500">
{element.placeholder || 'Выберите значение'}
</span>
</SelectTrigger>
</Select>
)
case 'radio':
return (
<div className="space-y-2">
{element.options?.length ? (
element.options.map((option, index) => (
<div key={index} className="flex items-center space-x-2">
<div className="h-4 w-4 rounded-full border border-gray-300" />
<span className="text-sm">{option.label}</span>
</div>
))
) : (
<div className="flex items-center space-x-2">
<div className="h-4 w-4 rounded-full border border-gray-300" />
<span className="text-sm text-gray-500">Вариант 1</span>
</div>
)}
</div>
)
case 'checkbox':
return (
<div className="flex items-center space-x-2">
<div className="h-4 w-4 rounded border border-gray-300" />
<span className="text-sm">
{element.placeholder || element.label || 'Отметить'}
</span>
</div>
)
case 'standards':
return (
<div className="space-y-2">
<div className="flex items-center justify-between rounded-md border border-input bg-background p-3">
<span className="text-sm text-muted-foreground">
{element.placeholder || 'Выберите эталоны'}
</span>
<div className="flex items-center gap-2">
<Calendar className="h-4 w-4 opacity-50" />
<span className="text-xs text-muted-foreground">Выбрать</span>
</div>
</div>
<div className="text-xs text-muted-foreground">
Выбрано эталонов: 0
</div>
</div>
)
case 'calibration_conditions':
return (
<div className="space-y-2">
<div className="flex items-center gap-3 rounded-lg border bg-muted/50 px-3 py-2">
<div className="flex items-center gap-3 text-xs">
<div className="flex items-center gap-1">
<Thermometer className="h-3 w-3 text-muted-foreground" />
<span className="text-foreground">20°C</span>
</div>
<div className="flex items-center gap-1">
<Droplets className="h-3 w-3 text-muted-foreground" />
<span className="text-foreground">65%</span>
</div>
<div className="flex items-center gap-1">
<Gauge className="h-3 w-3 text-muted-foreground" />
<span className="text-foreground">101.3кПа</span>
</div>
<div className="flex items-center gap-1">
<Zap className="h-3 w-3 text-muted-foreground" />
<span className="text-foreground">220В</span>
</div>
<div className="flex items-center gap-1">
<Radio className="h-3 w-3 text-muted-foreground" />
<span className="text-foreground">50Гц</span>
</div>
</div>
<Button variant="ghost" size="icon" className="h-6 w-6 p-0">
<Edit3 className="h-3 w-3" />
</Button>
</div>
</div>
)
case 'button_group':
return (
<div className="space-y-2">
<div className="flex flex-wrap gap-1.5">
{element.options?.length ? (
element.options.map((option, index) => (
<button
key={index}
className="rounded-md border border-border bg-background px-3 py-1.5 text-sm font-medium text-foreground transition-all duration-200 hover:border-primary/30 hover:bg-primary/5"
>
{option.label || `Кнопка ${index + 1}`}
</button>
))
) : (
<div className="rounded-md border border-dashed bg-muted/30 px-3 py-1.5 text-sm text-muted-foreground">
{element.placeholder || 'Добавьте кнопки'}
</div>
)}
</div>
</div>
)
default:
return (
<div className="rounded border border-gray-200 bg-gray-50 p-3 text-center text-sm text-gray-500">
Выберите тип элемента
</div>
)
}
}
// Fallback для неизвестных типов элементов
return (
<div className="space-y-3">
<div className="text-sm font-medium text-gray-700">Предпросмотр</div>
@@ -326,7 +175,13 @@ const ElementPreview: React.FC<{ element: Partial<TemplateElement> }> = ({
{element.required && <span className="ml-1 text-red-500">*</span>}
</label>
)}
{renderPreviewInput()}
<div className="rounded border border-gray-200 bg-gray-50 p-3 text-center text-sm text-gray-500">
{element.type
? `Элемент типа "${element.type}" не найден`
: 'Выберите тип элемента'}
</div>
{element.targetCells && element.targetCells.length > 0 && (
<div className="mt-2 flex flex-wrap gap-1">
{element.targetCells.map((target, index) => (
@@ -699,7 +554,6 @@ export const ElementConstructor: React.FC<ElementConstructorProps> = ({
showGrid: true,
}
const [isAddDialogOpen, setIsAddDialogOpen] = useState(false)
const [isSettingsOpen, setIsSettingsOpen] = useState(false)
const [editingElement, setEditingElement] = useState<TemplateElement | null>(
null
)