Files
universal_is/client/src/pages/PrintReport.tsx

1296 lines
44 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useEffect, useState } from "react"
import createReport, { listCommands } from 'docx-templates'
import { IconPlus, 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 { Button, Field, Input, Text, tokens, useId } from "@fluentui/react-components"
import { ArrowUploadRegular } from "@fluentui/react-icons"
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:template match="/">
<xsl:processing-instruction name="mso-application">
<xsl:text>progid="Excel.Sheet"</xsl:text>
</xsl:processing-instruction>
<Workbook>
<!-- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Стили шаблона >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -->
<Styles>
<Style ss:ID="Bordered1">
<Borders>
<Border ss:LineStyle="Continuous" ss:Position="Bottom" ss:Weight="1" />
<Border ss:LineStyle="Continuous" ss:Position="Left" ss:Weight="1" />
<Border ss:LineStyle="Continuous" ss:Position="Right" ss:Weight="1" />
<Border ss:LineStyle="Continuous" ss:Position="Top" ss:Weight="1" />
</Borders>
</Style>
<Style ss:ID="Bordered2">
<Borders>
<Border ss:LineStyle="Continuous" ss:Position="Bottom" ss:Weight="2" />
<Border ss:LineStyle="Continuous" ss:Position="Left" ss:Weight="2" />
<Border ss:LineStyle="Continuous" ss:Position="Right" ss:Weight="2" />
<Border ss:LineStyle="Continuous" ss:Position="Top" ss:Weight="2" />
</Borders>
</Style>
<Style ss:ID="Column" ss:Parent="Bordered2">
<Alignment ss:Horizontal="Center" ss:Vertical="Center" ss:WrapText="1" />
<Font ss:Color="#000000" ss:FontName="Arial Cyr" x:CharSet="204" />
</Style>
<Style ss:ID="Cell1" ss:Parent="Bordered1">
<Font ss:Bold="1" ss:Color="#000000" ss:FontName="Arial Cyr" x:CharSet="204" />
<Interior ss:Color="#47FF19" ss:Pattern="Solid" />
</Style>
<Style ss:ID="Cell2" ss:Parent="Bordered1">
<Font ss:Bold="1" ss:Color="#003366" ss:FontName="Arial Cyr" x:CharSet="204" />
<Interior ss:Color="#F2FF02" ss:Pattern="Solid" />
</Style>
<Style ss:ID="Cell3" ss:Parent="Bordered1">
<Font ss:Bold="1" ss:Color="#333333" ss:FontName="Arial Cyr" x:CharSet="204" />
<Interior ss:Color="#C0C0C0" ss:Pattern="Solid" />
</Style>
<Style ss:ID="Cell4" ss:Parent="Bordered1">
<Font ss:Color="#000000" ss:FontName="Arial Cyr" x:CharSet="204" />
</Style>
<Style ss:ID="CellReg" ss:Parent="Bordered1">
<Font ss:Color="#003366" ss:FontName="Arial Cyr" x:CharSet="204" />
</Style>
<Style ss:ID="CellCity" ss:Parent="Bordered1">
<Font ss:Color="#333333" ss:FontName="Arial Cyr" x:CharSet="204" />
</Style>
</Styles>
<Worksheet ss:Name="Жилищний фонд">
<Table>
<Column ss:Width="100" />
<Column ss:Width="100" />
<Column ss:Width="100" />
<Column ss:Width="150" />
<Column ss:Width="50" />
<Column ss:Width="50" />
<Column ss:Width="50" />
<Column ss:Width="50" />
<Column ss:Width="70" />
<Column ss:Width="70" />
<Column ss:Width="70" />
<Column ss:Width="70" />
<Column ss:Width="70" />
<Column ss:Width="70" />
<Column ss:Width="70" />
<Column ss:Width="70" />
<Column ss:Width="80" />
<!-- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Столбцы таблицы >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -->
<Row>
<Cell ss:MergeDown="1" ss:StyleID="Column">
<Data ss:Type="String">Регион</Data>
</Cell>
<Cell ss:MergeDown="1" ss:StyleID="Column">
<Data ss:Type="String">Нас. пункт</Data>
</Cell>
<Cell ss:MergeDown="1" ss:StyleID="Column">
<Data ss:Type="String">Котельная</Data>
</Cell>
<Cell ss:MergeDown="1" ss:StyleID="Column">
<Data ss:Type="String">Адрес</Data>
</Cell>
<Cell ss:MergeDown="1" ss:StyleID="Column">
<Data ss:Type="String">Кол-во домов</Data>
</Cell>
<Cell ss:MergeDown="1" ss:StyleID="Column">
<Data ss:Type="String">Этаж.</Data>
</Cell>
<Cell ss:MergeDown="1" ss:StyleID="Column">
<Data ss:Type="String">Общая пл.</Data>
</Cell>
<Cell ss:MergeDown="1" ss:StyleID="Column">
<Data ss:Type="String">Кол-во прожив.</Data>
</Cell>
<Cell ss:MergeAcross="1" ss:StyleID="Column">
<Data ss:Type="String">Отопление</Data>
</Cell>
<Cell ss:MergeAcross="1" ss:StyleID="Column">
<Data ss:Type="String">ГВС</Data>
</Cell>
<Cell ss:MergeAcross="1" ss:StyleID="Column">
<Data ss:Type="String">ХВС</Data>
</Cell>
<Cell ss:MergeAcross="1" ss:StyleID="Column">
<Data ss:Type="String">Канализация</Data>
</Cell>
<Cell ss:MergeDown="1" ss:StyleID="Column">
<Data ss:Type="String">Сальдо исход.</Data>
</Cell>
</Row>
<Row>
<Cell ss:Index="9" ss:StyleID="Column">
<Data ss:Type="String">Объем</Data>
</Cell>
<Cell ss:StyleID="Column">
<Data ss:Type="String">Сумма</Data>
</Cell>
<Cell ss:StyleID="Column">
<Data ss:Type="String">Объем</Data>
</Cell>
<Cell ss:StyleID="Column">
<Data ss:Type="String">Сумма</Data>
</Cell>
<Cell ss:StyleID="Column">
<Data ss:Type="String">Объем</Data>
</Cell>
<Cell ss:StyleID="Column">
<Data ss:Type="String">Сумма</Data>
</Cell>
<Cell ss:StyleID="Column">
<Data ss:Type="String">Объем</Data>
</Cell>
<Cell ss:StyleID="Column">
<Data ss:Type="String">Сумма</Data>
</Cell>
</Row>
<!-- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Данные таблицы >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -->
<xsl:apply-templates select="//Kvp" />
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<FreezePanes />
<FrozenNoSplit />
<SplitHorizontal>2</SplitHorizontal>
<TopRowBottomPane>2</TopRowBottomPane>
<ActivePane>2</ActivePane>
</WorksheetOptions>
</Worksheet>
<Worksheet ss:Name="Договорные подключения">
<Table>
<Column ss:Width="100" />
<Column ss:Width="100" />
<Column ss:Width="100" />
<Column ss:Width="150" />
<Column ss:Width="50" />
<Column ss:Width="50" />
<Column ss:Width="50" />
<Column ss:Width="50" />
<Column ss:Width="50" />
<Column ss:Width="50" />
<Column ss:Width="50" />
<Column ss:Width="50" />
<Column ss:Width="50" />
<Column ss:Width="50" />
<Column ss:Width="70" />
<!-- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Столбцы таблицы >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -->
<Row>
<Cell ss:MergeDown="1" ss:StyleID="Column">
<Data ss:Type="String">Регион</Data>
</Cell>
<Cell ss:MergeDown="1" ss:StyleID="Column">
<Data ss:Type="String">Нас. пункт</Data>
</Cell>
<Cell ss:MergeDown="1" ss:StyleID="Column">
<Data ss:Type="String">Котельная</Data>
</Cell>
<Cell ss:MergeDown="1" ss:StyleID="Column">
<Data ss:Type="String">Наименование</Data>
</Cell>
<Cell ss:MergeDown="1" ss:StyleID="Column">
<Data ss:Type="String">Кол-во объектов</Data>
</Cell>
<Cell ss:MergeDown="1" ss:StyleID="Column">
<Data ss:Type="String">Объем здания</Data>
</Cell>
<Cell ss:MergeAcross="1" ss:StyleID="Column">
<Data ss:Type="String">Отопление</Data>
</Cell>
<Cell ss:MergeAcross="1" ss:StyleID="Column">
<Data ss:Type="String">Подогрев</Data>
</Cell>
<Cell ss:MergeAcross="1" ss:StyleID="Column">
<Data ss:Type="String">ГВС</Data>
</Cell>
<Cell ss:MergeAcross="1" ss:StyleID="Column">
<Data ss:Type="String">ХВС</Data>
</Cell>
<Cell ss:MergeAcross="1" ss:StyleID="Column">
<Data ss:Type="String">Канализация</Data>
</Cell>
<Cell ss:MergeDown="1" ss:StyleID="Column">
<Data ss:Type="String">Итого</Data>
</Cell>
</Row>
<Row>
<Cell ss:Index="7" ss:StyleID="Column">
<Data ss:Type="String">Объем</Data>
</Cell>
<Cell ss:StyleID="Column">
<Data ss:Type="String">Сумма</Data>
</Cell>
<Cell ss:StyleID="Column">
<Data ss:Type="String">Объем</Data>
</Cell>
<Cell ss:StyleID="Column">
<Data ss:Type="String">Сумма</Data>
</Cell>
<Cell ss:StyleID="Column">
<Data ss:Type="String">Объем</Data>
</Cell>
<Cell ss:StyleID="Column">
<Data ss:Type="String">Сумма</Data>
</Cell>
<Cell ss:StyleID="Column">
<Data ss:Type="String">Объем</Data>
</Cell>
<Cell ss:StyleID="Column">
<Data ss:Type="String">Сумма</Data>
</Cell>
<Cell ss:StyleID="Column">
<Data ss:Type="String">Объем</Data>
</Cell>
<Cell ss:StyleID="Column">
<Data ss:Type="String">Сумма</Data>
</Cell>
</Row>
<!-- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Данные таблицы >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -->
<xsl:apply-templates select="//Jur" />
</Table>
</Worksheet>
</Workbook>
</xsl:template>
<!-- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Шаблон данных >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -->
<xsl:template match="Kvp">
<xsl:choose>
<xsl:when test="style_id = 1">
<!-- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Строка с улусом >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -->
<Row>
<Cell ss:MergeAcross="3" ss:StyleID="Cell1">
<Data ss:Type="String">
<xsl:value-of select="region" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="house_count" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="String" />
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="square" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="people_count" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="volume_heat" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="sum_heat" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="volume_hwater" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="sum_hwater" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="volume_cwater" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="sum_cwater" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="volume_sewers" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="sum_sewers" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="saldo_out" />
</Data>
</Cell>
</Row>
</xsl:when>
<xsl:when test="style_id = 2">
<!-- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Строка с населенным пунктом >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -->
<Row>
<Cell ss:StyleID="Cell2">
<Data ss:Type="String">
<xsl:value-of select="region" />
</Data>
</Cell>
<Cell ss:Index="2" ss:MergeAcross="2" ss:StyleID="Cell2">
<Data ss:Type="String">
<xsl:value-of select="city" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="house_count" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="String" />
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="square" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="people_count" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="volume_heat" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="sum_heat" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="volume_hwater" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="sum_hwater" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="volume_cwater" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="sum_cwater" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="volume_sewers" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="sum_sewers" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="saldo_out" />
</Data>
</Cell>
</Row>
</xsl:when>
<xsl:when test="style_id = 3">
<!-- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Строка с котельной >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -->
<Row>
<Cell ss:StyleID="Cell3">
<Data ss:Type="String">
<xsl:value-of select="region" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="String">
<xsl:value-of select="city" />
</Data>
</Cell>
<Cell ss:Index="3" ss:MergeAcross="1" ss:StyleID="Cell3">
<Data ss:Type="String">
<xsl:value-of select="boiler" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="house_count" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="String" />
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="square" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="people_count" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="volume_heat" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="sum_heat" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="volume_hwater" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="sum_hwater" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="volume_cwater" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="sum_cwater" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="volume_sewers" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="sum_sewers" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="saldo_out" />
</Data>
</Cell>
</Row>
</xsl:when>
<xsl:when test="style_id = 4">
<!-- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Строка с объектами >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -->
<Row>
<Cell ss:StyleID="CellReg">
<Data ss:Type="String">
<xsl:value-of select="region" />
</Data>
</Cell>
<Cell ss:Index="2" ss:StyleID="CellCity">
<Data ss:Type="String">
<xsl:value-of select="city" />
</Data>
</Cell>
<Cell ss:Index="3" ss:StyleID="Cell3">
<Data ss:Type="String">
<xsl:value-of select="boiler" />
</Data>
</Cell>
<Cell ss:MergeAcross="1" ss:Index="4" ss:StyleID="Cell4">
<Data ss:Type="String">
<xsl:value-of select="address" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="floors" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="square" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="people_count" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="volume_heat" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="sum_heat" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="volume_hwater" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="sum_hwater" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="volume_cwater" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="sum_cwater" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="volume_sewers" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="sum_sewers" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="saldo_out" />
</Data>
</Cell>
</Row>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="Jur">
<xsl:choose>
<xsl:when test="style_id = 1">
<!-- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Строка с улусом >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -->
<Row>
<Cell ss:MergeAcross="3" ss:StyleID="Cell1">
<Data ss:Type="String">
<xsl:value-of select="reg" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="count" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="building_volume" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="heat_volume" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="heat_summa" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="gcal_ost" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="gcal_ost_summa" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="hw_vol" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="hw_summa" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="vol_xvs" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="sum_xvs" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="vol_kan" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="sum_kan" />
</Data>
</Cell>
<Cell ss:StyleID="Cell1">
<Data ss:Type="Number">
<xsl:value-of select="all_summa" />
</Data>
</Cell>
</Row>
</xsl:when>
<xsl:when test="style_id = 2">
<!-- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Строка с населенным пунктом >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -->
<Row>
<Cell ss:StyleID="Cell2">
<Data ss:Type="String">
<xsl:value-of select="reg" />
</Data>
</Cell>
<Cell ss:Index="2" ss:MergeAcross="2" ss:StyleID="Cell2">
<Data ss:Type="String">
<xsl:value-of select="city" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="count" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="building_volume" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="heat_volume" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="heat_summa" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="gcal_ost" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="gcal_ost_summa" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="hw_vol" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="hw_summa" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="vol_xvs" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="sum_xvs" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="vol_kan" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="sum_kan" />
</Data>
</Cell>
<Cell ss:StyleID="Cell2">
<Data ss:Type="Number">
<xsl:value-of select="all_summa" />
</Data>
</Cell>
</Row>
</xsl:when>
<xsl:when test="style_id = 3">
<!-- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Строка с котельной >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -->
<Row>
<Cell ss:StyleID="Cell3">
<Data ss:Type="String">
<xsl:value-of select="reg" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="String">
<xsl:value-of select="city" />
</Data>
</Cell>
<Cell ss:Index="3" ss:MergeAcross="1" ss:StyleID="Cell3">
<Data ss:Type="String">
<xsl:value-of select="boiler" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="count" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="building_volume" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="heat_volume" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="heat_summa" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="gcal_ost" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="gcal_ost_summa" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="hw_vol" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="hw_summa" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="vol_xvs" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="sum_xvs" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="vol_kan" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="sum_kan" />
</Data>
</Cell>
<Cell ss:StyleID="Cell3">
<Data ss:Type="Number">
<xsl:value-of select="all_summa" />
</Data>
</Cell>
</Row>
</xsl:when>
<xsl:when test="style_id = 4">
<!-- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Строка с объектами >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -->
<Row>
<Cell ss:StyleID="CellReg">
<Data ss:Type="String">
<xsl:value-of select="reg" />
</Data>
</Cell>
<Cell ss:Index="2" ss:StyleID="CellCity">
<Data ss:Type="String">
<xsl:value-of select="city" />
</Data>
</Cell>
<Cell ss:Index="3" ss:StyleID="Cell3">
<Data ss:Type="String">
<xsl:value-of select="boiler" />
</Data>
</Cell>
<Cell ss:MergeAcross="1" ss:Index="4" ss:StyleID="Cell4">
<Data ss:Type="String">
<xsl:value-of select="name" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="building_volume" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="heat_volume" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="heat_summa" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="gcal_ost" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="gcal_ost_summa" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="hw_vol" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="hw_summa" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="vol_xvs" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="sum_xvs" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="vol_kan" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="sum_kan" />
</Data>
</Cell>
<Cell ss:StyleID="Cell4">
<Data ss:Type="Number">
<xsl:value-of select="all_summa" />
</Data>
</Cell>
</Row>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>`
const handleGenerateExcel = () => {
// Define the example XML data
const xmlData = `
<root>
<Kvp>
<style_id>1</style_id>
<region>Region 1</region>
<city>City 1</city>
<house_count>10</house_count>
<square>1000</square>
<people_count>500</people_count>
<volume_heat>200</volume_heat>
<sum_heat>1000</sum_heat>
<volume_hwater>300</volume_hwater>
<sum_hwater>1500</sum_hwater>
<volume_cwater>400</volume_cwater>
<sum_cwater>2000</sum_cwater>
<volume_sewers>500</volume_sewers>
<sum_sewers>2500</sum_sewers>
<saldo_out>300</saldo_out>
</Kvp>
</root>
`
// 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")
// Apply the transformation
const xsltProcessor = new XSLTProcessor()
xsltProcessor.importStylesheet(xslDoc)
const resultDocument = xsltProcessor.transformToDocument(xmlDoc)
// Serialize the result to a string
const serializer = new XMLSerializer()
const resultXml = serializer.serializeToString(resultDocument)
// Add missing Excel-specific headers if needed
const correctedXml = `<?xml version="1.0" encoding="utf-8"?>\n` + resultXml
// 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()
URL.revokeObjectURL(url)
}
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 (
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
<div style={{ display: 'flex', flexDirection: 'column', width: '100%' }} key={command.code}>
{
fields.map((field, index) => (
<div style={{ display: 'flex', width: '100%', justifyContent: 'space-between', alignItems: '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 appearance='subtle' onClick={() => {
remove(index)
}}>
<IconX />
</Button>
</div>
))
}
</div>
<Button icon={<IconPlus />} onClick={() => {
if (command.children) {
append(command.children.map(c => c.code).reduce((acc, key) => {
acc[key] = '';
return acc;
}, {} as Record<string, string>))
}
}} />
</div>
)
}
const IMAGE_MIME_TYPE = ["image/png", "image/jpeg", "image/jpg", "image/webp"];
const renderCommand = (
control: Control<FieldValues, any>,
register: UseFormRegister<FieldValues>,
command: CommandSummary,
label: string,
key: string,
name: string,
) => {
if (command.type === 'INS') {
return (
<Field label={label}
key={key}>
<Input {...register(name)} />
</Field>
)
}
if (command.type === 'IMAGE') {
const inputId = useId("file-input");
return (
<div style={{ display: 'flex', flexDirection: 'column' }}>
<Text size={200} weight="semibold">{command.code}</Text>
<Controller
name={name}
control={control}
render={({ field: { onChange } }) => {
const handleFiles = (files: FileList | null) => {
if (!files || files.length === 0) return;
const file = files[0];
if (!IMAGE_MIME_TYPE.includes(file.type)) {
console.log("Rejected file:", file);
return;
}
file.arrayBuffer().then((res) => {
onChange({
width: 6,
height: 6,
data: new Uint8Array(res),
extension: file.name.match(/\.[^.]+$/)?.[0] || "",
});
});
};
const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
handleFiles(e.dataTransfer.files);
};
return (
<div
onDragOver={(e) => e.preventDefault()}
onDrop={handleDrop}
style={{
border: `2px dashed ${tokens.colorNeutralStroke1}`,
borderRadius: tokens.borderRadiusLarge,
minHeight: "220px",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
gap: "1rem",
padding: "1rem",
textAlign: "center",
cursor: "pointer",
}}
onClick={() => document.getElementById(inputId)?.click()}
>
<input
id={inputId}
type="file"
accept={IMAGE_MIME_TYPE.join(",")}
style={{ display: "none" }}
onChange={(e) => handleFiles(e.target.files)}
/>
<ArrowUploadRegular fontSize={40} color={tokens.colorBrandForeground1} />
<Text size={300}>
Перетащите изображение сюда или нажмите, чтобы выбрать
</Text>
</div>
);
}}
/>
</div>
)
}
}
const TemplateForm = ({
templateUrl,
}: {
templateUrl: string,
}) => {
const { register, control, handleSubmit } = 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])
useEffect(() => {
console.log(loading)
}, [loading])
useEffect(() => {
console.log(saving)
}, [saving])
if (commandList) {
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div style={{ display: 'flex', flexDirection: 'column' }}>
{commandList.map(command => {
if (command.type === 'FOR') {
return (
<div style={{ display: 'flex', flexDirection: 'column' }} key={command.code}>
<Text size={200} weight='semibold'>{command.code}</Text>
<FormLoop control={control} register={register} command={command} />
</div>
)
} else {
return renderCommand(control, register, command, command.code, command.code, command.code)
}
})}
<Button style={{ marginLeft: 'auto', width: 'fit-content' }} type='submit'>Сохранить</Button>
</div>
</form>
)
}
}
const PrintReport = () => {
return (
<div style={{ display: 'flex', flexDirection: 'column', padding: '1rem', gap: '1rem', width: '100%' }}>
<TemplateForm templateUrl="/template_table.docx" />
<div style={{ display: 'flex', gap: '1rem' }}>
<Button onClick={handleGenerateExcel}>Сохранить в Excel</Button>
</div>
</div>
)
}
export default PrintReport