|
@ -1,6 +1,11 @@ |
|
|
import { Button, Flex } from "@mantine/core"; |
|
|
|
|
|
import { useState } from "react"; |
|
|
|
|
|
import createReport from 'docx-templates' |
|
|
|
|
|
|
|
|
import { ActionIcon, Button, Flex, Group, Input, Stack, Text, TextInput } from "@mantine/core" |
|
|
|
|
|
import { useEffect, useState } from "react" |
|
|
|
|
|
import createReport, { listCommands } from 'docx-templates' |
|
|
|
|
|
import { Dropzone, DropzoneProps, IMAGE_MIME_TYPE, MS_WORD_MIME_TYPE } from '@mantine/dropzone' |
|
|
|
|
|
import { IconFile, IconFileTypeDocx, IconPhoto, IconPlus, IconUpload, IconX } from "@tabler/icons-react" |
|
|
|
|
|
import { CommandSummary } from "docx-templates/lib/types" |
|
|
|
|
|
import { Control, Controller, FieldValues, SubmitHandler, useFieldArray, useForm, UseFormRegister } from "react-hook-form" |
|
|
|
|
|
import { TemplateHandler } from 'easy-template-x' |
|
|
|
|
|
|
|
|
const xslTemplate = `<?xml version="1.0" encoding="utf-8"?>
|
|
|
const xslTemplate = `<?xml version="1.0" encoding="utf-8"?>
|
|
|
<xsl:stylesheet version="1.0" xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> |
|
|
<xsl:stylesheet version="1.0" xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> |
|
@ -905,108 +910,7 @@ const xslTemplate = `<?xml version="1.0" encoding="utf-8"?> |
|
|
</xsl:template> |
|
|
</xsl:template> |
|
|
</xsl:stylesheet>` |
|
|
</xsl:stylesheet>` |
|
|
|
|
|
|
|
|
const PrintReport = () => { |
|
|
|
|
|
const [loading, setLoading] = useState(false); |
|
|
|
|
|
|
|
|
|
|
|
const generateDocx = async () => { |
|
|
|
|
|
setLoading(true); |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
// Fetch the DOCX template from the public folder
|
|
|
|
|
|
const response = await fetch("/template.docx"); |
|
|
|
|
|
const response_table = await fetch("/template_table.docx"); |
|
|
|
|
|
const templateArrayBuffer = await response.arrayBuffer(); |
|
|
|
|
|
const templateArrayBuffer_table = await response_table.arrayBuffer(); |
|
|
|
|
|
|
|
|
|
|
|
// Convert ArrayBuffer to Uint8Array (Fix TypeScript error)
|
|
|
|
|
|
const templateUint8Array = new Uint8Array(templateArrayBuffer); |
|
|
|
|
|
const templateUint8Array_table = new Uint8Array(templateArrayBuffer_table); |
|
|
|
|
|
|
|
|
|
|
|
// Fetch the image (Example: Load from public folder)
|
|
|
|
|
|
const imageResponse = await fetch("/test.png"); // Change this to your image path
|
|
|
|
|
|
const imageBlob = await imageResponse.blob(); |
|
|
|
|
|
const imageArrayBuffer = await imageBlob.arrayBuffer(); |
|
|
|
|
|
const imageUint8Array = new Uint8Array(imageArrayBuffer); |
|
|
|
|
|
|
|
|
|
|
|
// Generate the DOCX file with the replacement
|
|
|
|
|
|
const report = await createReport({ |
|
|
|
|
|
template: templateUint8Array, // Ensure it's Uint8Array
|
|
|
|
|
|
data: { |
|
|
|
|
|
test: "Hello World", |
|
|
|
|
|
myImage: { |
|
|
|
|
|
width: 6, // Width in cm
|
|
|
|
|
|
height: 6, // Height in cm
|
|
|
|
|
|
data: imageUint8Array, // Image binary data
|
|
|
|
|
|
extension: ".png", // Specify the image format
|
|
|
|
|
|
}, |
|
|
|
|
|
}, |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
const report_table = await createReport({ |
|
|
|
|
|
template: templateUint8Array_table, // Ensure it's Uint8Array
|
|
|
|
|
|
data: { |
|
|
|
|
|
test: "Hello World", |
|
|
|
|
|
rows: [ |
|
|
|
|
|
{ |
|
|
|
|
|
first: 'A', |
|
|
|
|
|
second: 'B', |
|
|
|
|
|
third: 'C', |
|
|
|
|
|
fourth: 'D', |
|
|
|
|
|
}, |
|
|
|
|
|
{ |
|
|
|
|
|
first: 'E', |
|
|
|
|
|
second: 'F', |
|
|
|
|
|
third: 'G', |
|
|
|
|
|
fourth: 'H', |
|
|
|
|
|
}, |
|
|
|
|
|
{ |
|
|
|
|
|
first: 'I', |
|
|
|
|
|
second: 'J', |
|
|
|
|
|
third: 'K', |
|
|
|
|
|
fourth: 'L', |
|
|
|
|
|
} |
|
|
|
|
|
] |
|
|
|
|
|
}, |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// Convert Uint8Array to a Blob
|
|
|
|
|
|
const blob = new Blob([report], { |
|
|
|
|
|
type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
const blob_table = new Blob([report_table], { |
|
|
|
|
|
type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// Create a download link and trigger the download
|
|
|
|
|
|
const url = URL.createObjectURL(blob); |
|
|
|
|
|
const a = document.createElement("a"); |
|
|
|
|
|
a.href = url; |
|
|
|
|
|
a.download = "report.docx"; |
|
|
|
|
|
document.body.appendChild(a); |
|
|
|
|
|
a.click(); |
|
|
|
|
|
document.body.removeChild(a); |
|
|
|
|
|
|
|
|
|
|
|
// Create a download link and trigger the download
|
|
|
|
|
|
const url_table = URL.createObjectURL(blob_table); |
|
|
|
|
|
const a_table = document.createElement("a"); |
|
|
|
|
|
a_table.href = url_table; |
|
|
|
|
|
a_table.download = "report_table.docx"; |
|
|
|
|
|
document.body.appendChild(a_table); |
|
|
|
|
|
a_table.click(); |
|
|
|
|
|
document.body.removeChild(a_table); |
|
|
|
|
|
|
|
|
|
|
|
// Revoke the object URL after download
|
|
|
|
|
|
URL.revokeObjectURL(url); |
|
|
|
|
|
URL.revokeObjectURL(url_table); |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error("Error generating DOCX:", error); |
|
|
|
|
|
} finally { |
|
|
|
|
|
setLoading(false); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const handleGenerateExcel = () => { |
|
|
|
|
|
|
|
|
const handleGenerateExcel = () => { |
|
|
// Define the example XML data
|
|
|
// Define the example XML data
|
|
|
const xmlData = `
|
|
|
const xmlData = `
|
|
|
<root> |
|
|
<root> |
|
@ -1028,42 +932,381 @@ const PrintReport = () => { |
|
|
<saldo_out>300</saldo_out> |
|
|
<saldo_out>300</saldo_out> |
|
|
</Kvp> |
|
|
</Kvp> |
|
|
</root> |
|
|
</root> |
|
|
`;
|
|
|
|
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
// Parse the XSL template and XML data
|
|
|
// Parse the XSL template and XML data
|
|
|
const parser = new DOMParser(); |
|
|
|
|
|
const xslDoc = parser.parseFromString(xslTemplate, "application/xml"); |
|
|
|
|
|
const xmlDoc = parser.parseFromString(xmlData, "application/xml"); |
|
|
|
|
|
|
|
|
const parser = new DOMParser() |
|
|
|
|
|
const xslDoc = parser.parseFromString(xslTemplate, "application/xml") |
|
|
|
|
|
const xmlDoc = parser.parseFromString(xmlData, "application/xml") |
|
|
|
|
|
|
|
|
// Apply the transformation
|
|
|
// Apply the transformation
|
|
|
const xsltProcessor = new XSLTProcessor(); |
|
|
|
|
|
xsltProcessor.importStylesheet(xslDoc); |
|
|
|
|
|
const resultDocument = xsltProcessor.transformToDocument(xmlDoc); |
|
|
|
|
|
|
|
|
const xsltProcessor = new XSLTProcessor() |
|
|
|
|
|
xsltProcessor.importStylesheet(xslDoc) |
|
|
|
|
|
const resultDocument = xsltProcessor.transformToDocument(xmlDoc) |
|
|
|
|
|
|
|
|
// Serialize the result to a string
|
|
|
// Serialize the result to a string
|
|
|
const serializer = new XMLSerializer(); |
|
|
|
|
|
const resultXml = serializer.serializeToString(resultDocument); |
|
|
|
|
|
|
|
|
const serializer = new XMLSerializer() |
|
|
|
|
|
const resultXml = serializer.serializeToString(resultDocument) |
|
|
|
|
|
|
|
|
// Add missing Excel-specific headers if needed
|
|
|
// Add missing Excel-specific headers if needed
|
|
|
const correctedXml = `<?xml version="1.0" encoding="utf-8"?>\n` + resultXml |
|
|
const correctedXml = `<?xml version="1.0" encoding="utf-8"?>\n` + resultXml |
|
|
|
|
|
|
|
|
// Convert to Blob and trigger download
|
|
|
// Convert to Blob and trigger download
|
|
|
const blob = new Blob([correctedXml], { type: "application/vnd.ms-excel" }); |
|
|
|
|
|
const url = URL.createObjectURL(blob); |
|
|
|
|
|
const link = document.createElement("a"); |
|
|
|
|
|
link.href = url; |
|
|
|
|
|
link.download = "template.xls"; |
|
|
|
|
|
link.click(); |
|
|
|
|
|
|
|
|
const blob = new Blob([correctedXml], { type: "application/vnd.ms-excel" }) |
|
|
|
|
|
const url = URL.createObjectURL(blob) |
|
|
|
|
|
const link = document.createElement("a") |
|
|
|
|
|
link.href = url |
|
|
|
|
|
link.download = "template.xls" |
|
|
|
|
|
link.click() |
|
|
|
|
|
|
|
|
|
|
|
URL.revokeObjectURL(url) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const TemplateFormET = ({ |
|
|
|
|
|
templateUrl |
|
|
|
|
|
}: { |
|
|
|
|
|
templateUrl: string |
|
|
|
|
|
}) => { |
|
|
|
|
|
const [templateUint8Array, setTemplateUint8Array] = useState<Uint8Array | null>(null) |
|
|
|
|
|
const [loading, setLoading] = useState(false) |
|
|
|
|
|
|
|
|
|
|
|
const loadTemplate = async (templateUrl: string) => { |
|
|
|
|
|
setLoading(true) |
|
|
|
|
|
try { |
|
|
|
|
|
const response = await fetch(templateUrl) |
|
|
|
|
|
const templateArrayBuffer = await response.arrayBuffer() |
|
|
|
|
|
|
|
|
// Clean up
|
|
|
|
|
|
URL.revokeObjectURL(url); |
|
|
|
|
|
|
|
|
setTemplateUint8Array(new Uint8Array(templateArrayBuffer)) |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error("Error generating DOCX:", error) |
|
|
|
|
|
} finally { |
|
|
|
|
|
setLoading(false) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const loadTags = async (templateUint8Array: Uint8Array) => { |
|
|
|
|
|
const handler = new TemplateHandler() |
|
|
|
|
|
const tags = await handler.parseTags(templateUint8Array) |
|
|
|
|
|
|
|
|
|
|
|
console.log(tags) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
if (templateUint8Array) { |
|
|
|
|
|
loadTags(templateUint8Array) |
|
|
|
|
|
} |
|
|
|
|
|
}, [templateUint8Array]) |
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
if (templateUrl) { |
|
|
|
|
|
loadTemplate(templateUrl) |
|
|
} |
|
|
} |
|
|
|
|
|
}, [templateUrl]) |
|
|
|
|
|
|
|
|
return ( |
|
|
return ( |
|
|
<Flex p='sm' gap='sm'> |
|
|
|
|
|
<Button onClick={generateDocx} disabled={loading}>{loading ? "Генерация отчета..." : "Сохранить в docx"}</Button> |
|
|
|
|
|
|
|
|
<div> |
|
|
|
|
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
interface TemplateCommand extends CommandSummary { |
|
|
|
|
|
children?: CommandSummary[] |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
export function parseCommandList(commands: CommandSummary[]): TemplateCommand[] { |
|
|
|
|
|
function parseBlock(startIndex: number, currentElement?: string): [TemplateCommand[], number] { |
|
|
|
|
|
const block: TemplateCommand[] = [] |
|
|
|
|
|
let i = startIndex |
|
|
|
|
|
|
|
|
|
|
|
while (i < commands.length) { |
|
|
|
|
|
const command = commands[i] |
|
|
|
|
|
|
|
|
|
|
|
if (command.type === "FOR") { |
|
|
|
|
|
const [elementName, , arrayName] = command.code.split(" ") |
|
|
|
|
|
const forCommand: TemplateCommand = { |
|
|
|
|
|
raw: command.raw, |
|
|
|
|
|
type: command.type, |
|
|
|
|
|
code: arrayName, |
|
|
|
|
|
children: [], |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const [children, nextIndex] = parseBlock(i + 1, elementName) |
|
|
|
|
|
forCommand.children = children |
|
|
|
|
|
i = nextIndex |
|
|
|
|
|
block.push(forCommand) |
|
|
|
|
|
} else if (command.type === "END-FOR") { |
|
|
|
|
|
return [block, i + 1] |
|
|
|
|
|
} else { |
|
|
|
|
|
let code = command.code |
|
|
|
|
|
if (currentElement && (code.startsWith(`${currentElement}.`) || code.startsWith(`$${currentElement}.`))) { |
|
|
|
|
|
code = code.replace(`$${currentElement}.`, "").replace(`${currentElement}.`, "") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
block.push({ |
|
|
|
|
|
...command, |
|
|
|
|
|
code, |
|
|
|
|
|
}) |
|
|
|
|
|
i++ |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return [block, i] |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const [parsed] = parseBlock(0) |
|
|
|
|
|
return parsed |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const FormLoop = ({ |
|
|
|
|
|
control, |
|
|
|
|
|
register, |
|
|
|
|
|
command, |
|
|
|
|
|
}: { |
|
|
|
|
|
control: Control<FieldValues, any>, |
|
|
|
|
|
register: UseFormRegister<FieldValues>, |
|
|
|
|
|
command: TemplateCommand, |
|
|
|
|
|
}) => { |
|
|
|
|
|
const { fields, append, remove } = useFieldArray({ |
|
|
|
|
|
name: command.code, |
|
|
|
|
|
control |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
|
<Stack align="center"> |
|
|
|
|
|
<Stack w='100%' key={command.code}> |
|
|
|
|
|
{ |
|
|
|
|
|
fields.map((field, index) => ( |
|
|
|
|
|
<Flex w='100%' justify='space-between' align='flex-end' key={field.id}> |
|
|
|
|
|
{command.children && |
|
|
|
|
|
command.children.map(c => |
|
|
|
|
|
renderCommand( |
|
|
|
|
|
control, |
|
|
|
|
|
register, |
|
|
|
|
|
c, |
|
|
|
|
|
`${c.code}`, |
|
|
|
|
|
`${command.code}.${index}.${c.code}`, |
|
|
|
|
|
`${command.code}.${index}.${c.code}` |
|
|
|
|
|
) |
|
|
|
|
|
)} |
|
|
|
|
|
<Button variant='subtle' onClick={() => { |
|
|
|
|
|
remove(index) |
|
|
|
|
|
}}> |
|
|
|
|
|
<IconX /> |
|
|
|
|
|
</Button> |
|
|
|
|
|
</Flex> |
|
|
|
|
|
)) |
|
|
|
|
|
} |
|
|
|
|
|
</Stack> |
|
|
|
|
|
<ActionIcon onClick={() => { |
|
|
|
|
|
if (command.children) { |
|
|
|
|
|
append(command.children.map(c => c.code).reduce((acc, key) => { |
|
|
|
|
|
acc[key] = ''; |
|
|
|
|
|
return acc; |
|
|
|
|
|
}, {} as Record<string, string>)) |
|
|
|
|
|
} |
|
|
|
|
|
}}> |
|
|
|
|
|
<IconPlus /> |
|
|
|
|
|
</ActionIcon> |
|
|
|
|
|
</Stack> |
|
|
|
|
|
) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const renderCommand = ( |
|
|
|
|
|
control: Control<FieldValues, any>, |
|
|
|
|
|
register: UseFormRegister<FieldValues>, |
|
|
|
|
|
command: CommandSummary, |
|
|
|
|
|
label: string, |
|
|
|
|
|
key: string, |
|
|
|
|
|
name: string, |
|
|
|
|
|
) => { |
|
|
|
|
|
if (command.type === 'INS') { |
|
|
|
|
|
return ( |
|
|
|
|
|
<TextInput |
|
|
|
|
|
label={label} |
|
|
|
|
|
key={key} |
|
|
|
|
|
{...register(name)} |
|
|
|
|
|
/> |
|
|
|
|
|
) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (command.type === 'IMAGE') { |
|
|
|
|
|
return ( |
|
|
|
|
|
<Controller |
|
|
|
|
|
key={key} |
|
|
|
|
|
name={name} |
|
|
|
|
|
control={control} |
|
|
|
|
|
render={({ field: { onChange, value } }) => ( |
|
|
|
|
|
<Dropzone |
|
|
|
|
|
accept={IMAGE_MIME_TYPE} |
|
|
|
|
|
maxSize={5 * 1024 ** 2} |
|
|
|
|
|
onReject={(files) => console.log('rejected files', files)} |
|
|
|
|
|
onDrop={(files) => { |
|
|
|
|
|
console.log(files[0]) |
|
|
|
|
|
files[0].arrayBuffer().then(res => { |
|
|
|
|
|
onChange({ |
|
|
|
|
|
width: 6, |
|
|
|
|
|
height: 6, |
|
|
|
|
|
data: new Uint8Array(res), |
|
|
|
|
|
extension: files[0]?.path?.match(/\.[^.]+$/)?.[0] || "" |
|
|
|
|
|
}) |
|
|
|
|
|
}) |
|
|
|
|
|
}} |
|
|
|
|
|
maxFiles={1} |
|
|
|
|
|
> |
|
|
|
|
|
<Group justify="center" gap="xl" mih={220} style={{ pointerEvents: 'none' }}> |
|
|
|
|
|
<Dropzone.Accept> |
|
|
|
|
|
<IconUpload size={52} color="var(--mantine-color-blue-6)" stroke={1.5} /> |
|
|
|
|
|
</Dropzone.Accept> |
|
|
|
|
|
<Dropzone.Reject> |
|
|
|
|
|
<IconX size={52} color="var(--mantine-color-red-6)" stroke={1.5} /> |
|
|
|
|
|
</Dropzone.Reject> |
|
|
|
|
|
<Dropzone.Idle> |
|
|
|
|
|
<IconFileTypeDocx size={52} color="var(--mantine-color-dimmed)" stroke={1.5} /> |
|
|
|
|
|
</Dropzone.Idle> |
|
|
|
|
|
|
|
|
|
|
|
<div> |
|
|
|
|
|
<Text size="xl" inline> |
|
|
|
|
|
Drag files here or click to select files |
|
|
|
|
|
</Text> |
|
|
|
|
|
<Text size="sm" c="dimmed" inline mt={7}> |
|
|
|
|
|
Attach as many files as you like, each file should not exceed 5mb |
|
|
|
|
|
</Text> |
|
|
|
|
|
</div> |
|
|
|
|
|
</Group> |
|
|
|
|
|
</Dropzone> |
|
|
|
|
|
)} |
|
|
|
|
|
/> |
|
|
|
|
|
) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const TemplateForm = ({ |
|
|
|
|
|
templateUrl, |
|
|
|
|
|
}: { |
|
|
|
|
|
templateUrl: string, |
|
|
|
|
|
}) => { |
|
|
|
|
|
const { register, control, handleSubmit, reset, watch, formState } = useForm({ |
|
|
|
|
|
mode: 'onChange', |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
const [loading, setLoading] = useState(false) |
|
|
|
|
|
const [saving, setSaving] = useState(false) |
|
|
|
|
|
|
|
|
|
|
|
const [templateUint8Array, setTemplateUint8Array] = useState<Uint8Array | null>(null) |
|
|
|
|
|
|
|
|
|
|
|
const [commandList, setCommandList] = useState<TemplateCommand[]>([]) |
|
|
|
|
|
|
|
|
|
|
|
const saveTest = async (templateUint8Array: Uint8Array, data: any) => { |
|
|
|
|
|
setSaving(true) |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
// Generate the DOCX file with the replacement
|
|
|
|
|
|
const report = await createReport({ |
|
|
|
|
|
template: templateUint8Array, // Ensure it's Uint8Array
|
|
|
|
|
|
data: data, |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
// Convert Uint8Array to a Blob
|
|
|
|
|
|
const blob = new Blob([report], { |
|
|
|
|
|
type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
// Create a download link and trigger the download
|
|
|
|
|
|
const url = URL.createObjectURL(blob) |
|
|
|
|
|
const a = document.createElement("a") |
|
|
|
|
|
a.href = url |
|
|
|
|
|
a.download = "report.docx" |
|
|
|
|
|
document.body.appendChild(a) |
|
|
|
|
|
a.click() |
|
|
|
|
|
document.body.removeChild(a) |
|
|
|
|
|
|
|
|
|
|
|
URL.revokeObjectURL(url) |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error("Error generating DOCX:", error) |
|
|
|
|
|
} finally { |
|
|
|
|
|
setSaving(false) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const loadTemplate = async () => { |
|
|
|
|
|
setLoading(true) |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
const response = await fetch(templateUrl) |
|
|
|
|
|
const templateArrayBuffer = await response.arrayBuffer() |
|
|
|
|
|
|
|
|
|
|
|
setTemplateUint8Array(new Uint8Array(templateArrayBuffer)) |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error("Error generating DOCX:", error) |
|
|
|
|
|
} finally { |
|
|
|
|
|
setLoading(false) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const loadCommands = async (templateUint8Array: Uint8Array) => { |
|
|
|
|
|
try { |
|
|
|
|
|
await listCommands(templateUint8Array).then(l => { |
|
|
|
|
|
setCommandList(parseCommandList(l)) |
|
|
|
|
|
}) |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error("Error loading commands from DOCX:", error) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
if (templateUint8Array) { |
|
|
|
|
|
loadCommands(templateUint8Array) |
|
|
|
|
|
} |
|
|
|
|
|
}, [templateUint8Array]) |
|
|
|
|
|
|
|
|
|
|
|
const onSubmit: SubmitHandler<any> = async (data) => { |
|
|
|
|
|
try { |
|
|
|
|
|
if (templateUint8Array && data) { |
|
|
|
|
|
saveTest(templateUint8Array, data) |
|
|
|
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error(error) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
if (templateUrl) { |
|
|
|
|
|
loadTemplate() |
|
|
|
|
|
} |
|
|
|
|
|
}, [templateUrl]) |
|
|
|
|
|
|
|
|
|
|
|
if (commandList) { |
|
|
|
|
|
return ( |
|
|
|
|
|
<form onSubmit={handleSubmit(onSubmit)}> |
|
|
|
|
|
<Stack> |
|
|
|
|
|
{commandList.map(command => { |
|
|
|
|
|
if (command.type === 'FOR') { |
|
|
|
|
|
return ( |
|
|
|
|
|
<FormLoop key={command.code} control={control} register={register} command={command} /> |
|
|
|
|
|
) |
|
|
|
|
|
} else { |
|
|
|
|
|
return renderCommand(control, register, command, command.code, command.code, command.code) |
|
|
|
|
|
} |
|
|
|
|
|
})} |
|
|
|
|
|
<Button type='submit'>Submit</Button> |
|
|
|
|
|
</Stack> |
|
|
|
|
|
</form> |
|
|
|
|
|
) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const PrintReport = () => { |
|
|
|
|
|
const [loading, setLoading] = useState(false) |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
|
<Stack p='sm' gap='sm' w='100%'> |
|
|
|
|
|
<TemplateForm templateUrl="/template_table.docx" /> |
|
|
|
|
|
|
|
|
|
|
|
<Flex gap='sm'> |
|
|
<Button onClick={handleGenerateExcel}>Сохранить в Excel</Button> |
|
|
<Button onClick={handleGenerateExcel}>Сохранить в Excel</Button> |
|
|
</Flex> |
|
|
</Flex> |
|
|
|
|
|
</Stack> |
|
|
) |
|
|
) |
|
|
} |
|
|
} |
|
|
|
|
|
|