-
-
-
- Excel шаблон:
-
- {editedTemplate.excelFile ? (
-
-
- {editedTemplate.excelFile.name}
-
- ) : (
-
Файл не загружен
- )}
-
-
-
-
-
+ {/* Панель загрузки Excel */}
+
+
+
+
+ Excel шаблон:
+ {editedTemplate.excelFile ? (
+
+
+ {editedTemplate.excelFile.name}
+
+ ) : (
+
Файл не загружен
+ )}
-
- {/* Таблицы */}
-
+
- {/* Конструктор элементов */}
-
-
-
+ {/* Таблицы - теперь занимают всё оставшееся пространство */}
+
+
);
diff --git a/src/components/TemplateManager/TemplateManager.tsx b/src/components/TemplateManager/TemplateManager.tsx
index f26c2e6..5edcb3b 100644
--- a/src/components/TemplateManager/TemplateManager.tsx
+++ b/src/components/TemplateManager/TemplateManager.tsx
@@ -1,9 +1,10 @@
import { FileText, Plus, Settings, Upload } from 'lucide-react';
import React, { useState } from 'react';
+import { useTemplateContext } from '../../contexts/TemplateContext';
import { Template } from '../../types/template';
import { Button } from '../ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../ui/card';
-import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '../ui/dialog';
+import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from '../ui/dialog';
import { Input } from '../ui/input';
import { TemplateEditor } from './TemplateEditor';
import { TemplateRenderer } from './TemplateRenderer';
@@ -13,7 +14,7 @@ interface TemplateManagerProps {
}
export const TemplateManager: React.FC
= ({ onTemplateSelect }) => {
- const [templates, setTemplates] = useState([]);
+ const { templates, addTemplate, updateTemplate, deleteTemplate } = useTemplateContext();
const [selectedTemplate, setSelectedTemplate] = useState(null);
const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
const [isEditMode, setIsEditMode] = useState(false);
@@ -32,7 +33,7 @@ export const TemplateManager: React.FC = ({ onTemplateSele
updatedAt: new Date(),
};
- setTemplates(prev => [...prev, newTemplate]);
+ addTemplate(newTemplate);
setSelectedTemplate(newTemplate);
setIsEditMode(true);
setIsCreateDialogOpen(false);
@@ -41,14 +42,12 @@ export const TemplateManager: React.FC = ({ onTemplateSele
};
const handleTemplateUpdate = (updatedTemplate: Template) => {
- setTemplates(prev => prev.map(t =>
- t.id === updatedTemplate.id ? updatedTemplate : t
- ));
+ updateTemplate(updatedTemplate);
setSelectedTemplate(updatedTemplate);
};
const handleTemplateDelete = (templateId: string) => {
- setTemplates(prev => prev.filter(t => t.id !== templateId));
+ deleteTemplate(templateId);
if (selectedTemplate?.id === templateId) {
setSelectedTemplate(null);
setIsEditMode(false);
@@ -94,8 +93,8 @@ export const TemplateManager: React.FC = ({ onTemplateSele
-
Система протоколов
-
Управление шаблонами и создание отчетов
+
Настройка шаблонов
+
Создание и управление шаблонами протоколов
);
diff --git a/src/contexts/TemplateContext.tsx b/src/contexts/TemplateContext.tsx
new file mode 100644
index 0000000..a9a56cf
--- /dev/null
+++ b/src/contexts/TemplateContext.tsx
@@ -0,0 +1,58 @@
+import React, { createContext, ReactNode, useContext, useState } from 'react';
+import { Template } from '../types/template';
+
+interface TemplateContextType {
+ templates: Template[];
+ addTemplate: (template: Template) => void;
+ updateTemplate: (template: Template) => void;
+ deleteTemplate: (templateId: string) => void;
+ getTemplate: (templateId: string) => Template | undefined;
+}
+
+const TemplateContext = createContext
(undefined);
+
+export const useTemplateContext = () => {
+ const context = useContext(TemplateContext);
+ if (!context) {
+ throw new Error('useTemplateContext must be used within a TemplateProvider');
+ }
+ return context;
+};
+
+interface TemplateProviderProps {
+ children: ReactNode;
+}
+
+export const TemplateProvider: React.FC = ({ children }) => {
+ const [templates, setTemplates] = useState([]);
+
+ const addTemplate = (template: Template) => {
+ setTemplates(prev => [...prev, template]);
+ };
+
+ const updateTemplate = (updatedTemplate: Template) => {
+ setTemplates(prev => prev.map(t =>
+ t.id === updatedTemplate.id ? updatedTemplate : t
+ ));
+ };
+
+ const deleteTemplate = (templateId: string) => {
+ setTemplates(prev => prev.filter(t => t.id !== templateId));
+ };
+
+ const getTemplate = (templateId: string) => {
+ return templates.find(t => t.id === templateId);
+ };
+
+ return (
+
+ {children}
+
+ );
+};
\ No newline at end of file
diff --git a/src/hooks/useSpreadsheetEngine.ts b/src/hooks/useSpreadsheetEngine.ts
index bee5dad..e401e7d 100644
--- a/src/hooks/useSpreadsheetEngine.ts
+++ b/src/hooks/useSpreadsheetEngine.ts
@@ -15,8 +15,8 @@ interface UseSpreadsheetEngineProps {
}
export function useSpreadsheetEngine({
- rows = 20,
- cols = 10,
+ rows = 50,
+ cols = 20,
sheetName = 'Sheet1',
initialData
}: UseSpreadsheetEngineProps = {}) {
diff --git a/src/lib/spreadsheet-example.ts b/src/lib/spreadsheet-example.ts
index 4c33180..2dabbdf 100644
--- a/src/lib/spreadsheet-example.ts
+++ b/src/lib/spreadsheet-example.ts
@@ -112,7 +112,7 @@ export function convertFromReactData(reactData: string[][], sheetName: string =
}
// Функция для конвертации данных из движка в React компонент
-export function convertToReactData(wb: Workbook, sheetName: string = 'Sheet1', maxRows: number = 20, maxCols: number = 10): string[][] {
+export function convertToReactData(wb: Workbook, sheetName: string = 'Sheet1', maxRows: number = 50, maxCols: number = 20): string[][] {
const sheet = wb.getSheet(sheetName);
if (!sheet) {
return Array(maxRows).fill(null).map(() => Array(maxCols).fill(''));
diff --git a/src/pages/ElementsCreation/index.ts b/src/pages/ElementsCreation/index.ts
new file mode 100644
index 0000000..696cd38
--- /dev/null
+++ b/src/pages/ElementsCreation/index.ts
@@ -0,0 +1,3 @@
+import { ElementsCreation } from "./ui/Page";
+
+export { ElementsCreation };
diff --git a/src/pages/ElementsCreation/ui/Page/Page.tsx b/src/pages/ElementsCreation/ui/Page/Page.tsx
new file mode 100644
index 0000000..f725329
--- /dev/null
+++ b/src/pages/ElementsCreation/ui/Page/Page.tsx
@@ -0,0 +1,166 @@
+import { Plus, Wrench } from 'lucide-react';
+import { FC, useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { ElementConstructor } from '../../../../components/TemplateManager/ElementConstructor';
+import { Button } from '../../../../components/ui/button';
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../../../../components/ui/card';
+import { useTemplateContext } from '../../../../contexts/TemplateContext';
+import { Template, TemplateElement } from '../../../../types/template';
+
+export const ElementsCreation: FC = () => {
+ const navigate = useNavigate();
+ const { templates, updateTemplate } = useTemplateContext();
+ const [selectedTemplate, setSelectedTemplate] = useState(null);
+ const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
+
+ const handleTemplateSelect = (template: Template) => {
+ setSelectedTemplate(template);
+ };
+
+ const handleElementAdd = (element: TemplateElement) => {
+ if (!selectedTemplate) return;
+
+ const updatedTemplate = {
+ ...selectedTemplate,
+ elements: [...selectedTemplate.elements, element],
+ updatedAt: new Date(),
+ };
+
+ updateTemplate(updatedTemplate);
+ setSelectedTemplate(updatedTemplate);
+ };
+
+ const handleElementUpdate = (elementId: string, updates: Partial) => {
+ if (!selectedTemplate) return;
+
+ const updatedTemplate = {
+ ...selectedTemplate,
+ elements: selectedTemplate.elements.map(el =>
+ el.id === elementId ? { ...el, ...updates } : el
+ ),
+ updatedAt: new Date(),
+ };
+
+ updateTemplate(updatedTemplate);
+ setSelectedTemplate(updatedTemplate);
+ };
+
+ const handleElementDelete = (elementId: string) => {
+ if (!selectedTemplate) return;
+
+ const updatedTemplate = {
+ ...selectedTemplate,
+ elements: selectedTemplate.elements.filter(el => el.id !== elementId),
+ updatedAt: new Date(),
+ };
+
+ updateTemplate(updatedTemplate);
+ setSelectedTemplate(updatedTemplate);
+ };
+
+ const handleBack = () => {
+ setSelectedTemplate(null);
+ };
+
+ if (selectedTemplate) {
+ return (
+
+
+
+
+
+
+
+ Создание элементов: {selectedTemplate.name}
+
+
+ Создайте элементы формы для связи с ячейками шаблона
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+
Создание элементов
+
Выберите шаблон для создания элементов интерфейса
+
+
+
+
+
+ {templates.length === 0 ? (
+
+
+
Нет доступных шаблонов
+
Создайте шаблон для начала работы с элементами
+
+
+ ) : (
+
+ {templates.map((template) => (
+
+
+ {template.name}
+ {template.description && (
+
+ {template.description}
+
+ )}
+
+
+
+
+
+ {template.elements.length} элементов создано
+
+
+ Обновлен: {template.updatedAt.toLocaleDateString()}
+
+
+
+
+
+
+
+ ))}
+
+ )}
+
+ );
+};
\ No newline at end of file
diff --git a/src/pages/ElementsCreation/ui/Page/index.ts b/src/pages/ElementsCreation/ui/Page/index.ts
new file mode 100644
index 0000000..a00eefc
--- /dev/null
+++ b/src/pages/ElementsCreation/ui/Page/index.ts
@@ -0,0 +1 @@
+export { ElementsCreation } from './Page';
diff --git a/src/pages/ProtocolCreation/index.ts b/src/pages/ProtocolCreation/index.ts
new file mode 100644
index 0000000..a1fe00f
--- /dev/null
+++ b/src/pages/ProtocolCreation/index.ts
@@ -0,0 +1 @@
+export { ProtocolCreation } from './ui/Page/Page';
diff --git a/src/pages/ProtocolCreation/ui/Page/Page.tsx b/src/pages/ProtocolCreation/ui/Page/Page.tsx
new file mode 100644
index 0000000..dfcf0b7
--- /dev/null
+++ b/src/pages/ProtocolCreation/ui/Page/Page.tsx
@@ -0,0 +1,105 @@
+import { FileText, Plus } from 'lucide-react';
+import { FC, useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { TemplateRenderer } from '../../../../components/TemplateManager/TemplateRenderer';
+import { Button } from '../../../../components/ui/button';
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../../../../components/ui/card';
+import { useTemplateContext } from '../../../../contexts/TemplateContext';
+import { Template } from '../../../../types/template';
+
+export const ProtocolCreation: FC = () => {
+ const navigate = useNavigate();
+ const { templates } = useTemplateContext();
+ const [selectedTemplate, setSelectedTemplate] = useState(null);
+
+ const handleTemplateSelect = (template: Template) => {
+ setSelectedTemplate(template);
+ };
+
+ const handleBack = () => {
+ setSelectedTemplate(null);
+ };
+
+ const handleEdit = () => {
+ // Переходим на страницу редактирования шаблона
+ navigate('/templates');
+ };
+
+ if (selectedTemplate) {
+ return (
+
+ );
+ }
+
+ return (
+
+
+
+
Создание протокола
+
Выберите шаблон для создания нового протокола
+
+
+
+
+
+ {templates.length === 0 ? (
+
+
+
Нет доступных шаблонов
+
Создайте шаблон протокола для начала работы
+
+
+ ) : (
+
+ {templates.map((template) => (
+
+
+ {template.name}
+ {template.description && (
+
+ {template.description}
+
+ )}
+
+
+
+
+
+ {template.elements.length} элементов для заполнения
+
+
+ Создан: {template.createdAt.toLocaleDateString()}
+
+
+
+
+
+
+
+ ))}
+
+ )}
+
+ );
+};
\ No newline at end of file
diff --git a/src/pages/TemplateSetup/index.ts b/src/pages/TemplateSetup/index.ts
new file mode 100644
index 0000000..a6f44ca
--- /dev/null
+++ b/src/pages/TemplateSetup/index.ts
@@ -0,0 +1 @@
+export { TemplateSetup } from './ui/Page/Page';
diff --git a/src/pages/TemplateSetup/ui/Page/Page.tsx b/src/pages/TemplateSetup/ui/Page/Page.tsx
new file mode 100644
index 0000000..895dc20
--- /dev/null
+++ b/src/pages/TemplateSetup/ui/Page/Page.tsx
@@ -0,0 +1,6 @@
+import { FC } from 'react';
+import { TemplateManager } from '../../../../components/TemplateManager/TemplateManager';
+
+export const TemplateSetup: FC = () => {
+ return ;
+};
\ No newline at end of file
diff --git a/src/pages/index.ts b/src/pages/index.ts
index 8aca9ea..b44496a 100644
--- a/src/pages/index.ts
+++ b/src/pages/index.ts
@@ -1,4 +1,8 @@
+import { ElementsCreation } from "./ElementsCreation";
import { Home } from "./Home";
import { NoMatch } from "./NoMatch";
+import { ProtocolCreation } from "./ProtocolCreation";
+import { TemplateSetup } from "./TemplateSetup";
+
+export { ElementsCreation, Home, NoMatch, ProtocolCreation, TemplateSetup };
-export { Home, NoMatch };
diff --git a/src/types/template.ts b/src/types/template.ts
index c868298..b8f0dc3 100644
--- a/src/types/template.ts
+++ b/src/types/template.ts
@@ -1,4 +1,4 @@
-// Типы элементов интерфейса
+ц// Типы элементов интерфейса
export type ElementType = 'text' | 'select' | 'radio' | 'checkbox' | 'number' | 'textarea' | 'date';
export interface ElementOption {