From 84a82c38eb5bffeef9e1f1a9304f19a24803358b Mon Sep 17 00:00:00 2001 From: popovspiridon99 Date: Fri, 24 Oct 2025 15:43:39 +0900 Subject: [PATCH] grouped object parameters --- client/src/components/map/GTCBParameter.tsx | 109 ++++++++++++++++++ client/src/components/map/MapComponent.tsx | 2 +- client/src/components/map/ObjectParameter.tsx | 93 ++++++++++----- .../map/ObjectParameters/ObjectParameters.tsx | 44 +++---- client/src/components/map/TCBParameter.tsx | 37 +++--- client/src/components/map/TableValue.tsx | 40 ++++--- client/src/interfaces/objects.ts | 59 +++++----- server/src/general/general.service.ts | 81 +++++++++++-- 8 files changed, 334 insertions(+), 131 deletions(-) create mode 100644 client/src/components/map/GTCBParameter.tsx diff --git a/client/src/components/map/GTCBParameter.tsx b/client/src/components/map/GTCBParameter.tsx new file mode 100644 index 0000000..f1fec6c --- /dev/null +++ b/client/src/components/map/GTCBParameter.tsx @@ -0,0 +1,109 @@ +import TableValue from './TableValue' +import { Text } from '@fluentui/react-components'; +import { IObjectValue } from '../../interfaces/objects'; + +interface ITCBParameterProps { + values: IObjectValue[]; + vtable: string; + inactive?: boolean; + name: string; + map_id: string; +} + +const GTCBParameter = ({ + values, + vtable, + name, + map_id +}: ITCBParameterProps) => { + //Get value + // const { data: tcbValue } = useSWR( + // value ? `/general/params/tcb?id=${value}&vtable=${vtable}` : null, + // (url) => fetcher(url, BASE_URL.ems).then(res => res[0]), + // { + // revalidateOnFocus: false, + // revalidateIfStale: false + // } + // ) + + const tables = [ + 'BoilersTemper', + 'FuelsParametrs', + 'PipesTypes', + 'vAddRepairEvent', + 'vApartmentTypes', + 'vBoilers', + 'vBoilersAppointment', + 'vBoilersBalance', + 'vBoilersCondition', + 'vBoilersFuels', + 'vBoilersHotWater', + 'vBoilersPerimeter', + 'vBoilersPeriods', + 'vBoilersScheme', + 'vBoilersState', + 'vBoilersTypes', + 'vBuildingManagement', + 'vBuildingOwner', + 'vCanalization', + 'vColdWaterTypes', + 'vConditionEquipment', + 'vCovering', + 'vDensityWater', + 'vDryer', + 'vElectroSupplyTypes', + 'vEquipmentsTypes', + 'vFoundation', + 'vFuelsFeed', + 'vGasSupplyTypes', + 'vHeatingTypes', + 'vHeatTransfer', + 'vHotWaterTypes', + 'vMaterialsWall', + 'vNormative', + 'vPeriodHW', + 'vPipeDiameters', + 'vPipeOutDiameters', + 'vPipesBearingType', + 'vPipesCovering', + 'vPipesEvent', + 'vPipesGround', + 'vPipesIsolation', + 'vPipesLayer', + 'vPipesMaterial', + 'vPumpType', + 'vRepairEvent', + 'vRoof', + 'vRPSType', + 'vServe', + 'vStreets', + 'vTechStatus', + 'vTrash', + 'vTrashStorage', + 'vVentilation', + 'vValvingType', + 'vWallingEquipment', + 'tTypes', + ] + + const TCBValue = (vtable: string) => { + if (tables.includes(vtable)) { + return ( + + ) + } else { + return ( + + {JSON.stringify(name)} + {JSON.stringify(Array.isArray(values) && values.length > 0 && values[0].value)} + + ) + } + } + + return ( + TCBValue(vtable) + ) +} + +export default GTCBParameter \ No newline at end of file diff --git a/client/src/components/map/MapComponent.tsx b/client/src/components/map/MapComponent.tsx index aa208f3..becf884 100644 --- a/client/src/components/map/MapComponent.tsx +++ b/client/src/components/map/MapComponent.tsx @@ -156,7 +156,7 @@ const MapComponent = ({ marker.setStyle(new Style({ image: new Icon({ - src: 'public/map_pin_icon.svg', + src: '/map_pin_icon.svg', scale: 0.2 }) })) diff --git a/client/src/components/map/ObjectParameter.tsx b/client/src/components/map/ObjectParameter.tsx index 92745cd..a95c975 100644 --- a/client/src/components/map/ObjectParameter.tsx +++ b/client/src/components/map/ObjectParameter.tsx @@ -1,10 +1,7 @@ -import useSWR from 'swr' -import { fetcher } from '../../http/axiosInstance' -import { BASE_URL } from '../../constants' -import { IObjectParam, IParam } from '../../interfaces/objects' +import { IObjectParam, IObjectValue } from '../../interfaces/objects' import TCBParameter from './TCBParameter' import TableValue from './TableValue' -import { TableCell, TableCellLayout, TableRow } from '@fluentui/react-components' +import { Accordion, AccordionHeader, AccordionItem, AccordionPanel, Table, TableBody, TableCell, TableCellLayout, TableRow, Text } from '@fluentui/react-components' interface ObjectParameterProps { showLabel?: boolean; @@ -16,61 +13,73 @@ const ObjectParameter = ({ param, map_id }: ObjectParameterProps) => { - const { data: paramData } = useSWR( - `/general/params/?param_id=${param.id_param}`, - (url) => fetcher(url, BASE_URL.ems).then(res => res[0] as IParam), - { - revalidateOnFocus: false, - revalidateIfStale: false - } - ) - const Parameter = (type: string, name: string, value: unknown, vtable: string, unit: string | null) => { + const Parameter = (type: string, name: string, values: IObjectValue[], vtable: string, unit: string | null) => { switch (type) { case 'bit': return ( - + ) case 'int': return ( - + + ) + case 'smallint': + return ( + ) case 'bigint': return ( - + ) case 'tinyint': return ( - + + ) + case 'smalldatetime': + return ( + ) // TODO: Calculate from calc procedures case 'calculate': return ( - + ) case 'GTCB': return ( - + ) case 'TCB': return ( - + ) case type.match(/varchar\((\d+)\)/)?.input: return ( - + ) case type.match(/numeric\((\d+),(\d+)\)/)?.input: return ( - + ) case 'year': return ( - + ) case 'uniqueidentifier': return ( - + + ) + case 'group': + return ( + + ) + case 'groupcalculate': + return ( + + ) + case 'array': + return ( + ) default: return ( @@ -83,7 +92,7 @@ const ObjectParameter = ({ - {value as string} + {values[0].value as string} @@ -93,9 +102,37 @@ const ObjectParameter = ({ return ( <> - {paramData && - Parameter(paramData.format, paramData.name, param.value, paramData.vtable, paramData.unit) + {param && param.parameters && Array.isArray(param.parameters) && param.parameters.length > 0 ? + + + + + + + {param.name} + + + + + + {param.parameters.length > 0 && + param.parameters.map((p, index) => ( + + )) + } + +
+
+
+
+
+
+
+ + : + param && Parameter(param.format, param.name, param.values, param.vtable, param.unit) } + ) } diff --git a/client/src/components/map/ObjectParameters/ObjectParameters.tsx b/client/src/components/map/ObjectParameters/ObjectParameters.tsx index 7ed396e..f63bbab 100644 --- a/client/src/components/map/ObjectParameters/ObjectParameters.tsx +++ b/client/src/components/map/ObjectParameters/ObjectParameters.tsx @@ -4,7 +4,7 @@ import useSWR from 'swr'; import { BASE_URL } from '../../../constants'; import { fetcher } from '../../../http/axiosInstance'; import { useObjectsStore } from '../../../store/objects'; -import { Spinner, Table, TableBody } from '@fluentui/react-components'; +import { Spinner, Table, TableBody, TableHeader, TableHeaderCell, TableRow } from '@fluentui/react-components'; const ObjectParameters = ({ map_id @@ -41,38 +41,20 @@ const ObjectParameters = ({ )} - +
+ + + Параметр + + Значение + + + {Array.isArray(valuesData) && - Object.entries( - valuesData.reduce((acc, param) => { - if (!acc[param.id_param]) { - acc[param.id_param] = []; - } - acc[param.id_param].push(param); - return acc; - }, {} as Record) - ).map(([id_param, params]) => { - // Step 1: Sort the parameters by date_s (start date) and date_po (end date) - const sortedParams = (params as IObjectParam[]).sort((b, a) => { - const dateA = new Date(a.date_s || 0); - const dateB = new Date(b.date_s || 0); - return dateA.getTime() - dateB.getTime(); - }); - - return sortedParams.length > 1 ? ( - sortedParams.map((param: IObjectParam) => { - if (param.date_po == null) { - return ( - - ) - } - } - ) - ) : ( - - ); - }) + valuesData.map((param: IObjectParam) => ( + + )) }
diff --git a/client/src/components/map/TCBParameter.tsx b/client/src/components/map/TCBParameter.tsx index 78c2390..521e2cc 100644 --- a/client/src/components/map/TCBParameter.tsx +++ b/client/src/components/map/TCBParameter.tsx @@ -1,11 +1,9 @@ -import useSWR from 'swr' -import { fetcher } from '../../http/axiosInstance' -import { BASE_URL } from '../../constants' import TableValue from './TableValue' import { Text } from '@fluentui/react-components'; +import { IObjectValue } from '../../interfaces/objects'; interface ITCBParameterProps { - value: string; + values: IObjectValue[]; vtable: string; inactive?: boolean; name: string; @@ -13,27 +11,27 @@ interface ITCBParameterProps { } const TCBParameter = ({ - value, + values, vtable, name, map_id }: ITCBParameterProps) => { - //Get value - const { data: tcbValue } = useSWR( - `/general/params/tcb?id=${value}&vtable=${vtable}`, - (url) => fetcher(url, BASE_URL.ems).then(res => res[0]), - { - revalidateOnFocus: false, - revalidateIfStale: false - } - ) + // const { data: tcbValue } = useSWR( + // value ? `/general/params/tcb?id=${value}&vtable=${vtable}` : null, + // (url) => fetcher(url, BASE_URL.ems).then(res => res[0]), + // { + // revalidateOnFocus: false, + // revalidateIfStale: false + // } + // ) const tables = [ 'BoilersTemper', 'FuelsParametrs', 'PipesTypes', 'vAddRepairEvent', + 'vApartmentTypes', 'vBoilers', 'vBoilersAppointment', 'vBoilersBalance', @@ -51,6 +49,7 @@ const TCBParameter = ({ 'vColdWaterTypes', 'vConditionEquipment', 'vCovering', + 'vDensityWater', 'vDryer', 'vElectroSupplyTypes', 'vEquipmentsTypes', @@ -62,21 +61,27 @@ const TCBParameter = ({ 'vHotWaterTypes', 'vMaterialsWall', 'vNormative', + 'vPeriodHW', 'vPipeDiameters', 'vPipeOutDiameters', 'vPipesBearingType', 'vPipesCovering', + 'vPipesEvent', 'vPipesGround', 'vPipesIsolation', 'vPipesLayer', 'vPipesMaterial', + 'vPumpType', 'vRepairEvent', 'vRoof', 'vRPSType', + 'vServe', 'vStreets', 'vTechStatus', 'vTrash', + 'vTrashStorage', 'vVentilation', + 'vValvingType', 'vWallingEquipment', 'tTypes', ] @@ -84,13 +89,13 @@ const TCBParameter = ({ const TCBValue = (vtable: string) => { if (tables.includes(vtable)) { return ( - + ) } else { return ( {JSON.stringify(name)} - {JSON.stringify(tcbValue)} + {JSON.stringify(Array.isArray(values) && values.length > 0 && values[0].value)} ) } diff --git a/client/src/components/map/TableValue.tsx b/client/src/components/map/TableValue.tsx index 312452a..8bb0aac 100644 --- a/client/src/components/map/TableValue.tsx +++ b/client/src/components/map/TableValue.tsx @@ -2,11 +2,13 @@ import useSWR from 'swr'; import { fetcher } from '../../http/axiosInstance'; import { BASE_URL } from '../../constants'; import { useObjectsStore } from '../../store/objects'; -import { Checkbox, Input, Select, TableCell, TableCellLayout, TableRow, Text } from '@fluentui/react-components'; +import { Input, Select, TableCell, TableCellLayout, TableRow, Text } from '@fluentui/react-components'; +import { useState } from 'react'; +import { IObjectValue } from '../../interfaces/objects'; interface TableValueProps { name: string; - value: unknown; + values: IObjectValue[]; type: 'value' | 'boolean' | 'number' | 'select' | 'string'; unit?: string | null | undefined; vtable?: string; @@ -15,14 +17,17 @@ interface TableValueProps { const TableValue = ({ name, - value, + values, type, unit, vtable, map_id }: TableValueProps) => { const { selectedDistrict } = useObjectsStore().id[map_id] + //Get available values + const [value] = useState(Array.isArray(values) && values.length > 0 ? values[0].value : null) + const { data: tcbAll, isValidating } = useSWR( type === 'select' && selectedDistrict ? `/general/params/tcb?vtable=${vtable}&id_city=${selectedDistrict}` : null, (url) => fetcher(url, BASE_URL.ems).then(res => { @@ -42,22 +47,22 @@ const TableValue = ({ return ( - - {name as string} + + {name as string} - +
{type === 'boolean' ? - // - + + // : type === 'number' ? { }} - contentAfter={unit ? ` ${unit}` : ''} + contentAfter={unit ? {unit} : undefined} //displayValue={unit ? ` ${unit}` : ''} /> : @@ -81,7 +86,10 @@ const TableValue = ({ type === 'string' ? : - {value as string} + type === 'value' ? + + : + {value as string} }
diff --git a/client/src/interfaces/objects.ts b/client/src/interfaces/objects.ts index 134a104..247ebd5 100644 --- a/client/src/interfaces/objects.ts +++ b/client/src/interfaces/objects.ts @@ -1,44 +1,45 @@ export interface IObjectList { - id: number, - name: string, + id: number + name: string count: number } export interface IObjectData { - object_id: string, - id_city: number, - year: number, - id_parent: number | null, - type: number, - planning: boolean, - activity: boolean, - kvr: string | null, - jur: string | null, - fuel: string | null, + object_id: string + id_city: number + year: number + id_parent: number | null + type: number + planning: boolean + activity: boolean + kvr: string | null + jur: string | null + fuel: string | null boiler_id: string | null } -export interface IObjectParam { - id_object: string, - id_param: number, - value: string, - date_s: string | null, - date_po: string | null, - id_user: number +export interface IObjectValue { + value: any + date_s: string | null + date_po: string | null } -export interface IParam { - id: number, - id_group: number | null, - name: string, - format: string, - vtable: string, - unit: string | null, - exact_format: string | null, - inHistory: string | null +export interface IObjectParam { + id_object: string + id_param: number + name: string + date_s: string | null + date_po: string | null + id_user: number + format: string + vtable: string + exact_format: string | null + unit: string | null + values: IObjectValue[] + parameters?: IObjectParam[] } export interface IObjectType { - id: number, + id: number name: string } \ No newline at end of file diff --git a/server/src/general/general.service.ts b/server/src/general/general.service.ts index d04b6a8..e392a7a 100644 --- a/server/src/general/general.service.ts +++ b/server/src/general/general.service.ts @@ -181,20 +181,81 @@ export class GeneralService { } async getValuesByObjectId(object_id: string): Promise { - const generalDatabase = 'nGeneral' + const generalDatabase = 'nGeneral'; - const result = await this.dataSource.query(` - SELECT id_object, id_param, CAST(v.value AS varchar(max)) AS value, - date_s, - date_po, - id_user - FROM ${generalDatabase}..tValues v - JOIN ${generalDatabase}..tParameters p ON v.id_param = p.id + const parameters = await this.dataSource.query(` + SELECT + pt.id_param, + p.name AS name, + p.id_group, + p.format, + p.vtable, + p.unit, + p.exact_format + FROM ${generalDatabase}..ParametersType pt + JOIN ${generalDatabase}..tParameters p + ON pt.id_param = p.id + WHERE pt.id_type = ( + SELECT TOP 1 CAST(value AS int) + FROM ${generalDatabase}..tValues WHERE id_object = '${object_id}' - `) - return result + AND id_param = 3 + ORDER BY date_s DESC + ) + ORDER BY pt.id_order; + `); + + const values = await this.dataSource.query(` + SELECT + v.id_param, + CAST(v.value AS varchar(max)) AS value, + v.date_s, + v.date_po, + v.id_user + FROM ${generalDatabase}..tValues v + WHERE v.id_object = '${object_id}'; + `); + + const valuesByParam = values.reduce((acc, v) => { + if (!acc[v.id_param]) acc[v.id_param] = []; + acc[v.id_param].push({ + value: v.value, + date_s: v.date_s, + date_po: v.date_po, + id_user: v.id_user + }); + return acc; + }, {} as Record); + + const grouped = parameters + .filter(p => p.id_group == null) + .map(parent => ({ + id_param: parent.id_param, + name: parent.name, + format: parent.format, + vtable: parent.vtable, + unit: parent.unit, + exact_format: parent.exact_format, + values: valuesByParam[parent.id_param] || [], + parameters: parameters + .filter(child => child.id_group === parent.id_param) + .map(child => ({ + id_param: child.id_param, + name: child.name, + id_group: child.id_group, + format: child.format, + vtable: child.vtable, + unit: child.unit, + exact_format: child.exact_format, + values: valuesByParam[child.id_param] || [] + })) + })); + + return grouped; } + + async getParamsById(param_id: number): Promise { const generalDatabase = 'nGeneral'