фикс багов

This commit is contained in:
2025-07-25 09:19:36 +03:00
parent 1f02136455
commit 035cf89f92
6 changed files with 89 additions and 52 deletions

View File

@@ -111,7 +111,9 @@ export const selectDefinition: ElementDefinition<SelectConfig, string> = {
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectGroup> <SelectGroup>
{config.options.map((option, index) => ( {config.options
.filter(option => option.value.trim() !== '')
.map((option, index) => (
<SelectItem key={index} value={option.value}> <SelectItem key={index} value={option.value}>
{option.label} {option.label}
</SelectItem> </SelectItem>
@@ -127,7 +129,9 @@ export const selectDefinition: ElementDefinition<SelectConfig, string> = {
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectGroup> <SelectGroup>
{config.options.map((option, index) => ( {config.options
.filter(option => option.value.trim() !== '')
.map((option, index) => (
<SelectItem key={index} value={option.value}> <SelectItem key={index} value={option.value}>
{option.label} {option.label}
</SelectItem> </SelectItem>

View File

@@ -1,5 +1,4 @@
import { Button } from '@/component/ui/button' import { Button } from '@/component/ui/button'
import { Calendar } from '@/component/ui/calendar'
import { Card, CardContent, CardHeader, CardTitle } from '@/component/ui/card' import { Card, CardContent, CardHeader, CardTitle } from '@/component/ui/card'
import { import {
Dialog, Dialog,
@@ -10,7 +9,6 @@ import {
} from '@/component/ui/dialog' } from '@/component/ui/dialog'
import { Input } from '@/component/ui/input' import { Input } from '@/component/ui/input'
import { Label } from '@/component/ui/label' import { Label } from '@/component/ui/label'
import { Popover, PopoverContent, PopoverTrigger } from '@/component/ui/popover'
import { import {
AlertCircle, AlertCircle,
Building2, Building2,
@@ -47,7 +45,6 @@ export function VerificationConditionsRender({
config.selectedDate || new Date().toISOString().split('T')[0] config.selectedDate || new Date().toISOString().split('T')[0]
) )
const [editDialogOpen, setEditDialogOpen] = useState(false) const [editDialogOpen, setEditDialogOpen] = useState(false)
const [calendarOpen, setCalendarOpen] = useState(false)
const [editingConditions, setEditingConditions] = useState< const [editingConditions, setEditingConditions] = useState<
Record<string, string> Record<string, string>
>({}) >({})
@@ -67,26 +64,23 @@ export function VerificationConditionsRender({
const hasConditions = const hasConditions =
dailyCondition && Object.keys(dailyCondition.conditions).length > 0 dailyCondition && Object.keys(dailyCondition.conditions).length > 0
// Автоматическая инициализация onChange при загрузке данных // Инициализация данных при загрузке из БД, только если данные еще не заполнены
useEffect(() => { useEffect(() => {
if (dailyCondition && onChange && hasConditions) { if (
dailyCondition &&
hasConditions &&
onChange &&
(!value?.conditions || Object.keys(value.conditions).length === 0)
) {
onChange({ onChange({
date: selectedDate, date: selectedDate,
conditions: dailyCondition.conditions, conditions: dailyCondition.conditions,
}) })
} }
}, [dailyCondition, onChange, selectedDate, hasConditions]) }, [dailyCondition, hasConditions, onChange, selectedDate, value?.conditions])
const handleDateChange = (date: string) => { const handleDateChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setSelectedDate(date) setSelectedDate(event.target.value)
}
const handleCalendarSelect = (date: Date | undefined) => {
if (date) {
const dateString = date.toISOString().split('T')[0]
setSelectedDate(dateString)
setCalendarOpen(false)
}
} }
const handleOpenEditDialog = (isCreating = false) => { const handleOpenEditDialog = (isCreating = false) => {
@@ -167,25 +161,13 @@ export function VerificationConditionsRender({
{/* Выбор даты */} {/* Выбор даты */}
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<CalendarIcon className="h-3.5 w-3.5 text-muted-foreground" /> <CalendarIcon className="h-3.5 w-3.5 text-muted-foreground" />
<Popover open={calendarOpen} onOpenChange={setCalendarOpen}> <Input
<PopoverTrigger asChild> type="date"
<Button value={selectedDate}
variant="outline" onChange={handleDateChange}
className="h-6 justify-start border-none bg-muted/50 px-2 text-xs font-normal hover:bg-muted/70" lang="ru"
> className="h-6 border-none bg-muted/50 px-2 text-xs font-normal hover:bg-muted/70 focus:bg-background"
{new Date(selectedDate).toLocaleDateString('ru-RU')}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar
mode="single"
selected={new Date(selectedDate)}
onSelect={handleCalendarSelect}
className="rounded-md border shadow-sm"
captionLayout="dropdown"
/> />
</PopoverContent>
</Popover>
</div> </div>
{/* Статус и данные */} {/* Статус и данные */}

View File

@@ -31,6 +31,14 @@ export const verificationConditionsElementDefinition: ElementDefinition<
Preview: VerificationConditionsPreview, Preview: VerificationConditionsPreview,
Render: VerificationConditionsRender, Render: VerificationConditionsRender,
// Получение начальных значений из конфигурации
getInitialValue: config => {
return {
date: config.selectedDate || new Date().toISOString().split('T')[0],
conditions: {},
}
},
// Получение ячеек для записи данных на основе маппинга условий // Получение ячеек для записи данных на основе маппинга условий
mapToCells: (config): CellTarget[] => { mapToCells: (config): CellTarget[] => {
// Возвращаем только те targetCells, которые замаплены к условиям // Возвращаем только те targetCells, которые замаплены к условиям

View File

@@ -39,6 +39,15 @@ export const standardsDefinition: ElementDefinition<
}, },
Editor: StandardsEditor, Editor: StandardsEditor,
Preview: StandardsPreview, Preview: StandardsPreview,
// Получение начальных значений из конфигурации
getInitialValue: config => {
return {
standardIds: config.selectedStandards || [],
standardNames: [], // Будет заполнено при рендере компонента
}
},
Render: ({ config, value, onChange }) => { Render: ({ config, value, onChange }) => {
const [isStandardsDialogOpen, setIsStandardsDialogOpen] = useState(false) const [isStandardsDialogOpen, setIsStandardsDialogOpen] = useState(false)
const [selectedStandardIds, setSelectedStandardIds] = useState<string[]>( const [selectedStandardIds, setSelectedStandardIds] = useState<string[]>(
@@ -60,9 +69,14 @@ export const standardsDefinition: ElementDefinition<
.map(id => standards.find(s => s.id === id)) .map(id => standards.find(s => s.id === id))
.filter(Boolean) .filter(Boolean)
// Автоматическая инициализация onChange при загрузке данных эталонов // Обновляем standardNames при получении данных из API, если они еще не заполнены
useEffect(() => { useEffect(() => {
if (standards.length > 0 && selectedStandardIds.length > 0) { if (
standards.length > 0 &&
selectedStandardIds.length > 0 &&
(!value?.standardNames || value.standardNames.length === 0) &&
onChange
) {
const standardNames = selectedStandardIds const standardNames = selectedStandardIds
.map((id, index) => { .map((id, index) => {
const standard = standards.find(s => s.id === id) const standard = standards.find(s => s.id === id)
@@ -72,12 +86,14 @@ export const standardsDefinition: ElementDefinition<
}) })
.filter(Boolean) .filter(Boolean)
onChange?.({ if (standardNames.length > 0) {
onChange({
standardIds: selectedStandardIds, standardIds: selectedStandardIds,
standardNames, standardNames,
}) })
} }
}, [selectedStandardIds, standards, onChange]) }
}, [standards, selectedStandardIds, value?.standardNames, onChange])
return ( return (
<div className="space-y-2"> <div className="space-y-2">

View File

@@ -20,6 +20,7 @@ export interface ElementDefinition<Config = any, Value = any> {
/* бизнес-логика */ /* бизнес-логика */
defaultConfig: Config defaultConfig: Config
getInitialValue?(config: Config): Value // получение начальных значений из конфигурации
mapToCells(config: Config): CellTarget[] // куда пишем данные (для отображения) mapToCells(config: Config): CellTarget[] // куда пишем данные (для отображения)
mapToCellValues( mapToCellValues(
config: Config, config: Config,

View File

@@ -74,10 +74,36 @@ const FormElement: FC<FormElementProps> = ({ element, value, onChange }) => {
const ProtocolForm: FC<ProtocolFormProps> = ({ template, onSave, onBack }) => { const ProtocolForm: FC<ProtocolFormProps> = ({ template, onSave, onBack }) => {
const [formData, setFormData] = useState<Record<string, any>>({}) const [formData, setFormData] = useState<Record<string, any>>({})
const [showSpreadsheet, setShowSpreadsheet] = useState(false) const [showSpreadsheet, setShowSpreadsheet] = useState(false)
const [isInitialized, setIsInitialized] = useState(false)
const engineRef = useRef<any>(null) const engineRef = useRef<any>(null)
const toast = useToast() const toast = useToast()
const navigate = useNavigate() const navigate = useNavigate()
// Инициализация значений для специальных элементов
useEffect(() => {
if (!isInitialized && template.elements.length > 0) {
const initialData: Record<string, any> = {}
template.elements.forEach(element => {
// Получаем определение элемента
const elementDefinition = getElementDefinition(element.type)
if (elementDefinition?.getInitialValue) {
// Используем метод getInitialValue для получения начального значения
const initialValue = elementDefinition.getInitialValue(element as any)
if (initialValue !== undefined) {
initialData[element.id] = initialValue
}
}
})
if (Object.keys(initialData).length > 0) {
setFormData(initialData)
}
setIsInitialized(true)
}
}, [template.elements, isInitialized])
const handleFieldChange = (elementId: string, value: any) => { const handleFieldChange = (elementId: string, value: any) => {
setFormData(prev => ({ setFormData(prev => ({
...prev, ...prev,