From 3dae039765fbd2bf904a986e4b687ef8552dd02b Mon Sep 17 00:00:00 2001 From: YangJinSoo94 Date: Tue, 15 Jul 2025 20:54:38 +0900 Subject: [PATCH] first init --- apps/fo/.env.development | 12 + apps/fo/.env.local | 13 + apps/fo/.gitignore | 41 + apps/fo/app/components/api/config/env.ts | 12 + apps/fo/app/components/api/config/index.ts | 1 + apps/fo/app/components/api/index.ts | 79 + apps/fo/app/components/common/DataForm.tsx | 46 + .../common/FacilityTermModalHeader.tsx | 279 +++ .../common/FacilityTermModalHeaderMonth.tsx | 276 +++ .../app/components/common/HeadMakeColSpan.tsx | 65 + apps/fo/app/components/common/SearchInput.tsx | 108 + apps/fo/app/favicon.ico | Bin 0 -> 25931 bytes apps/fo/app/globals.css | 7 + apps/fo/app/layout.tsx | 24 + apps/fo/app/page.tsx | 44 + .../dashboard/drainageEquipment/page.tsx | 98 + .../dashboard/facilityInfo/modal/page.tsx | 184 ++ .../app/pages/dashboard/facilityInfo/page.tsx | 277 +++ .../fo/app/pages/dashboard/maingraph/page.tsx | 243 +++ apps/fo/app/pages/dashboard/page.tsx | 306 +++ .../app/pages/dashboard/rainManage/page.tsx | 59 + apps/fo/app/pages/dashboardMain/page.tsx | 58 + .../facilityPrecipitation/modal/page.tsx | 203 ++ .../app/pages/facilityPrecipitation/page.tsx | 249 +++ .../facilityWaterQlty/HeadMakeColSpan.tsx | 176 ++ .../pages/facilityWaterQlty/modal/page.tsx | 537 +++++ apps/fo/app/pages/facilityWaterQlty/page.tsx | 208 ++ apps/fo/app/pages/flowRate/modal/page.tsx | 238 +++ apps/fo/app/pages/flowRate/page.tsx | 207 ++ apps/fo/app/pages/map/page.tsx | 145 ++ apps/fo/app/pages/planSewage/page.tsx | 197 ++ .../app/pages/processArea/HeadMakeColSpan.tsx | 87 + apps/fo/app/pages/processArea/modal/page.tsx | 55 + apps/fo/app/pages/processArea/page.tsx | 172 ++ .../app/pages/processFacility/modal/page.tsx | 211 ++ apps/fo/app/pages/processFacility/page.tsx | 294 +++ apps/fo/app/pages/rdi/page.tsx | 200 ++ apps/fo/app/pages/sewageOccur/modal/page.tsx | 161 ++ apps/fo/app/pages/sewageOccur/page.tsx | 237 +++ .../app/pages/underWaterInput/modal/page.tsx | 317 +++ apps/fo/app/pages/underWaterInput/page.tsx | 237 +++ apps/fo/app/store/common/index.tsx | 375 ++++ apps/fo/app/store/dashboard/index.tsx | 1866 +++++++++++++++++ .../app/store/facilityPrecipitation/index.tsx | 307 +++ apps/fo/app/store/facilityWaterQlty/index.tsx | 644 ++++++ apps/fo/app/store/flowRate/index.tsx | 355 ++++ apps/fo/app/store/index.tsx | 45 + apps/fo/app/store/planSewage/index.tsx | 226 ++ apps/fo/app/store/processArea/index.tsx | 507 +++++ apps/fo/app/store/processFacility/index.tsx | 832 ++++++++ .../store/publicReuseFaciltyInsert/index.tsx | 97 + apps/fo/app/store/rdi/index.tsx | 274 +++ apps/fo/app/store/sewageOccur/index.tsx | 464 ++++ apps/fo/app/store/store.tsx | 78 + apps/fo/app/store/underWaterInput/index.tsx | 397 ++++ apps/fo/components.json | 21 + apps/fo/eslint.config.mjs | 16 + apps/fo/middleware.ts | 115 + apps/fo/next.config.ts | 33 + apps/fo/package.json | 29 + apps/fo/postcss.config.mjs | 8 + apps/fo/public/file.svg | 1 + apps/fo/public/globe.svg | 1 + .../images/map/layericon/BML_CBAS_PS.png | Bin 0 -> 1547 bytes .../images/map/layericon/BML_ELEV_PS.png | Bin 0 -> 1030 bytes .../images/map/layericon/BML_ETCP_PS.png | Bin 0 -> 961 bytes .../images/map/layericon/BML_STMS_PS.png | Bin 0 -> 1542 bytes .../images/map/layericon/BML_SYMB_PS.png | Bin 0 -> 970 bytes .../images/map/layericon/RDL_BYST_PS.png | Bin 0 -> 1196 bytes .../images/map/layericon/RDL_CROS_PS.png | Bin 0 -> 1083 bytes .../images/map/layericon/RDL_ETCT_PS.png | Bin 0 -> 1016 bytes .../images/map/layericon/RDL_OCUP_PS.png | Bin 0 -> 1061 bytes .../images/map/layericon/RDL_RDSN_PS.png | Bin 0 -> 1313 bytes .../images/map/layericon/RDL_SCLT_PS.png | Bin 0 -> 1072 bytes .../images/map/layericon/RDL_SEPC_PS.png | Bin 0 -> 1068 bytes .../images/map/layericon/RDL_STAT_PS.png | Bin 0 -> 1075 bytes .../images/map/layericon/RDL_STLT_PS.png | Bin 0 -> 1089 bytes .../images/map/layericon/RDL_TFSN_PS.png | Bin 0 -> 1291 bytes .../images/map/layericon/RDL_TRCT_PS.png | Bin 0 -> 1412 bytes .../images/map/layericon/RDL_TREE_PS.png | Bin 0 -> 1136 bytes .../images/map/layericon/RDL_TRSN_PS.png | Bin 0 -> 1375 bytes .../images/map/layericon/RDL_TSCT_PS.png | Bin 0 -> 1700 bytes .../images/map/layericon/SWL_CLAY_PS.png | Bin 0 -> 1146 bytes .../images/map/layericon/SWL_CLAY_PS_RED.png | Bin 0 -> 468 bytes .../images/map/layericon/SWL_DEPT_PS.png | Bin 0 -> 1079 bytes .../images/map/layericon/SWL_MANH_PS.png | Bin 0 -> 1559 bytes .../map/layericon/SWL_MANH_PS_BLACK.png | Bin 0 -> 757 bytes .../images/map/layericon/SWL_MANH_PS_BLUE.png | Bin 0 -> 785 bytes .../images/map/layericon/SWL_MANH_PS_GRAY.png | Bin 0 -> 1054 bytes .../map/layericon/SWL_MANH_PS_GREEN.png | Bin 0 -> 791 bytes .../images/map/layericon/SWL_MANH_PS_RED.png | Bin 0 -> 782 bytes .../map/layericon/SWL_MANH_PS_YELLOW.png | Bin 0 -> 782 bytes .../images/map/layericon/SWL_SPEW_PS.png | Bin 0 -> 1217 bytes .../images/map/layericon/SWL_SPOT_PS.png | Bin 0 -> 1067 bytes .../map/layericon/SWL_SPOT_PS_BLACK.png | Bin 0 -> 217 bytes .../images/map/layericon/SWL_SPOT_PS_BLUE.png | Bin 0 -> 217 bytes .../map/layericon/SWL_SPOT_PS_GREEN.png | Bin 0 -> 217 bytes .../images/map/layericon/SWL_SPOT_PS_GREY.png | Bin 0 -> 217 bytes .../images/map/layericon/SWL_SPOT_PS_RED.png | Bin 0 -> 217 bytes .../images/map/layericon/SWL_VENT_PS.png | Bin 0 -> 1033 bytes .../images/map/layericon/TL_SPBD_ENTRC.png | Bin 0 -> 1260 bytes .../images/map/layericon/TL_SPGF_LOC.png | Bin 0 -> 1383 bytes .../images/map/layericon/TL_SPOT_NOIN.png | Bin 0 -> 1009 bytes .../images/map/layericon/TL_SPRD_BANO.png | Bin 0 -> 1044 bytes .../images/map/layericon/TL_SPRD_CRSRD.png | Bin 0 -> 1083 bytes .../images/map/layericon/TL_SPRD_NONM.png | Bin 0 -> 1049 bytes .../images/map/layericon/TL_SPRD_RENM.png | Bin 0 -> 1009 bytes .../images/map/layericon/TL_SPRD_RWNM.png | Bin 0 -> 1049 bytes .../images/map/layericon/UFL_BMAN_PS.png | Bin 0 -> 1552 bytes .../images/map/layericon/UFL_BOPC_PS.png | Bin 0 -> 1132 bytes .../images/map/layericon/UFL_BPIP_PS.png | Bin 0 -> 1017 bytes .../images/map/layericon/UFL_BPOL_PS.png | Bin 0 -> 1193 bytes .../images/map/layericon/UFL_BTRS_PS.png | Bin 0 -> 1097 bytes .../images/map/layericon/UFL_GMNT_PS.png | Bin 0 -> 1166 bytes .../images/map/layericon/UFL_GPIP_PS.png | Bin 0 -> 1103 bytes .../images/map/layericon/UFL_GPRS_PS.png | Bin 0 -> 1408 bytes .../images/map/layericon/UFL_GVAL_PS.png | Bin 0 -> 1426 bytes .../images/map/layericon/UFL_KMAN_PS.png | Bin 0 -> 1572 bytes .../images/map/layericon/UFL_KPOL_PS.png | Bin 0 -> 1122 bytes .../images/map/layericon/UFL_VALV_PS.png | Bin 0 -> 1058 bytes .../images/map/layericon/WTL_FIRE_PS.png | Bin 0 -> 1072 bytes .../images/map/layericon/WTL_FLOW_PS.png | Bin 0 -> 1137 bytes .../images/map/layericon/WTL_MANH_PS.png | Bin 0 -> 1557 bytes .../images/map/layericon/WTL_META_PS.png | Bin 0 -> 1100 bytes .../images/map/layericon/WTL_PIPE_PS.png | Bin 0 -> 1075 bytes .../images/map/layericon/WTL_RSRV_PS.png | Bin 0 -> 1057 bytes .../images/map/layericon/WTL_RSRV_PS_GRAY.png | Bin 0 -> 259 bytes .../images/map/layericon/WTL_VALV_PS.png | Bin 0 -> 1077 bytes .../public/images/map/layericon/default.png | Bin 0 -> 160 bytes apps/fo/public/images/map/layericon/reset.png | Bin 0 -> 108 bytes .../public/images/map/toolbar/arrow_down.png | Bin 0 -> 1532 bytes .../public/images/map/toolbar/arrow_right.png | Bin 0 -> 1931 bytes .../images/map/toolbar/backward_icon.png | Bin 0 -> 313 bytes .../images/map/toolbar/btn_cont_area.png | Bin 0 -> 1231 bytes .../images/map/toolbar/btn_cont_area_on.png | Bin 0 -> 1184 bytes .../images/map/toolbar/btn_cont_next.png | Bin 0 -> 1256 bytes .../images/map/toolbar/btn_cont_next_on.png | Bin 0 -> 1204 bytes .../images/map/toolbar/btn_cont_prev.png | Bin 0 -> 1265 bytes .../images/map/toolbar/btn_cont_prev_on.png | Bin 0 -> 1223 bytes .../images/map/toolbar/btn_cont_print.png | Bin 0 -> 1318 bytes .../images/map/toolbar/btn_cont_print_on.png | Bin 0 -> 1293 bytes .../images/map/toolbar/btn_cont_ruler.png | Bin 0 -> 1353 bytes .../images/map/toolbar/btn_cont_ruler_on.png | Bin 0 -> 1339 bytes .../images/map/toolbar/btn_cont_save.png | Bin 0 -> 1216 bytes .../images/map/toolbar/btn_cont_save_on.png | Bin 0 -> 1202 bytes .../images/map/toolbar/btn_cont_sketch.png | Bin 0 -> 15103 bytes .../images/map/toolbar/btn_cont_sketch_on.png | Bin 0 -> 14933 bytes .../images/map/toolbar/btn_cont_zoomin.png | Bin 0 -> 1456 bytes .../images/map/toolbar/btn_cont_zoomin_on.png | Bin 0 -> 1423 bytes .../images/map/toolbar/btn_cont_zoomout.png | Bin 0 -> 1395 bytes .../map/toolbar/btn_cont_zoomout_on.png | Bin 0 -> 1376 bytes .../images/map/toolbar/btn_edit_add.png | Bin 0 -> 1169 bytes .../images/map/toolbar/btn_edit_add_on.png | Bin 0 -> 1168 bytes .../images/map/toolbar/btn_edit_del.png | Bin 0 -> 1160 bytes .../images/map/toolbar/btn_edit_del_on.png | Bin 0 -> 1158 bytes .../images/map/toolbar/btn_edit_next.png | Bin 0 -> 1209 bytes .../images/map/toolbar/btn_edit_next_on.png | Bin 0 -> 1205 bytes .../images/map/toolbar/btn_edit_prev.png | Bin 0 -> 1172 bytes .../images/map/toolbar/btn_edit_prev_on.png | Bin 0 -> 1176 bytes .../images/map/toolbar/btn_edit_save.png | Bin 0 -> 1180 bytes .../images/map/toolbar/btn_edit_save_on.png | Bin 0 -> 1190 bytes .../images/map/toolbar/btn_edit_slt.png | Bin 0 -> 1288 bytes .../images/map/toolbar/btn_edit_slt_on.png | Bin 0 -> 1274 bytes .../images/map/toolbar/btn_edit_snap.png | Bin 0 -> 1185 bytes .../images/map/toolbar/btn_edit_snap_on.png | Bin 0 -> 1185 bytes .../public/images/map/toolbar/close_icon.png | Bin 0 -> 313 bytes .../images/map/toolbar/ico_gis_sprite.png | Bin 0 -> 7858 bytes .../images/map/toolbar/icon-viewclose.png | Bin 0 -> 2895 bytes .../images/map/toolbar/img_base_map.png | Bin 0 -> 4537 bytes .../images/map/toolbar/img_network_map.png | Bin 0 -> 4974 bytes .../images/map/toolbar/img_road_map.png | Bin 0 -> 6079 bytes .../images/map/toolbar/img_settle_map.png | Bin 0 -> 7264 bytes apps/fo/public/images/map/toolbar/loading.gif | Bin 0 -> 184974 bytes apps/fo/public/images/map/toolbar/map_pin.png | Bin 0 -> 2362 bytes .../public/images/map/toolbar/toggle_off.png | Bin 0 -> 1591 bytes .../public/images/map/toolbar/toggle_on.png | Bin 0 -> 1612 bytes apps/fo/public/mainDashBoard.xlsx | Bin 0 -> 13783 bytes apps/fo/public/next.svg | 1 + apps/fo/public/vercel.svg | 1 + apps/fo/public/window.svg | 1 + apps/fo/tailwind.config.ts | 12 + apps/fo/tsconfig.json | 54 + 182 files changed, 13123 insertions(+) create mode 100644 apps/fo/.env.development create mode 100644 apps/fo/.env.local create mode 100644 apps/fo/.gitignore create mode 100644 apps/fo/app/components/api/config/env.ts create mode 100644 apps/fo/app/components/api/config/index.ts create mode 100644 apps/fo/app/components/api/index.ts create mode 100644 apps/fo/app/components/common/DataForm.tsx create mode 100644 apps/fo/app/components/common/FacilityTermModalHeader.tsx create mode 100644 apps/fo/app/components/common/FacilityTermModalHeaderMonth.tsx create mode 100644 apps/fo/app/components/common/HeadMakeColSpan.tsx create mode 100644 apps/fo/app/components/common/SearchInput.tsx create mode 100644 apps/fo/app/favicon.ico create mode 100644 apps/fo/app/globals.css create mode 100644 apps/fo/app/layout.tsx create mode 100644 apps/fo/app/page.tsx create mode 100644 apps/fo/app/pages/dashboard/drainageEquipment/page.tsx create mode 100644 apps/fo/app/pages/dashboard/facilityInfo/modal/page.tsx create mode 100644 apps/fo/app/pages/dashboard/facilityInfo/page.tsx create mode 100644 apps/fo/app/pages/dashboard/maingraph/page.tsx create mode 100644 apps/fo/app/pages/dashboard/page.tsx create mode 100644 apps/fo/app/pages/dashboard/rainManage/page.tsx create mode 100644 apps/fo/app/pages/dashboardMain/page.tsx create mode 100644 apps/fo/app/pages/facilityPrecipitation/modal/page.tsx create mode 100644 apps/fo/app/pages/facilityPrecipitation/page.tsx create mode 100644 apps/fo/app/pages/facilityWaterQlty/HeadMakeColSpan.tsx create mode 100644 apps/fo/app/pages/facilityWaterQlty/modal/page.tsx create mode 100644 apps/fo/app/pages/facilityWaterQlty/page.tsx create mode 100644 apps/fo/app/pages/flowRate/modal/page.tsx create mode 100644 apps/fo/app/pages/flowRate/page.tsx create mode 100644 apps/fo/app/pages/map/page.tsx create mode 100644 apps/fo/app/pages/planSewage/page.tsx create mode 100644 apps/fo/app/pages/processArea/HeadMakeColSpan.tsx create mode 100644 apps/fo/app/pages/processArea/modal/page.tsx create mode 100644 apps/fo/app/pages/processArea/page.tsx create mode 100644 apps/fo/app/pages/processFacility/modal/page.tsx create mode 100644 apps/fo/app/pages/processFacility/page.tsx create mode 100644 apps/fo/app/pages/rdi/page.tsx create mode 100644 apps/fo/app/pages/sewageOccur/modal/page.tsx create mode 100644 apps/fo/app/pages/sewageOccur/page.tsx create mode 100644 apps/fo/app/pages/underWaterInput/modal/page.tsx create mode 100644 apps/fo/app/pages/underWaterInput/page.tsx create mode 100644 apps/fo/app/store/common/index.tsx create mode 100644 apps/fo/app/store/dashboard/index.tsx create mode 100644 apps/fo/app/store/facilityPrecipitation/index.tsx create mode 100644 apps/fo/app/store/facilityWaterQlty/index.tsx create mode 100644 apps/fo/app/store/flowRate/index.tsx create mode 100644 apps/fo/app/store/index.tsx create mode 100644 apps/fo/app/store/planSewage/index.tsx create mode 100644 apps/fo/app/store/processArea/index.tsx create mode 100644 apps/fo/app/store/processFacility/index.tsx create mode 100644 apps/fo/app/store/publicReuseFaciltyInsert/index.tsx create mode 100644 apps/fo/app/store/rdi/index.tsx create mode 100644 apps/fo/app/store/sewageOccur/index.tsx create mode 100644 apps/fo/app/store/store.tsx create mode 100644 apps/fo/app/store/underWaterInput/index.tsx create mode 100644 apps/fo/components.json create mode 100644 apps/fo/eslint.config.mjs create mode 100644 apps/fo/middleware.ts create mode 100644 apps/fo/next.config.ts create mode 100644 apps/fo/package.json create mode 100644 apps/fo/postcss.config.mjs create mode 100644 apps/fo/public/file.svg create mode 100644 apps/fo/public/globe.svg create mode 100644 apps/fo/public/images/map/layericon/BML_CBAS_PS.png create mode 100644 apps/fo/public/images/map/layericon/BML_ELEV_PS.png create mode 100644 apps/fo/public/images/map/layericon/BML_ETCP_PS.png create mode 100644 apps/fo/public/images/map/layericon/BML_STMS_PS.png create mode 100644 apps/fo/public/images/map/layericon/BML_SYMB_PS.png create mode 100644 apps/fo/public/images/map/layericon/RDL_BYST_PS.png create mode 100644 apps/fo/public/images/map/layericon/RDL_CROS_PS.png create mode 100644 apps/fo/public/images/map/layericon/RDL_ETCT_PS.png create mode 100644 apps/fo/public/images/map/layericon/RDL_OCUP_PS.png create mode 100644 apps/fo/public/images/map/layericon/RDL_RDSN_PS.png create mode 100644 apps/fo/public/images/map/layericon/RDL_SCLT_PS.png create mode 100644 apps/fo/public/images/map/layericon/RDL_SEPC_PS.png create mode 100644 apps/fo/public/images/map/layericon/RDL_STAT_PS.png create mode 100644 apps/fo/public/images/map/layericon/RDL_STLT_PS.png create mode 100644 apps/fo/public/images/map/layericon/RDL_TFSN_PS.png create mode 100644 apps/fo/public/images/map/layericon/RDL_TRCT_PS.png create mode 100644 apps/fo/public/images/map/layericon/RDL_TREE_PS.png create mode 100644 apps/fo/public/images/map/layericon/RDL_TRSN_PS.png create mode 100644 apps/fo/public/images/map/layericon/RDL_TSCT_PS.png create mode 100644 apps/fo/public/images/map/layericon/SWL_CLAY_PS.png create mode 100644 apps/fo/public/images/map/layericon/SWL_CLAY_PS_RED.png create mode 100644 apps/fo/public/images/map/layericon/SWL_DEPT_PS.png create mode 100644 apps/fo/public/images/map/layericon/SWL_MANH_PS.png create mode 100644 apps/fo/public/images/map/layericon/SWL_MANH_PS_BLACK.png create mode 100644 apps/fo/public/images/map/layericon/SWL_MANH_PS_BLUE.png create mode 100644 apps/fo/public/images/map/layericon/SWL_MANH_PS_GRAY.png create mode 100644 apps/fo/public/images/map/layericon/SWL_MANH_PS_GREEN.png create mode 100644 apps/fo/public/images/map/layericon/SWL_MANH_PS_RED.png create mode 100644 apps/fo/public/images/map/layericon/SWL_MANH_PS_YELLOW.png create mode 100644 apps/fo/public/images/map/layericon/SWL_SPEW_PS.png create mode 100644 apps/fo/public/images/map/layericon/SWL_SPOT_PS.png create mode 100644 apps/fo/public/images/map/layericon/SWL_SPOT_PS_BLACK.png create mode 100644 apps/fo/public/images/map/layericon/SWL_SPOT_PS_BLUE.png create mode 100644 apps/fo/public/images/map/layericon/SWL_SPOT_PS_GREEN.png create mode 100644 apps/fo/public/images/map/layericon/SWL_SPOT_PS_GREY.png create mode 100644 apps/fo/public/images/map/layericon/SWL_SPOT_PS_RED.png create mode 100644 apps/fo/public/images/map/layericon/SWL_VENT_PS.png create mode 100644 apps/fo/public/images/map/layericon/TL_SPBD_ENTRC.png create mode 100644 apps/fo/public/images/map/layericon/TL_SPGF_LOC.png create mode 100644 apps/fo/public/images/map/layericon/TL_SPOT_NOIN.png create mode 100644 apps/fo/public/images/map/layericon/TL_SPRD_BANO.png create mode 100644 apps/fo/public/images/map/layericon/TL_SPRD_CRSRD.png create mode 100644 apps/fo/public/images/map/layericon/TL_SPRD_NONM.png create mode 100644 apps/fo/public/images/map/layericon/TL_SPRD_RENM.png create mode 100644 apps/fo/public/images/map/layericon/TL_SPRD_RWNM.png create mode 100644 apps/fo/public/images/map/layericon/UFL_BMAN_PS.png create mode 100644 apps/fo/public/images/map/layericon/UFL_BOPC_PS.png create mode 100644 apps/fo/public/images/map/layericon/UFL_BPIP_PS.png create mode 100644 apps/fo/public/images/map/layericon/UFL_BPOL_PS.png create mode 100644 apps/fo/public/images/map/layericon/UFL_BTRS_PS.png create mode 100644 apps/fo/public/images/map/layericon/UFL_GMNT_PS.png create mode 100644 apps/fo/public/images/map/layericon/UFL_GPIP_PS.png create mode 100644 apps/fo/public/images/map/layericon/UFL_GPRS_PS.png create mode 100644 apps/fo/public/images/map/layericon/UFL_GVAL_PS.png create mode 100644 apps/fo/public/images/map/layericon/UFL_KMAN_PS.png create mode 100644 apps/fo/public/images/map/layericon/UFL_KPOL_PS.png create mode 100644 apps/fo/public/images/map/layericon/UFL_VALV_PS.png create mode 100644 apps/fo/public/images/map/layericon/WTL_FIRE_PS.png create mode 100644 apps/fo/public/images/map/layericon/WTL_FLOW_PS.png create mode 100644 apps/fo/public/images/map/layericon/WTL_MANH_PS.png create mode 100644 apps/fo/public/images/map/layericon/WTL_META_PS.png create mode 100644 apps/fo/public/images/map/layericon/WTL_PIPE_PS.png create mode 100644 apps/fo/public/images/map/layericon/WTL_RSRV_PS.png create mode 100644 apps/fo/public/images/map/layericon/WTL_RSRV_PS_GRAY.png create mode 100644 apps/fo/public/images/map/layericon/WTL_VALV_PS.png create mode 100644 apps/fo/public/images/map/layericon/default.png create mode 100644 apps/fo/public/images/map/layericon/reset.png create mode 100644 apps/fo/public/images/map/toolbar/arrow_down.png create mode 100644 apps/fo/public/images/map/toolbar/arrow_right.png create mode 100644 apps/fo/public/images/map/toolbar/backward_icon.png create mode 100644 apps/fo/public/images/map/toolbar/btn_cont_area.png create mode 100644 apps/fo/public/images/map/toolbar/btn_cont_area_on.png create mode 100644 apps/fo/public/images/map/toolbar/btn_cont_next.png create mode 100644 apps/fo/public/images/map/toolbar/btn_cont_next_on.png create mode 100644 apps/fo/public/images/map/toolbar/btn_cont_prev.png create mode 100644 apps/fo/public/images/map/toolbar/btn_cont_prev_on.png create mode 100644 apps/fo/public/images/map/toolbar/btn_cont_print.png create mode 100644 apps/fo/public/images/map/toolbar/btn_cont_print_on.png create mode 100644 apps/fo/public/images/map/toolbar/btn_cont_ruler.png create mode 100644 apps/fo/public/images/map/toolbar/btn_cont_ruler_on.png create mode 100644 apps/fo/public/images/map/toolbar/btn_cont_save.png create mode 100644 apps/fo/public/images/map/toolbar/btn_cont_save_on.png create mode 100644 apps/fo/public/images/map/toolbar/btn_cont_sketch.png create mode 100644 apps/fo/public/images/map/toolbar/btn_cont_sketch_on.png create mode 100644 apps/fo/public/images/map/toolbar/btn_cont_zoomin.png create mode 100644 apps/fo/public/images/map/toolbar/btn_cont_zoomin_on.png create mode 100644 apps/fo/public/images/map/toolbar/btn_cont_zoomout.png create mode 100644 apps/fo/public/images/map/toolbar/btn_cont_zoomout_on.png create mode 100644 apps/fo/public/images/map/toolbar/btn_edit_add.png create mode 100644 apps/fo/public/images/map/toolbar/btn_edit_add_on.png create mode 100644 apps/fo/public/images/map/toolbar/btn_edit_del.png create mode 100644 apps/fo/public/images/map/toolbar/btn_edit_del_on.png create mode 100644 apps/fo/public/images/map/toolbar/btn_edit_next.png create mode 100644 apps/fo/public/images/map/toolbar/btn_edit_next_on.png create mode 100644 apps/fo/public/images/map/toolbar/btn_edit_prev.png create mode 100644 apps/fo/public/images/map/toolbar/btn_edit_prev_on.png create mode 100644 apps/fo/public/images/map/toolbar/btn_edit_save.png create mode 100644 apps/fo/public/images/map/toolbar/btn_edit_save_on.png create mode 100644 apps/fo/public/images/map/toolbar/btn_edit_slt.png create mode 100644 apps/fo/public/images/map/toolbar/btn_edit_slt_on.png create mode 100644 apps/fo/public/images/map/toolbar/btn_edit_snap.png create mode 100644 apps/fo/public/images/map/toolbar/btn_edit_snap_on.png create mode 100644 apps/fo/public/images/map/toolbar/close_icon.png create mode 100644 apps/fo/public/images/map/toolbar/ico_gis_sprite.png create mode 100644 apps/fo/public/images/map/toolbar/icon-viewclose.png create mode 100644 apps/fo/public/images/map/toolbar/img_base_map.png create mode 100644 apps/fo/public/images/map/toolbar/img_network_map.png create mode 100644 apps/fo/public/images/map/toolbar/img_road_map.png create mode 100644 apps/fo/public/images/map/toolbar/img_settle_map.png create mode 100644 apps/fo/public/images/map/toolbar/loading.gif create mode 100644 apps/fo/public/images/map/toolbar/map_pin.png create mode 100644 apps/fo/public/images/map/toolbar/toggle_off.png create mode 100644 apps/fo/public/images/map/toolbar/toggle_on.png create mode 100644 apps/fo/public/mainDashBoard.xlsx create mode 100644 apps/fo/public/next.svg create mode 100644 apps/fo/public/vercel.svg create mode 100644 apps/fo/public/window.svg create mode 100644 apps/fo/tailwind.config.ts create mode 100644 apps/fo/tsconfig.json diff --git a/apps/fo/.env.development b/apps/fo/.env.development new file mode 100644 index 000000000..b270a2694 --- /dev/null +++ b/apps/fo/.env.development @@ -0,0 +1,12 @@ +NEXT_PUBLIC_SITE_ID = FO +NEXT_PUBLIC_PORT = 11300 +NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11300 +NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000 +NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver +NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver +NEXT_PUBLIC_CLAIM_NAME = Authorization +NEXT_PUBLIC_AUTH_USER_ID = token-id +NEXT_PUBLIC_ACCESS_TOKEN = access-token +NEXT_PUBLIC_REFRESH_TOKEN = refresh-token + +NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service/api # 개발 서버 API diff --git a/apps/fo/.env.local b/apps/fo/.env.local new file mode 100644 index 000000000..ccb832d70 --- /dev/null +++ b/apps/fo/.env.local @@ -0,0 +1,13 @@ +NEXT_PUBLIC_SITE_ID = FO +NEXT_PUBLIC_PORT = 3000 +NEXT_PUBLIC_PROXY_HOST = http://localhost:3000 +NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000 +NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver +NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver +NEXT_PUBLIC_CLAIM_NAME = Authorization +NEXT_PUBLIC_AUTH_USER_ID = token-id +NEXT_PUBLIC_ACCESS_TOKEN = access-token +NEXT_PUBLIC_REFRESH_TOKEN = refresh-token + +NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service/api # 개발 서버 API +#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.128:8883/sewerage-service/api # 최용성 PC 서버 API diff --git a/apps/fo/.gitignore b/apps/fo/.gitignore new file mode 100644 index 000000000..8c5b2ee3a --- /dev/null +++ b/apps/fo/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +#.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/apps/fo/app/components/api/config/env.ts b/apps/fo/app/components/api/config/env.ts new file mode 100644 index 000000000..22272ecd8 --- /dev/null +++ b/apps/fo/app/components/api/config/env.ts @@ -0,0 +1,12 @@ +const DEV_PORT_COMMON = "11081"; +const DEV_PORT_FO = "11082"; +const DEV_PORT_WR = "11080"; + +export const LOCAL_URL_COMMON = `http://192.168.1.129:${DEV_PORT_COMMON}/api/v1`; +export const DEV_URL_COMMON = `http://con.mind-one.co.kr:${DEV_PORT_COMMON}/api/v1`; + +export const LOCAL_URL_FO = `http://192.168.1.129:${DEV_PORT_FO}/api/v1`; +export const DEV_URL_FO = `http://con.mind-one.co.kr:${DEV_PORT_FO}/api/v1`; + +export const LOCAL_URL_WR = `http://192.168.1.129:${DEV_PORT_WR}/api/v1`; +export const DEV_URL_WR = `http://con.mind-one.co.kr:${DEV_PORT_WR}/api/v1`; diff --git a/apps/fo/app/components/api/config/index.ts b/apps/fo/app/components/api/config/index.ts new file mode 100644 index 000000000..b9f9f76d6 --- /dev/null +++ b/apps/fo/app/components/api/config/index.ts @@ -0,0 +1 @@ +export * from './env'; \ No newline at end of file diff --git a/apps/fo/app/components/api/index.ts b/apps/fo/app/components/api/index.ts new file mode 100644 index 000000000..fe8e54bb6 --- /dev/null +++ b/apps/fo/app/components/api/index.ts @@ -0,0 +1,79 @@ +import { DEV_URL_COMMON, DEV_URL_FO, DEV_URL_WR } from "./config/env"; + +export const getFetch = async (part : string, url: string) => { + let reqUrl = ""; + reqUrl = part === "fo" ? DEV_URL_FO+url : part === "wr" ? DEV_URL_WR+url : DEV_URL_COMMON+url; + const response = await fetch(reqUrl , { + method: "GET", + headers: { + accept: "application/json", + } + }); + if(!response.ok) { + throw new Error(`오류 발생: ${response.status}`); + } + const res = await response.json() + return res; +} + +export const getFetchAreaList = async (url: string) => { + const response = await fetch(url , { + method: "GET", + headers: { + accept: "application/json", + } + }); + if(!response.ok) { + throw new Error(`오류 발생: ${response.status}`); + } + const res = await response.json() + return res; +} + +export const postFetch = async (part : string, url: string, params: unknown) => { + let reqUrl = ""; + reqUrl = part === "fo" ? DEV_URL_FO+url : DEV_URL_COMMON+url; + const response = await fetch(reqUrl, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(params), + }); + if(!response.ok) { + throw new Error(`오류 발생: ${response.status}`); + } + return await response.json(); +} + +export const putFetch = async (part : string, url: string, params: unknown) => { + let reqUrl = ""; + reqUrl = part === "fo" ? DEV_URL_FO+url : DEV_URL_COMMON+url; + const response = await fetch(reqUrl, { + method: "PUT", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(params), + }); + if(!response.ok) { + throw new Error(`오류 발생: ${response.status}`); + } + return response; +} + +export const deleteFetch = async (part : string, url: string, params: unknown) => { + let reqUrl = ""; + reqUrl = part === "fo" ? DEV_URL_FO+url : DEV_URL_COMMON+url; + const response = await fetch(reqUrl, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(params), + }); + if(!response.ok) { + throw new Error(`오류 발생: ${response.status}`); + } + return response; +} \ No newline at end of file diff --git a/apps/fo/app/components/common/DataForm.tsx b/apps/fo/app/components/common/DataForm.tsx new file mode 100644 index 000000000..66530aed9 --- /dev/null +++ b/apps/fo/app/components/common/DataForm.tsx @@ -0,0 +1,46 @@ +type DataFormProps = { + type: string; + column: string; + item: Record; +} + +export default function DataForm({ type, column, item }: DataFormProps) { + if(item) { + const value = item[column]; + switch(type){ + case 'date': + if(value && typeof value === 'string' && value.length >= 8) + item[column] = value.substring(0, 4) + "-" + value.substring(4, 6) + "-" + value.substring(6, 8); + break; + case 'number': + if(value && value != '') { + item[column] = value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); + } + break; + case 'float1': + if(value) { + item[column] = String(value).includes('.')?String(Math.round(parseFloat(value.toString().replace(/,/g, '')) * 10) / 10).split('.').map((part, index) => + index === 0 ? part.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : part + ).join('.') + : String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ","); + } + break; + case 'float2': + if(value) { + item[column] = String(value).includes('.')?String(Math.round(parseFloat(value.toString().replace(/,/g, '')) * 100) / 100).split('.').map((part, index) => + index === 0 ? part.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : part + ).join('.') + : String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ","); + } + break; + case 'float3': + if(value) { + item[column] = String(value).includes('.')?String(Math.round(parseFloat(value.toString().replace(/,/g, '')) * 1000) / 1000).split('.').map((part, index) => + index === 0 ? part.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : part + ).join('.') + : String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ","); + } + break; + } + } +} diff --git a/apps/fo/app/components/common/FacilityTermModalHeader.tsx b/apps/fo/app/components/common/FacilityTermModalHeader.tsx new file mode 100644 index 000000000..b360f496c --- /dev/null +++ b/apps/fo/app/components/common/FacilityTermModalHeader.tsx @@ -0,0 +1,279 @@ +import { useFoStore } from '@/app/store'; +import { DatePickerRange, SelectBox } from '@common/business_components/ui'; +import ListDiv from '@common/business_components/ui/list_div'; +import { Table, TableCell, TableHead, TableRow } from '@common/components/ui'; +import { useCallback, useEffect, useRef, useState } from 'react'; + +type FacilityTermModalHeaderProps = { + fcltyCd : string; + fcltyName: string; + tabName: string; + searchYear: string; + searchList: T[]; + ref: React.RefObject>; + queryClick:(returnType:ReturnType) => void; +} + +export type ReturnType = { + startDate: Date; + endDate: Date; + tabName: string; + filteredList: T[]; +} + +export default function FacilityTermModalHeader({ + searchList, + fcltyName, + tabName, + searchYear, + queryClick, + ref +}: FacilityTermModalHeaderProps) { + const {Common} = useFoStore((state) => state); + const { selectFlowPanel } = Common; + const [startDate, setStartDate] = useState(new Date(Number(searchYear), 0, 1)); + const [endDate, setEndDate] = useState(new Date(Number(searchYear), 11, 31)); + const startPickerRef = useRef(null); + const endPickerRef = useRef(null); + const [flowPanel, setFlowPanel] = useState(selectFlowPanel[0]?.val ?? '00'); + const [copySearchList, setCopySearchList] = useState(searchList); + const [standSearchList, setStandSearchList] = useState(searchList); + + const isDateInRanges = (date: Date) => { + const standYear = parseInt(searchYear); + const dateRanges = []; + + if (tabName.includes("_summer")) { + dateRanges.push({ + start: new Date(standYear, 5, 1), + end: new Date(standYear, 7, 31) + }); + } else if (tabName.includes("_winter")) { + dateRanges.push({ + start: new Date(standYear, 0, 1), + end: new Date(standYear, 1, 28) + }); + } else { + dateRanges.push({ + start: new Date(standYear, 0, 1), + end: new Date(standYear, 11, 31) + }); + } + + return dateRanges.some(range => { + const start = new Date(range.start); + const end = new Date(range.end); + return date >= start && date <= end; + }); + }; + + useEffect(() => { + let startDate = new Date(Number(searchYear), 0, 1); + let endDate = new Date(Number(searchYear), 11, 31); + + if(tabName.includes("_summer")) { + startDate = new Date(Number(searchYear), 5, 1); + endDate = new Date(Number(searchYear), 7, 31); + setStartDate(startDate); + setEndDate(endDate); + } else if (tabName.includes("_winter")) { + startDate = new Date(Number(searchYear), 0, 1); + endDate = new Date(Number(searchYear), 1, 28); + setStartDate(startDate); + setEndDate(endDate); + } else { + startDate = new Date(Number(searchYear), 0, 1); + endDate = new Date(Number(searchYear), 11, 31); + setStartDate(startDate); + setEndDate(endDate); + } + + let filteredData: T[] = []; + + if(tabName.includes("_rain")) { + filteredData = searchList.filter((item) => { + const itemDate = new Date((item as T & { msrDt: string }).msrDt); + const itemDateOnly = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate()); + const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate()); + const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate()); + const rainEffectDay = (item as T & { rainEffectDay: number }).rainEffectDay; + if(flowPanel === '1') { + const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay>0 && infoRnDay < 3; + } else if(flowPanel === '2'){ + const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 3 && infoRnDay < 10; + } else if(flowPanel === '3'){ + const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 10 && infoRnDay < 20; + } else if(flowPanel === '4'){ + const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 20 && infoRnDay < 30; + } else if(flowPanel === '5'){ + const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 30 && infoRnDay < 40; + } else if(flowPanel === '6'){ + const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 40 && infoRnDay < 50; + } else if(flowPanel === '7'){ + const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 50 && infoRnDay < 60; + } else if(flowPanel === '8'){ + const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 60; + } else { + const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && (infoRnDay>0 || rainEffectDay ===1); + } + }); + } else if(tabName.includes("_chuncheon")) { + filteredData = searchList.filter((item) => { + const itemDate = new Date((item as T & { msrDt: string }).msrDt); + const itemDateOnly = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate()); + const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate()); + const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate()); + const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay==0; + }); + } else { + filteredData = searchList.filter((item) => { + const itemDate = new Date((item as T & { msrDt: string }).msrDt); + const itemDateOnly = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate()); + const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate()); + const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate()); + return itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly; + }); + } + + setCopySearchList(filteredData); + setStandSearchList(filteredData); + }, [searchList, searchYear, tabName, flowPanel]); + + const handleStartDateSelect = (day: Date | undefined) => { + if(day && day > endDate) { + alert('종료일은 시작일 이전일 수 없습니다.'); + return; + } + + const selectedDate = day ?? startDate; + setStartDate(selectedDate); + const button = startPickerRef.current?.querySelector('button'); + if (button) { + setTimeout(() => button.click(), 0); + } + + const filteredData = standSearchList.filter((item) => { + const itemDate = new Date((item as T & { msrDt: string }).msrDt); + const itemDateOnly = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate()); + const startDateOnly = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate()); + const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate()); + return itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly; + }); + setCopySearchList(filteredData); + }; + + const handleEndDateSelect = (day: Date | undefined) => { + if(day && day < startDate) { + alert('종료일은 시작일 이후일 수 없습니다.'); + return; + } + + const selectedDate = day ?? endDate; + setEndDate(selectedDate); + const button = endPickerRef.current?.querySelector('button'); + if (button) { + setTimeout(() => button.click(), 0); + } + + const filteredData = standSearchList.filter((item) => { + const itemDate = new Date((item as T & { msrDt: string }).msrDt); + const itemDateOnly = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate()); + const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate()); + const endDateOnly = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate()); + return itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly; + }); + setCopySearchList(filteredData); + }; + + const fncSetFilteredList = useCallback(() => { + queryClick({ + startDate: startDate, + endDate: endDate, + tabName: tabName, + filteredList: copySearchList + }); + }, [queryClick, startDate, endDate, tabName, copySearchList]); + + useEffect(() => { + fncSetFilteredList(); + }, [fncSetFilteredList]); + + useEffect(() => { + if(ref && ref.current) { + const customRef = ref.current; + customRef.startDate = startDate; + customRef.endDate = endDate; + customRef.tabName = tabName; + customRef.filteredList = copySearchList; + } + }, [startDate, endDate, tabName, copySearchList, ref]); + + return ( + +
+ + + + {'시설명'} + {tabName === "tab_term_rain" ? {fcltyName} : + {fcltyName}} + {tabName === "tab_term_rain" && ( + <> + {'강수구분'} + +
+ setFlowPanel(val.toString())} + className="mx-3 w-[150px]" + label="" + selectClass="w-full p-1 border rounded bg-white" + /> +
+
+ + )} + {'년/월'} + +
+
+ handleStartDateSelect(date as Date)} + className="w-full p-1 border rounded bg-white" + disabled={(date) => !isDateInRanges(date)} + defaultMonth={startDate} + /> +
+

~

+
+ handleEndDateSelect(date as Date)} + className="w-full p-1 border rounded bg-white" + disabled={(date) => !isDateInRanges(date)} + defaultMonth={endDate} + /> +
+
+
+
+ +
+
+
+ ); +} \ No newline at end of file diff --git a/apps/fo/app/components/common/FacilityTermModalHeaderMonth.tsx b/apps/fo/app/components/common/FacilityTermModalHeaderMonth.tsx new file mode 100644 index 000000000..a284d04cf --- /dev/null +++ b/apps/fo/app/components/common/FacilityTermModalHeaderMonth.tsx @@ -0,0 +1,276 @@ +import { useFoStore } from '@/app/store'; +import { SelectBox } from '@common/business_components/ui'; +import ListDiv from '@common/business_components/ui/list_div'; +import { DatePicker, Table, TableCell, TableHead, TableRow } from '@common/components/ui'; +import { useCallback, useEffect, useRef, useState } from 'react'; + +type FacilityTermModalHeaderProps = { + fcltyCd : string; + fcltyName: string; + tabName: string; + searchYear: string; + searchList: T[]; + ref: React.RefObject>; + queryClick:(returnType:ReturnType) => void; +} + +export type ReturnType = { + startDate: Date; + endDate: Date; + tabName: string; + filteredList: T[]; +} + +export default function FacilityTermModalHeaderMonth({ + searchList, + fcltyName, + tabName, + searchYear, + queryClick, + ref +}: FacilityTermModalHeaderProps) { + const {Common} = useFoStore((state) => state); + const { selectFlowPanel } = Common; + const [startDate, setStartDate] = useState(new Date(Number(searchYear), 0, 1)); + const [endDate, setEndDate] = useState(new Date(Number(searchYear), 11, 31)); + const startPickerRef = useRef(null); + const endPickerRef = useRef(null); + const [flowPanel, setFlowPanel] = useState(selectFlowPanel[0]?.val ?? '00'); + const [copySearchList, setCopySearchList] = useState(searchList); + + /* const isDateInRanges = (date: Date) => { + const standYear = parseInt(searchYear); + const dateRanges = []; + + if (tabName.includes("_summer")) { + dateRanges.push({ + start: new Date(standYear, 5, 1), + end: new Date(standYear, 7, 31) + }); + } else if (tabName.includes("_winter")) { + dateRanges.push({ + start: new Date(standYear, 0, 1), + end: new Date(standYear, 1, 28) + }); + } else { + dateRanges.push({ + start: new Date(standYear, 0, 1), + end: new Date(standYear, 11, 31) + }); + } + + return dateRanges.some(range => { + const start = new Date(range.start); + const end = new Date(range.end); + return date >= start && date <= end; + }); + }; */ + + useEffect(() => { + let startDate = new Date(Number(searchYear), 0, 1); + let endDate = new Date(Number(searchYear), 11, 31); + + if(tabName.includes("_summer")) { + startDate = new Date(Number(searchYear), 5, 1); + endDate = new Date(Number(searchYear), 7, 31); + setStartDate(startDate); + setEndDate(endDate); + } else if (tabName.includes("_winter")) { + startDate = new Date(Number(searchYear), 0, 1); + endDate = new Date(Number(searchYear), 1, 28); + setStartDate(startDate); + setEndDate(endDate); + } else { + startDate = new Date(Number(searchYear), 0, 1); + endDate = new Date(Number(searchYear), 11, 31); + setStartDate(startDate); + setEndDate(endDate); + } + + let filteredData: T[] = []; + + if(tabName.includes("_rain")) { + filteredData = searchList.filter((item) => { + const itemDate = new Date((item as T & { msrDt: string }).msrDt); + const itemDateOnly = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate()); + const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate()); + const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate()); + const rainEffectDay = (item as T & { rainEffectDay: number }).rainEffectDay; + + if(flowPanel === '1') { + const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay>0 && infoRnDay < 3; + } else if(flowPanel === '2'){ + const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 3 && infoRnDay < 10; + } else if(flowPanel === '3'){ + const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 10 && infoRnDay < 20; + } else if(flowPanel === '4'){ + const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 20 && infoRnDay < 30; + } else if(flowPanel === '5'){ + const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 30 && infoRnDay < 40; + } else if(flowPanel === '6'){ + const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 40 && infoRnDay < 50; + } else if(flowPanel === '7'){ + const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 50 && infoRnDay < 60; + } else if(flowPanel === '8'){ + const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 60; + } else { + const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && (infoRnDay>0 || rainEffectDay ===1); + } + }); + } else if(tabName.includes("_chuncheon")) { + filteredData = searchList.filter((item) => { + const itemDate = new Date((item as T & { msrDt: string }).msrDt); + const itemDateOnly = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate()); + const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate()); + const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate()); + const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay==0; + }); + } else { + filteredData = searchList.filter((item) => { + const itemDate = new Date((item as T & { msrDt: string }).msrDt); + const itemDateOnly = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate()); + const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate()); + const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate()); + return itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly; + }); + } + + setCopySearchList(filteredData); + }, [searchList, searchYear, tabName, flowPanel]); + + const handleStartDateSelect = (day: Date | undefined) => { + if(day && day > endDate) { + alert('종료일은 시작일 이전일 수 없습니다.'); + return; + } + + const selectedDate = day ?? startDate; + setStartDate(selectedDate); + const button = startPickerRef.current?.querySelector('button'); + if (button) { + setTimeout(() => button.click(), 0); + } + + const filteredData = searchList.filter((item) => { + const itemDate = new Date((item as T & { msrDt: string }).msrDt); + const itemDateOnly = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate()); + const startDateOnly = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate()); + const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate()); + return itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly; + }); + setCopySearchList(filteredData); + }; + + const handleEndDateSelect = (day: Date | undefined) => { + if(day && day < startDate) { + alert('종료일은 시작일 이후일 수 없습니다.'); + return; + } + + const selectedDate = day ?? endDate; + setEndDate(selectedDate); + const button = endPickerRef.current?.querySelector('button'); + if (button) { + setTimeout(() => button.click(), 0); + } + + const filteredData = searchList.filter((item) => { + const itemDate = new Date((item as T & { msrDt: string }).msrDt); + const itemDateOnly = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate()); + const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate()); + const endDateOnly = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate()); + return itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly; + }); + setCopySearchList(filteredData); + }; + + const fncSetFilteredList = useCallback(() => { + queryClick({ + startDate: startDate, + endDate: endDate, + tabName: tabName, + filteredList: copySearchList + }); + }, [queryClick, startDate, endDate, tabName, copySearchList]); + + useEffect(() => { + fncSetFilteredList(); + }, [fncSetFilteredList]); + + useEffect(() => { + if(ref && ref.current) { + const customRef = ref.current; + customRef.startDate = startDate; + customRef.endDate = endDate; + customRef.tabName = tabName; + customRef.filteredList = copySearchList; + } + }, [startDate, endDate, tabName, copySearchList, ref]); + + return ( + +
+ + + + {'시설명'} + {tabName === "tab_term_rain" ? {fcltyName} : + {fcltyName}} + {tabName === "tab_term_rain" && ( + <> + {'강수구분'} + +
+ setFlowPanel(val.toString())} + className="mx-3 w-[150px]" + label="" + selectClass="w-full p-1 border rounded bg-white" + /> +
+
+ + )} + {'년/월'} + +
+
+ handleStartDateSelect(date as Date)} + className="w-full p-1 border rounded bg-white" + defaultMonth={startDate} + /> +
+

~

+
+ handleEndDateSelect(date as Date)} + className="w-full p-1 border rounded bg-white" + defaultMonth={endDate} + /> +
+
+
+
+ +
+
+
+ ); +} \ No newline at end of file diff --git a/apps/fo/app/components/common/HeadMakeColSpan.tsx b/apps/fo/app/components/common/HeadMakeColSpan.tsx new file mode 100644 index 000000000..06617839a --- /dev/null +++ b/apps/fo/app/components/common/HeadMakeColSpan.tsx @@ -0,0 +1,65 @@ +import { TableHead, TableRow } from "@common/components/ui"; +import type { TableUpperProps } from "../../store/dashboard"; + +const HeadMakeColSpan = ({ upHeadList, layoutNum }: { upHeadList: TableUpperProps[], layoutNum: string }) => { + return ( + layoutNum === 'A' ? ( + <> + {upHeadList.map((head: TableUpperProps) => + (head.id === 'trtFrfNm' ? {head.title} : + head.id === 'laeNm' ? {head.title} : + head.id == 'fctCpc' || head.id == 'planInputWaterQlty' || head.id == 'designInputWaterQlty' ? {head.title} : + head.id === 'trstOprEtpNm' ? {head.title} : + head.upName === 'upChangeRe' && head.upSequnce === 1 ? {'행정구역'} : + !head.upName ? {head.title} : null))} + + + {upHeadList.map((head: TableUpperProps) => { + if (head.upName === 'upChangeRe') { + return {head.title}; + } + })} + + + ) : layoutNum === 'R' ? ( + <> + {upHeadList.map((head: TableUpperProps) => + (head.id === 'trtFrfNm' ? {head.title} : + head.id === 'laeNm' ? {head.title} : + head.id == 'fctCpc' || head.id == 'planInputWaterQlty' || head.id == 'designInputWaterQlty' ? {head.title} : + head.id === 'trstOprEtpNm' ? {head.title} : + head.upName === 'upChangeRe' && head.upSequnce === 1 ? {'유역'} : + !head.upName ? {head.title} : null))} + + + {upHeadList.map((head: TableUpperProps) => { + if (head.upName === 'upChangeRe') { + return {head.title}; + } + })} + + + ) : ( + <> + {upHeadList.map((head: TableUpperProps) => + (head.id === 'trtFrfNm' ? {head.title} : + head.id === 'laeNm' ? {head.title} : + head.id == 'fctCpc' || head.id == 'planInputWaterQlty' || head.id == 'designInputWaterQlty' ? {head.title} : + head.id === 'trstOprEtpNm' ? {head.title} : + head.upName === 'upChangeRe1' && head.upSequnce === 1 ? {'권역'} : + head.upName === 'upChangeRe2' && head.upSequnce === 1 ? {'행정구역'} : + !head.upName ? {head.title} : null))} + + + {upHeadList.map((head: TableUpperProps) => { + if (head.upName === 'upChangeRe1' || head.upName === 'upChangeRe2') { + return {head.title}; + } + })} + + + ) + ); +} + +export { HeadMakeColSpan }; diff --git a/apps/fo/app/components/common/SearchInput.tsx b/apps/fo/app/components/common/SearchInput.tsx new file mode 100644 index 000000000..11bdd3676 --- /dev/null +++ b/apps/fo/app/components/common/SearchInput.tsx @@ -0,0 +1,108 @@ +import { useFoStore } from '@/app/store'; +import type { facilityListProps } from '@/app/store/processFacility'; +import { Label } from '@common/components/ui'; +import React, { useEffect, useState, useRef, useCallback } from 'react' + +type thisProps = { + label: string | undefined; + setValue : (fcltyCd?: string, fcltyNm?: string, fcltyCpc?: number | '', trtFrfNm?: string | '', efflWqltStndrdNm?: string | '') => void; + sidoSigun? : string | undefined; + fcltyName? : string | undefined; +} + +export default function SearchInputText({label=undefined, setValue=()=>{}, sidoSigun=undefined, fcltyName=undefined} :thisProps) { + + const { ProcessFacilityList, searchProcessFacilitySearching } = useFoStore((state) => state); + const [isOpen, setIsOpen] = useState(false); + const [textValue, setTextValue] = useState(fcltyName || ''); + const wrapperRef = useRef(null); + const processFacilityList = ProcessFacilityList?.processFacilityList || []; + + const handleInputChange = useCallback((e: React.ChangeEvent) => { + const value = e.target.value; + setTextValue(value); + if (value) { + setIsOpen(true); + if(sidoSigun) { + searchProcessFacilitySearching(1, 4999, 'A', sidoSigun, '0', '0', '0', value); + } else { + searchProcessFacilitySearching(1, 4999, '0', '0', '0', '0', '0', value); + } + } else { + setIsOpen(false); + } + }, [searchProcessFacilitySearching, sidoSigun]); + + const onInputFocus = useCallback(() => { + setIsOpen(true); + if(sidoSigun) { + searchProcessFacilitySearching(1, 4999, 'A', sidoSigun, '0', '0', '0'); + } else { + searchProcessFacilitySearching(1, 4999, '0', '0', '0', '0', '0'); + } + }, [searchProcessFacilitySearching, sidoSigun]); + + useEffect(() => { + setTextValue(fcltyName || ''); + }, [fcltyName]); + + const handleSuggestionClick = useCallback((bscFctCd: string, bscFctNm: string, fctCpc: number | '', trtFrfNm: string | '', efflWqltStndrdNm: string | '') => { + console.log('bscFctNm : ', bscFctNm); + console.log('bscFctCd : ', bscFctCd); + console.log('fctCpc : ', fctCpc); + console.log('trtFrfNm : ', trtFrfNm); + console.log('efflWqltStndrdNm : ', efflWqltStndrdNm); + setTextValue(bscFctNm); + setValue(bscFctCd, bscFctNm, fctCpc, trtFrfNm, efflWqltStndrdNm); + setIsOpen(false); + }, [setValue]); + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (wrapperRef.current && !wrapperRef.current.contains(event.target as Node)) { + setIsOpen(false); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, []); + + return ( +
+ {label && } + + {isOpen && processFacilityList.length > 0 && ( +
+
+ {processFacilityList.map((item : facilityListProps, index : number) => ( +
handleSuggestionClick(item.bscFctCd, item.bscFctNm, Number(item.fctCpc), item.trtFrfNm, item.efflWqltStndrdNm)} + role="button" + tabIndex={0} + onKeyDown={(e) => { + if (e.key === 'Enter' || e.key === ' ') { + handleSuggestionClick(item.bscFctCd, item.bscFctNm, Number(item.fctCpc), item.trtFrfNm, item.efflWqltStndrdNm); + } + }} + > + {item.sido} {item.gugun} {item.bscFctNm} +
+ ))} +
+
+ )} +
+ ) +} \ No newline at end of file diff --git a/apps/fo/app/favicon.ico b/apps/fo/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c GIT binary patch literal 25931 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 LrJugUA?W`A8`#=m literal 0 HcmV?d00001 diff --git a/apps/fo/app/globals.css b/apps/fo/app/globals.css new file mode 100644 index 000000000..4ff2b8802 --- /dev/null +++ b/apps/fo/app/globals.css @@ -0,0 +1,7 @@ +@import "../../../packages/common/components/src/base.css"; + +html, +body { + font-family: "Noto Sans KR", sans-serif; + font-size: 10px; +} \ No newline at end of file diff --git a/apps/fo/app/layout.tsx b/apps/fo/app/layout.tsx new file mode 100644 index 000000000..548ef77a9 --- /dev/null +++ b/apps/fo/app/layout.tsx @@ -0,0 +1,24 @@ +"use client" +import { BaseLayout } from "@common/components/ui"; +import "./globals.css"; +import { StoreProvider } from "./store"; + + + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + + + {children} + + + + + ); +} diff --git a/apps/fo/app/page.tsx b/apps/fo/app/page.tsx new file mode 100644 index 000000000..823e5a408 --- /dev/null +++ b/apps/fo/app/page.tsx @@ -0,0 +1,44 @@ +"use client" + +import Link from "next/link"; +import { Button } from "@common/components/ui"; + +export default function Home() { + return ( +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ ); +} diff --git a/apps/fo/app/pages/dashboard/drainageEquipment/page.tsx b/apps/fo/app/pages/dashboard/drainageEquipment/page.tsx new file mode 100644 index 000000000..f6f1188de --- /dev/null +++ b/apps/fo/app/pages/dashboard/drainageEquipment/page.tsx @@ -0,0 +1,98 @@ +"use client" + +import { useFoStore } from '@/app/store'; +import type { DrainageEquipmentListProps, TableUpperProps } from '@/app/store/dashboard'; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@common/components'; +import { useEffect, useState } from 'react'; + +export type DrainageEquipmentProps = { + searchYear?: string; + fcltyList?: { bscFctCd: string, bscFctNm: string, fcltyCpc: number | '', trtFrfNm: string, efflWqltStndrdNm: string }[]; +}; + +export default function DrainageEquipment({searchYear = '', fcltyList = []}: DrainageEquipmentProps) { + + const { + Common, + DrainageEquipment, + searchDrainageEquipment, + } = useFoStore((state) => state); + + const { + isInit, + } = Common; + + const { + upHeadListDrainageEquipment, + drainageEquipmentList, + } = DrainageEquipment; + + const [hasSearched, setHasSearched] = useState(false); + // 이전 시설코드 저장 + const [prevFacilityCode, setPrevFacilityCode] = useState(''); + + const tableData = fcltyList; + + useEffect(() => { + if (!isInit && tableData[0]?.bscFctCd && (tableData[0].bscFctCd !== prevFacilityCode || !hasSearched)) { + searchDrainageEquipment(searchYear, tableData[0].bscFctCd, false); + setHasSearched(true); + setPrevFacilityCode(tableData[0].bscFctCd); + } + }, [fcltyList, isInit, searchDrainageEquipment, searchYear, tableData, hasSearched, prevFacilityCode]); + + // 연도가 바뀌면 hasSearched를 false로 리셋 + useEffect(() => { + setHasSearched(false); + }, [searchYear]); + + // 시설계획 table header 변경 + const HeadMakeColSpan = ({ upHeadList }: { upHeadList: TableUpperProps[] }) => { + return ( + <> + {upHeadList.map((head: TableUpperProps) => + (head.id === 'part1' ? 구분 : + head.id === 'part2' ? 구분 : + head.id == 'nowSum' ? {'현재\n(기준년도)'} : + head.id == 'stepOneSum' ? {'변경(금회계획)'} : + head.id == 'etc' ? 비고 : null))} + + {upHeadList.map((head: TableUpperProps) => + (head.id === 'stepOneSum' ? 1단계 : + head.id === 'stepTwoSum' ? 2단계 : + head.id === 'stepThreeSum' ? 3단계 : + head.id === 'stepFourSum' ? 4단계 : null))} + + + {upHeadList.map((head: TableUpperProps) => { + if (head.upName === 'upChangeRe2' || head.upName === 'upChangeRe3' || head.upName === 'upChangeRe4' || head.upName === 'upChangeRe5' || head.upName === 'upChangeRe6') { + return {head.title}; + } + })} + + + ) + } + + const upHeadList = HeadMakeColSpan({upHeadList:upHeadListDrainageEquipment}); + return ( +
+ + + {upHeadList} + + + {drainageEquipmentList.map((el: DrainageEquipmentListProps, index) => ( + + {upHeadListDrainageEquipment.map((head) => ( + (head.id==='nowSum')? + {333} + :{el[head.id as keyof DrainageEquipmentListProps]} + ))} + + ))} + +
+
+ ) +} diff --git a/apps/fo/app/pages/dashboard/facilityInfo/modal/page.tsx b/apps/fo/app/pages/dashboard/facilityInfo/modal/page.tsx new file mode 100644 index 000000000..94bc28500 --- /dev/null +++ b/apps/fo/app/pages/dashboard/facilityInfo/modal/page.tsx @@ -0,0 +1,184 @@ +"use client" +import type { OperationalStatusListProps } from "@/app/store/dashboard"; +import { CHART_FORM, MainChart, type ChartConfig } from "@common/business_components"; +import { Button } from "@common/business_components/ui/table/lib/button"; +import html2canvas from "html2canvas"; +import { useEffect, useState, useRef } from "react"; + +type yearProps = { + label: string; + 평균 : number | string | ''; + 최대 : number | string | ''; + 최소 : number | string | ''; +} + +type summerProps = { + 전기간 : number | string | ''; + 강우일3mm이상 : number | string | ''; + 비강우시 : number | string | ''; +} + +type winterProps = { + 전기간 : number | string | ''; + 청천시최대 : number | string | ''; + 청천시평균 : number | string | ''; + 청천시최소 : number | string | ''; +} + +type dashBoardChartModalProps = { + title : string; + item : string; + period : string; + modalData : OperationalStatusListProps[]; + waterQlty : string; +} + +export default function DashBoardChartModal({item='', period='', title='',modalData=[], waterQlty=''} : dashBoardChartModalProps) { + + const [chartData, setChartData] = useState([]); + const [chartConfig, setChartConfig] = useState({}); + const chartRef = useRef(null); + const chartOption = { + chartForm : CHART_FORM.BAR, + chartConfig : chartConfig, + chartData : chartData, + chartTitle : title, + chartClassName : "h-[calc(100%-15%)] w-[90%] mt-5", + graphSize : 40, + yFieldText : item === 'flowRate' ? '유량(㎥/일)' : item === 'waterQlty' ? '수질(mg/L)' : item === 'chongin' ? '수질(mg/L)' : '', + showLegend : true + } + + const handleDownload = () => { + if (!chartRef.current) { + return alert('결과 저장에 실패했습니다.'); + } + html2canvas(chartRef.current).then((canvas) => { + const link = document.createElement('a'); + document.body.appendChild(link); + link.href = canvas.toDataURL('image/png'); + link.download = 'result.png'; + link.click(); + document.body.removeChild(link); + }); + } + + /** + * useEffect + */ + useEffect(() => { + if(period === 'year'){ + const filteredData: yearProps[] = modalData.map((item) => { + if(waterQlty.trim().includes('T-N') || waterQlty.trim().includes('T-P')){ + return { + label: item.waterQlty, + 평균: typeof item.yearAvg === 'string' ? Number(item.yearAvg.replace(/,/g, '')).toFixed(3) : (item.yearAvg || 0), + 최대: typeof item.yearMax === 'string' ? Number(item.yearMax.replace(/,/g, '')).toFixed(3) : (item.yearMax || 0), + 최소: typeof item.yearMin === 'string' ? Number(item.yearMin.replace(/,/g, '')).toFixed(3) : (item.yearMin || 0), + } + } + else{ + return { + label: item.waterQlty, + 평균: typeof item.yearAvg === 'string' ? Number(item.yearAvg.replace(/,/g, '')).toFixed(1) : (item.yearAvg || 0), + 최대: typeof item.yearMax === 'string' ? Number(item.yearMax.replace(/,/g, '')).toFixed(1) : (item.yearMax || 0), + 최소: typeof item.yearMin === 'string' ? Number(item.yearMin.replace(/,/g, '')).toFixed(1) : (item.yearMin || 0), + } + } + }) + if (item === 'flowRate') { + setChartData(filteredData.slice(0,5)); + } else if (item === 'waterQlty') { + setChartData(filteredData.slice(5,11)); + } else { + setChartData(filteredData.slice(11,13)); + } + } + else if (period === 'summer') { + const filteredData: summerProps[] = modalData.map((item) => { + if(waterQlty.trim().includes('T-N') || waterQlty.trim().includes('T-P')){ + return { + label: item.waterQlty, + 전기간: typeof item.summerAll === 'string' ? Number(item.summerAll.replace(/,/g, '')).toFixed(3) : (item.summerAll || 0), + 강우일3mm이상: typeof item.summerThree === 'string' ? Number(item.summerThree.replace(/,/g, '')).toFixed(3) : (item.summerThree || 0), + 비강우시: typeof item.summerRain === 'string' ? Number(item.summerRain.replace(/,/g, '')).toFixed(3) : (item.summerRain || 0), + } + }else{ + return { + label: item.waterQlty, + 전기간: typeof item.summerAll === 'string' ? Number(item.summerAll.replace(/,/g, '')).toFixed(1) : (item.summerAll || 0), + 강우일3mm이상: typeof item.summerThree === 'string' ? Number(item.summerThree.replace(/,/g, '')).toFixed(1) : (item.summerThree || 0), + 비강우시: typeof item.summerRain === 'string' ? Number(item.summerRain.replace(/,/g, '')).toFixed(1) : (item.summerRain || 0), + } + } + }) + if (item === 'flowRate') { + setChartData(filteredData.slice(0,5)); + } else if (item === 'waterQlty') { + setChartData(filteredData.slice(5,11)); + } else { + setChartData(filteredData.slice(11,13)); + } + } + else if (period === 'winter') { + const filteredData: winterProps[] = modalData.map((item) => { + return { + label: item.waterQlty, + 전기간: typeof item.winterAll === 'string' ? Number(item.winterAll.replace(/,/g, '')).toFixed(3) : (item.winterAll || 0), + 청천시최대: typeof item.winterSunnyMax === 'string' ? Number(item.winterSunnyMax.replace(/,/g, '')).toFixed(3) : (item.winterSunnyMax || 0), + 청천시평균: typeof item.winterSunnyAvg === 'string' ? Number(item.winterSunnyAvg.replace(/,/g, '')).toFixed(3) : (item.winterSunnyAvg || 0), + 청천시최소: typeof item.winterSunnyMin === 'string' ? Number(item.winterSunnyMin.replace(/,/g, '')).toFixed(3) : (item.winterSunnyMin || 0), + } + }) + setChartData(filteredData); + + if (item === 'flowRate') { + setChartData(filteredData.slice(0,5)); + } else if (item === 'waterQlty') { + setChartData(filteredData.slice(5,11)); + } else { + setChartData(filteredData.slice(11,13)); + } + } else { + setChartData([]); + } + }, [item, modalData, period, waterQlty]); + + useEffect(() => { + const newChartConfig = chartData.reduce((config, element) => { + const label = 'label' in element ? element.label : ''; + if (label) { + config[label] = { + label: label, + color : "hsl(var(--chart-1))" + }; + } + return config; + }, {} as Record) satisfies ChartConfig; + setChartConfig(newChartConfig); + }, [chartData]); + + return ( + <> +
+ + (하절기 : 6/1~8/31 동절기 : 1/1~2/28) + + +
+
+ +
+ + ); +} + diff --git a/apps/fo/app/pages/dashboard/facilityInfo/page.tsx b/apps/fo/app/pages/dashboard/facilityInfo/page.tsx new file mode 100644 index 000000000..7a88755ce --- /dev/null +++ b/apps/fo/app/pages/dashboard/facilityInfo/page.tsx @@ -0,0 +1,277 @@ +"use client" +import { useFoStore } from "@/app/store"; +import type { TableUpperProps } from "@/app/store/processFacility"; +import { ContentsDiv, UiModal, UiTable } from "@common/business_components"; +import { cn, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@common/components"; +import { useEffect, useState } from "react"; +import DashBoardChartModal from "./modal/page"; + +export type facilityInfoProps = { + searchYear?: string; + fcltyList?: { bscFctCd: string, bscFctNm: string, fcltyCpc: number | '', trtFrfNm: string, efflWqltStndrdNm: string }[]; +}; + +// 시설계획 table header 변경 +const headMakeColSpanPlanFclty = (upHeadList: TableUpperProps[], planYearList: string[]) => { + return ( <> + { + upHeadList.map((head: TableUpperProps) => + (!head.upSequnce?{head.title}: + head.upName === 'upChangeRe'&& head.upSequnce=== 1?{'시설계획\n(금회)'}:null))} + + + {upHeadList.map((head: TableUpperProps, index: number) => + (head.upName === 'upChangeRe'?{index===0?head.title:head.title+'\n('+planYearList[index-1]+')'}:null))} + + ) +} + +// 시설계획 table header 변경 +const headMakeColSpanOperationStatus = (upHeadList: TableUpperProps[], searchYear: string) => { + return ( <> + + {searchYear+'년도 운영실태'} + + { + upHeadList.map((head: TableUpperProps) => + (head.upName === 'upChangeRe1'&&head.upSequnce===1?{head.title}: + !head.upSequnce?{head.title}: + head.upName === 'upChangeRe2'&&head.upSequnce===1?{'연간 운영실태'}: + head.upName === 'upChangeRe3'&&head.upSequnce===1?{'하절기 운영실태\n(6~8월)'}: + head.upName === 'upChangeRe4'&&head.upSequnce===1?{'동절기 운영실태\n(1~2월)'}: + head.upName === 'upChangeRe5'&&head.upSequnce===1?{'지하수유입량'}:null))} + + + {upHeadList.map((head: TableUpperProps) => + (head.upName === 'upChangeRe2'||head.upName === 'upChangeRe3'||head.upName === 'upChangeRe4'||head.upName === 'upChangeRe5' ?{head.title}:null))} + + ) +} + +export default function ProcessFacilitySearch({searchYear = '', fcltyList = []}: facilityInfoProps & { onFacilityChange: (facility: { bscFctCd: string, bscFctNm: string, fcltyCpc: number | '', trtFrfNm: string, efflWqltStndrdNm: string }) => void }) { + // 입력값 상태 관리 + const { + Common, + FcltyMain, + PlanFclty, + OperationStatus, + searchOperationStatus, + searchPlanInfo + } = useFoStore((state) => state); + + const [modalItem, setModalItem] = useState<{item: string, period: string, title: string, waterQlty: string} | null>(null); + const [hasSearched, setHasSearched] = useState(false); + const [prevFacilityCode, setPrevFacilityCode] = useState(''); + + const { + isInit, + } = Common; + + // Tab1 + // fclty 관련 + const { + upHeadListFclty, + } = FcltyMain; + + // 시설계획 관련 + const { + upHeadListPlanFclty, + planFcltyList, + planYearList + } = PlanFclty; + + // 그리드 관련 + const { + upHeadListOperationStatus, + operationalStatusList + } = OperationStatus; + + const closeModal = () => { + setModalItem(null); + }; + + // const fcltyListArr = useMemo(() => [fcltyList], [fcltyList]); + + const tableData = fcltyList; + + // key 변환 + const mappedTableData = tableData.map(item => ({ + fcltyNm: item.bscFctNm, + facilityCapacity: item.fcltyCpc, + publicMethod: item.trtFrfNm, + location: item.efflWqltStndrdNm, + })); + + const fncLoadModal = (item: string, period: string, waterQlty: string) => { + // 유량 + if(item === 'flowRate'){ + if(period === 'year'){ + setModalItem({item: 'flowRate', period: 'year', title: '연간 유량', waterQlty: waterQlty}); + } + else if(period === 'summer'){ + setModalItem({item: 'flowRate', period: 'summer', title: '하절기 유량', waterQlty: waterQlty}); + } + else if(period === 'winter'){ + setModalItem({item: 'flowRate', period: 'winter', title: '동절기 유량', waterQlty: waterQlty}); + } + } + // 수질 + else if (item == 'waterQlty'){ + if(period === 'year'){ + setModalItem({item: 'waterQlty', period: 'year', title: '연간 수질', waterQlty: waterQlty}); + } + else if(period === 'summer'){ + setModalItem({item: 'waterQlty', period: 'summer', title: '하절기 수질', waterQlty: waterQlty}); + } + else if(period === 'winter'){ + setModalItem({item: 'waterQlty', period: 'winter', title: '동절기 수질', waterQlty: waterQlty}); + } + } + // 총인 + else { + if(period === 'year'){ + setModalItem({item: 'chongin', period: 'year', title: '총인설비 연간 수질', waterQlty: waterQlty}); + } + else if(period === 'summer'){ + setModalItem({item: 'chongin', period: 'summer', title: '총인설비 하절기 수질', waterQlty: waterQlty}); + } + else if(period === 'winter'){ + setModalItem({item: 'chongin', period: 'winter', title: '총인설비 동절기 수질', waterQlty: waterQlty}); + } + } + } + + useEffect(() => { + if (!isInit && fcltyList[0]?.bscFctCd && (fcltyList[0].bscFctCd !== prevFacilityCode || !hasSearched)) { + searchOperationStatus(false, searchYear, fcltyList[0].bscFctCd); + searchPlanInfo(searchYear, fcltyList[0].bscFctCd); + setHasSearched(true); + setPrevFacilityCode(fcltyList[0].bscFctCd); + planFcltyList.forEach((el: { [key: string]: string | number | boolean }, index) => { + if (index === 6) { + el['item'] = (Number(searchYear)-2).toString(); + el['provisionalApproval'] = Number(fcltyList[0]?.fcltyCpc)* 0.6; + } else if (index === 7) { + el['item'] = (Number(searchYear)-1).toString(); + el['provisionalApproval'] = Number(fcltyList[0]?.fcltyCpc)* 0.6; + } else if (index === 8) { + el['item'] = (Number(searchYear)-0).toString(); + el['provisionalApproval'] = Number(fcltyList[0]?.fcltyCpc)* 0.6; + } + }); + } + }, [isInit, searchOperationStatus, searchYear, fcltyList, hasSearched, prevFacilityCode, searchPlanInfo, planFcltyList]); + // 연도가 바뀌면 hasSearched를 false로 리셋 + useEffect(() => { + setHasSearched(false); + }, [searchYear]); + + useEffect(() => { + operationalStatusList.map((item: { [key: string]: string | number | boolean },index) => { + if(index===8 || index===9 || index===10 || index===11 || index===12 || index===13 || index===14 || index===15){ + item['yearAvg'] = Number(item['yearAvg']).toFixed(3); + item['yearMax'] = item['yearMax']+'%'; + item['yearMin'] = item['yearMin']+'%'; + item['summerAll'] = item['summerAll']+'%'; + item['summerThree'] = item['summerThree']+'%'; + item['summerRain'] = item['summerRain']+'%'; + item['winterAll'] = item['winterAll']+'%'; + item['winterSunnyAvg'] = item['winterSunnyAvg']+'%'; + item['winterSunnyMax'] = item['winterSunnyMax']+'%'; + item['winterSunnyMin'] = item['winterSunnyMin']+'%'; + } + + }); + }, [operationalStatusList]); + + const upChangeRePlanFclty = headMakeColSpanPlanFclty(upHeadListPlanFclty, planYearList); + const upChangeHeadListOperationStatus = headMakeColSpanOperationStatus(upHeadListOperationStatus, searchYear); + return ( + <> + { } } /> + +
+
+ + + {upChangeRePlanFclty} + + + {planFcltyList.map((el: { [key: string]: string | number | boolean },index) => ( + + {upHeadListPlanFclty.map((head) => ( + ((index === 6 || index === 7 || index === 8) && (head.id === 'provisionalApproval' || head.id === 'stepTwo'))? + {el[head.id]} + :((index === 6 || index === 7 || index === 8) && (head.id === 'now' || head.id === 'stepOne' || head.id === 'stepThree' || head.id === 'stepFour'))? + null + :((index === 5) && (head.id === 'provisionalApproval' || head.id === 'stepTwo'))? + {el[head.id]} + :((index === 5) && (head.id === 'now' || head.id === 'stepOne' || head.id === 'stepThree'|| head.id === 'stepFour'))? + null + :(index < 5 || index > 5)&& (index!= 4) && (head.id ==='provisionalApproval'||head.id ==='now'||head.id ==='stepOne'||head.id ==='stepTwo'||head.id ==='stepThree'||head.id ==='stepFour') + ?{el[head.id]} + :(head.id === "provisionalApproval" && index === 4) + ?{(Number(fcltyList[0]?.fcltyCpc)* 0.6).toLocaleString('en-US', { minimumFractionDigits: 1, maximumFractionDigits: 1 })} + :((head.id ==='now'||head.id ==='stepOne'||head.id ==='stepTwo'||head.id ==='stepThree'||head.id ==='stepFour') && index === 4) + ?null + :(head.id === 'item' && index != 5)? + {el[head.id]} + :{el[head.id]} + ))} + + ))} + +
+
+
+
+ + + {upChangeHeadListOperationStatus} + + + {operationalStatusList.map((el: { [key: string]: string | number | boolean },index) => ( + + {upHeadListOperationStatus.map((head) => ( + (head.id === 'flowRate' && index === 0)?{el[head.id]}: + (head.id === 'flowRate' && index === 5)?{el[head.id]}: + (head.id === 'flowRate' && index === 11)?{el[head.id]}: + (head.id === 'groundWaterAvg'||head.id === 'groundWaterSummer'||head.id === 'groundWaterWinter')&&(index === 0)?{el[head.id]}: + (head.id === 'groundWaterAvg'||head.id === 'groundWaterSummer'||head.id === 'groundWaterWinter')&&(index === 7)?{el[head.id]}: + (head.id === 'rdi'&&index === 0)?{el[head.id]}: + (head.id === 'rdi'&&index === 2)?{'RDII추정시\n일강수량(mm)'}: + (head.id === 'rdi'&&index === 5)?{el['rdiRain']}: + (head.id === 'rdi'&&index === 7)?: + (head.id === 'waterQlty')?{el[head.id]}: + ((head.id === 'yearAvg' || head.id === 'yearMax' || head.id === 'yearMin') && (index>=0 && index<=4))?{fncLoadModal('flowRate', 'year', el['waterQlty'] as string);}}>{el[head.id]}: + ((head.id === 'yearAvg' || head.id === 'yearMax' || head.id === 'yearMin') && (index>=5 && index<=10))?{fncLoadModal('waterQlty', 'year', el['waterQlty'] as string);}}>{el[head.id]}: + ((head.id === 'yearAvg' || head.id === 'yearMax' || head.id === 'yearMin') && (index>=11 && index<=12))?{fncLoadModal('chongin', 'year', el['waterQlty'] as string);}}>{el[head.id]}: + ((head.id === 'summerAll' || head.id === 'summerThree' || head.id === 'summerRain') && (index>=0 && index<=4))?{fncLoadModal('flowRate', 'summer', el['waterQlty'] as string);}}>{el[head.id]}: + ((head.id === 'summerAll' || head.id === 'summerThree' || head.id === 'summerRain') && (index>=5 && index<=10))?{fncLoadModal('waterQlty', 'summer', el['waterQlty'] as string);}}>{el[head.id]}: + ((head.id === 'summerAll' || head.id === 'summerThree' || head.id === 'summerRain') && (index>=11 && index<=12))?{fncLoadModal('chongin', 'summer', el['waterQlty'] as string);}}>{el[head.id]}: + ((head.id === 'winterAll' || head.id === 'winterSunnyAvg' || head.id === 'winterSunnyMax' || head.id === 'winterSunnyMin') && (index>=0 && index<=4))?{fncLoadModal('flowRate', 'winter', el['waterQlty'] as string);}}>{el[head.id]}: + ((head.id === 'winterAll' || head.id === 'winterSunnyAvg' || head.id === 'winterSunnyMax' || head.id === 'winterSunnyMin') && (index>=5 && index<=10))?{fncLoadModal('waterQlty', 'winter', el['waterQlty'] as string);}}>{el[head.id]}: + ((head.id === 'winterAll' || head.id === 'winterSunnyAvg' || head.id === 'winterSunnyMax' || head.id === 'winterSunnyMin') && (index>=11 && index<=12))?{fncLoadModal('chongin', 'winter', el['waterQlty'] as string);}}>{el[head.id]}: + null + ))} + + ))} + +
+
+
+
+
+ {modalItem && (modalItem.item === 'flowRate' || modalItem.item === 'waterQlty' || modalItem.item === 'chongin') && ( + } + bodyClass="sm:max-w-[80%] h-[88%]" + open={true} + onOpenChange={(open) => !open && closeModal()} + noHeaderYn="Y" + noFooterYn="Y" + /> + )} + + ); +} diff --git a/apps/fo/app/pages/dashboard/maingraph/page.tsx b/apps/fo/app/pages/dashboard/maingraph/page.tsx new file mode 100644 index 000000000..dc0a08912 --- /dev/null +++ b/apps/fo/app/pages/dashboard/maingraph/page.tsx @@ -0,0 +1,243 @@ +"use client" +import { useFoStore } from "@/app/store"; +import type { lineChartDataProps } from "@/app/store/dashboard"; +import { CHART_FORM, type ChartConfig, ContentsDiv, MainChart } from "@common/business_components"; +import { Card, CardContent } from "@common/business_components/ui/chart/lib/card"; +import ListDiv from "@common/business_components/ui/list_div"; +import { useEffect, useState } from "react"; + +type facilityInfoProps = { + searchYear?: string; + fcltyList?: { bscFctCd: string, bscFctNm: string, fcltyCpc: number | '', trtFrfNm: string, efflWqltStndrdNm: string }[]; +}; + +export default function DashBoardChart({searchYear = '', fcltyList = []}: facilityInfoProps) { + const {MainGraph + ,searchMainGraph + } = useFoStore((state) => state); + + const [hasSearched, setHasSearched] = useState(false); + const [prevFacilityCode, setPrevFacilityCode] = useState(''); + const [chart_tpTp, setChart_tpTp] = useState<{ + chartData1: lineChartDataProps[]; + chartData2: lineChartDataProps[]; + }>(); + const [chart_tntn, setChart_tntn] = useState<{ + chartData1: lineChartDataProps[]; + chartData2: lineChartDataProps[]; + }>(); + const [chart_inflBodInflTn, setChart_inflBodInflTn] = useState<{ + chartData1: lineChartDataProps[]; + chartData2: lineChartDataProps[]; + }>(); + const [chart_inflBodInflTp, setChart_inflBodInflTp] = useState<{ + chartData1: lineChartDataProps[]; + chartData2: lineChartDataProps[]; + }>(); + + const { + chart_inflowRain, + chart_bodRain, + chart_inflTp, + chart_chongInTp, + chart_efflTp, + chart_inflTn, + chart_efflTn, + chart_inflBod, + } = MainGraph; + + /** + * 차트 Config + */ + const colors = ["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FFEEAD", "#D4A5A5"]; + + //유입하수량-강수량 + const chartConfig_inflowRain = { + barVal0: { + label: '강수량', + color: colors[2], + }, + lineVal0: { + label: '시설용량', + color: colors[1], + }, + lineVal1: { + label: '유입량', + color: colors[4], + } + } satisfies ChartConfig; + //강우량-유입BOD + const chartConfig_rainBod = { + barVal0: { + label: '강수량', + color: colors[2], + }, + lineVal0: { + label: '유입BOD', + color: colors[0], + }, + } satisfies ChartConfig; + + //총인유입T-P-방류T-P + const chartConfig_tptp = { + chartData1: { + label: '총인유입T-P', + color: colors[0], + }, + chartData2: { + label: '방류T-P', + color: colors[1], + }, + } satisfies ChartConfig; + + // 유입T-N-방류T-N + const chartConfig_tntn = { + chartData1: { + label: '유입T-N', + color: colors[0], + }, + chartData2: { + label: '방류T-N', + color: colors[1], + }, + } satisfies ChartConfig; + + // 유입BOD-유입T-N + const chartConfig_inflBodInflTn = { + chartData1: { + label: '유입BOD', + color: colors[0], + }, + chartData2: { + label: '유입T-N', + color: colors[1], + }, + } satisfies ChartConfig; + + // 유입BOD-유입T-P + const chartConfig_inflBodInflTp = { + chartData1: { + label: '유입BOD', + color: colors[0], + }, + chartData2: { + label: '유입T-P', + color: colors[1], + }, + + } satisfies ChartConfig; + + useEffect(() => { + if (fcltyList.length > 0 && fcltyList[0]?.bscFctCd && (fcltyList[0].bscFctCd !== prevFacilityCode || !hasSearched)) { + searchMainGraph(searchYear, fcltyList[0].bscFctCd); + setHasSearched(true); + setPrevFacilityCode(fcltyList[0].bscFctCd); + } + }, [searchYear, fcltyList, searchMainGraph, hasSearched, chart_inflTp, chart_efflTp, prevFacilityCode]); + + useEffect(() => { + if (!chart_chongInTp || !chart_efflTp) return; + const chartTpTpData = { + chartData1: chart_chongInTp, + chartData2: chart_efflTp + }; + setChart_tpTp(chartTpTpData); + }, [chart_chongInTp, chart_efflTp]); + + useEffect(() => { + if (!chart_inflTn || !chart_efflTn) return; + const chartTntnData = { + chartData1: chart_inflTn, + chartData2: chart_efflTn + }; + setChart_tntn(chartTntnData); + }, [chart_inflTn, chart_efflTn]); + + useEffect(() => { + if (!chart_inflBod || !chart_inflTn) return; + const chartInflBodInflTnData = { + chartData1: chart_inflBod, + chartData2: chart_inflTn + }; + setChart_inflBodInflTn(chartInflBodInflTnData); + }, [chart_inflBod, chart_inflTn]); + + useEffect(() => { + if (!chart_inflBod || !chart_inflTp) return; + const chartInflBodInflTpData = { + chartData1: chart_inflBod, + chartData2: chart_inflTp + }; + setChart_inflBodInflTp(chartInflBodInflTpData); + }, [chart_inflBod, chart_inflTp]); + + // 연도가 바뀌면 hasSearched를 false로 리셋 + useEffect(() => { + setHasSearched(false); + }, [searchYear]); + + return ( + <> + + + + + + + + + + + + + + + + + + + + + + + {/* 유입T-N-방류T-N */} + + + + + + + + {/* 유입BOD-유입T-N */} + + + + + + + + {/* 유입BOD-유입T-P */} + + + + + + + + + + ); + {/*
> + +
+
+ +
+
+ +
+
+ +
+ */} +} diff --git a/apps/fo/app/pages/dashboard/page.tsx b/apps/fo/app/pages/dashboard/page.tsx new file mode 100644 index 000000000..97b45fd06 --- /dev/null +++ b/apps/fo/app/pages/dashboard/page.tsx @@ -0,0 +1,306 @@ +"use client" +import { useFoStore } from "@/app/store"; +import { ContentsDiv, downloadExcel, downloadMultipleExcel, filePickedBlobArray, MainDiv, SelectBox, UITab, type SelectDataType } from "@common/business_components"; +import { Button, TabsContent } from "@common/components/ui"; +import { useEffect, useState } from "react"; +import DashBoardFclty from "../dashboardMain/page"; +/* import DrainageEquipment from "./drainageEquipment/page"; */ +import ProcessFacilitySearch from "./facilityInfo/page"; +import DashBoardChart from "./maingraph/page"; +import RainManageTab from "./rainManage/page"; +import DrainageEquipment from "./drainageEquipment/page"; + +const tabList = [ + { value: 'facilityInfo', label: '시설정보 및 운영현황' }, + { value: 'mainGraph', label: '주요그래프' }, + { value: 'rainManage', label: '강우일 운영현황' }, + { value: 'drainageEquipment', label: '배수설비 정비현황' } +]; + +export default function DashBoard() { + // 입력값 상태 관리 + const { Common, initializeCommonData,searchMainGraph, searchRainManage, searchOperationStatus, OperationStatus, RainManage, MainGraph, PlanFclty } = useFoStore((state) => state); + const [activeTab, setActiveTab] = useState('facilityInfo'); + + const [filteredSigunData, setFilteredSigunData] = useState([{ text: "전체", val: '0' }]); + const [sidoValue, setSidoValue] = useState('0'); + const [sigunValue, setSigunValue] = useState('0'); + const { + isInit, + selectSearchYear, + btnClass, + selectSidoData, + selectSigunData, + } = Common; + + const { + planFcltyList + } = PlanFclty; + + const { + operationalStatusList + } = OperationStatus; + + const { + excelList + } = RainManage; + + const { + chart_inflowRain, + chart_bodRain, + chart_inflTp, + chart_chongInTp, + chart_efflTp, + chart_inflTn, + chart_efflTn, + } = MainGraph; + + /******************선택된 데이터******************/ + // 연도 + const [searchYear, setSearchYear] = useState(selectSearchYear[0]?.val || '0'); + // 시설명 + const [fcltyList, setFcltyList] = useState<{bscFctCd: string, bscFctNm: string, fcltyCpc: number | '', trtFrfNm: string | '', efflWqltStndrdNm: string | ''}>({ + bscFctCd: '', + bscFctNm: '', + fcltyCpc: '', + trtFrfNm: '', + efflWqltStndrdNm: '' + }); + + useEffect(() => { + if (!isInit) { + initializeCommonData(); + setFcltyList({ + bscFctCd: '11000SW001R', + bscFctNm: '난지', + fcltyCpc: 860000, + trtFrfNm: '표준활성슬러지법, MLE, A2O', + efflWqltStndrdNm: '500톤 이상(Ⅲ지역)' + }); + } + }, [isInit, initializeCommonData]); + + const handleFacilityChange = (facility: { bscFctCd: string, bscFctNm: string, fcltyCpc: number | '', trtFrfNm: string | '', efflWqltStndrdNm: string | '' }) => { + setFcltyList(facility); + }; + + const onSelectValue = (val: string, type: string) => { + switch(type) { + case 'sido': + setSidoValue(val); + initializeSigunData(val); + onSelectValue('0', 'sigun'); + break; + case 'sigun': + setSigunValue(val); + break; + } + } + + // 시군구 세팅 + const initializeSigunData = (sidoCd: string) => { + if (sidoCd === '0') { + setSigunValue('0'); + setFilteredSigunData([{ text: "전체", val: '0' }]); + } else { + const newFilteredData = [ + { text: "전체", val: '0' }, + ...selectSigunData.filter((item: SelectDataType) => item.val.substring(0, 2) === sidoCd) + ]; + setSigunValue('0'); + setFilteredSigunData(newFilteredData); + } + } + + const excelDownload = () => { + if (!fcltyList.bscFctCd) return; + switch (activeTab) { + case 'facilityInfo': + searchOperationStatus(false, searchYear, fcltyList.bscFctCd); + + fetch(`/mainDashBoard.xlsx`, {}).then(async (response) => { + if (!response.ok) { + throw Error(response.statusText); + } + // 받은 파일 바인너리 처리 + const blobRet = await response.arrayBuffer(); + + const excelData1 = planFcltyList.map((item) => { + return [ + item.item, + item.provisionalApproval, + item.now, + item.stepOne, + item.stepTwo, + item.stepThree, + item.stepFour, + ]; + }); + + // operationalStatusList를 2차원 배열로 변환 + const excelData2 = operationalStatusList.map((item, index) => { + const baseData = [ + item.yearAvg, + item.yearMax, + item.yearMin, + item.summerAll, + item.summerThree, + item.summerRain, + item.winterAll, + item.winterSunnyAvg, + item.winterSunnyMax, + item.winterSunnyMin, + item.groundWaterAvg, + item.groundWaterSummer, + item.groundWaterWinter + ]; + + // index가 0일 때만 rdi와 rdiRain 추가 + return index === 0 ? [...baseData, item.rdi, item.rdiRain] : baseData; + }); + + const sheetParameter = [ + { + data: excelData1, + headerNum: 3, + headerRange: 'A1:G2', + sheetName: '운영실태', + startCol: 'A' + }, + { + data: excelData2, + headerNum: 4, + headerRange: 'A1:Q3', + sheetName: '운영실태', + startCol: 'C' + } + ]; + // 버퍼에 있는 엑셀데이터 전달 후 json으로 변환 + await filePickedBlobArray(blobRet, '시설정보및운영현황황', sheetParameter); + }); + break; + + case 'mainGraph': + searchMainGraph(searchYear, fcltyList.bscFctCd); + + const sheetParameter = [ + { + data: [['날짜', '강수량'],...chart_inflowRain.map((item) => [item.label, item.barVal0])], + headerNum: 1, + headerRange: 'A1:B1', + sheetName: '강수량' + }, + { + data: [['날짜', '유입하수량'],...chart_inflowRain.map((item) => [item.label, item.lineVal1])], + headerNum: 1, + headerRange: 'A1:B1', + sheetName: '유입하수량' + }, + { + data: [['날짜', '시설용량'],...chart_inflowRain.map((item) => [item.label, item.lineVal0])], + headerNum: 1, + headerRange: 'A1:B1', + sheetName: '시설용량' + }, + { + data: [['날짜', '유입BOD'],...chart_bodRain.map((item) => [item.label, item.lineVal0])], + headerNum: 1, + headerRange: 'A1:B1', + sheetName: '유입BOD' + }, + { + data: [['날짜', '유입T-P'],...chart_inflTp.map((item) => [item.label, item.val])], + headerNum: 1, + headerRange: 'A1:B1', + sheetName: '유입T-P' + }, + { + data: [['날짜', '총인유입T-P'],...chart_chongInTp.map((item) => [item.label, item.val])], + headerNum: 1, + headerRange: 'A1:B1', + sheetName: '총인유입T-P' + }, + { + data: [['날짜', '방류T-P'],...chart_efflTp.map((item) => [item.label, item.val])], + headerNum: 1, + headerRange: 'A1:B1', + sheetName: '방류T-P' + }, + { + data: [['날짜', '유입T-N'],...chart_inflTn.map((item) => [item.label, item.val])], + headerNum: 1, + headerRange: 'A1:B1', + sheetName: '유입T-N' + }, + { + data: [['날짜', '방류T-N'],...chart_efflTn.map((item) => [item.label, item.val])], + headerNum: 1, + headerRange: 'A1:B1', + sheetName: '방류T-N' + } + ]; + + downloadMultipleExcel('주요그래프', sheetParameter); + break; + + case 'rainManage': + searchRainManage(searchYear, fcltyList.bscFctCd, true); + if (excelList && excelList.length > 0) { + downloadExcel({ data: excelList as unknown as JSON[], fileName: '강우일 운영현황', sheetNameArray: ['강우일 운영현황'], headerRange: 'A1:T1' }); + } + break; + // Add other cases for different tabs as needed + default: + break; + } + } + + const initVal = () => { + setFcltyList({ + bscFctCd: '11000SW001R', + bscFctNm: '난지', + fcltyCpc: 860000, + trtFrfNm: '표준활성슬러지법, MLE, A2O', + efflWqltStndrdNm: '500톤 이상(Ⅲ지역)' + }); + } + + return ( + + +
+
+ setSearchYear(val.toString()) } value={searchYear} selectClass={undefined}/> + onSelectValue(val.toString(), 'sido')} value={sidoValue} selectClass={undefined}/> + onSelectValue(val.toString(), 'sigun')} value={sigunValue} selectClass={undefined}/> +
+ +
+
+
+ + +
+
+ + + + + + + + + + + + + + +
+
+ ); +} diff --git a/apps/fo/app/pages/dashboard/rainManage/page.tsx b/apps/fo/app/pages/dashboard/rainManage/page.tsx new file mode 100644 index 000000000..ea20eb92c --- /dev/null +++ b/apps/fo/app/pages/dashboard/rainManage/page.tsx @@ -0,0 +1,59 @@ +"use client" +import { useFoStore } from "@/app/store"; +import { UiTable } from "@common/business_components/ui/table"; +import { useEffect, useState } from "react"; + +export type facilityInfoProps = { + searchYear?: string; + fcltyList?: { bscFctCd: string, bscFctNm: string, fcltyCpc: number | '', trtFrfNm: string, efflWqltStndrdNm: string }[]; +}; + +export default function RainManageTab({searchYear = '', fcltyList = []}: facilityInfoProps) { + + const { + Common, + searchRainManage, + RainManage + } = useFoStore((state) => state); + + const [hasSearched, setHasSearched] = useState(false); + // 이전 시설코드 저장 + const [prevFacilityCode, setPrevFacilityCode] = useState(''); + + const { + isInit, + } = Common; + + const { + upHeadListRainManage, + rainManageList, + } = RainManage; + + const tableData = fcltyList; + + useEffect(() => { + if (!isInit && tableData[0]?.bscFctCd && (tableData[0].bscFctCd !== prevFacilityCode || !hasSearched)) { + searchRainManage(searchYear, tableData[0].bscFctCd, false); + setHasSearched(true); + setPrevFacilityCode(tableData[0].bscFctCd); + } + }, [fcltyList, isInit, searchRainManage, searchYear, tableData, hasSearched, prevFacilityCode]); + + // 연도가 바뀌면 hasSearched를 false로 리셋 + useEffect(() => { + setHasSearched(false); + }, [searchYear]); + + return ( + {}} + > + + ) +} diff --git a/apps/fo/app/pages/dashboardMain/page.tsx b/apps/fo/app/pages/dashboardMain/page.tsx new file mode 100644 index 000000000..3fa403d90 --- /dev/null +++ b/apps/fo/app/pages/dashboardMain/page.tsx @@ -0,0 +1,58 @@ +"use client" +import { useFoStore } from "@/app/store"; +import { useEffect, useState } from "react"; +import SearchInput from "../../components/common/SearchInput"; + +export default function DashBoardFclty({ onFacilityChange, sidoSigun, facilityNm }: { onFacilityChange?: (facility: { bscFctCd: string, bscFctNm: string, fcltyCpc: number | '', trtFrfNm: string | '', efflWqltStndrdNm: string | '' }) => void, sidoSigun?: string, facilityNm?: string }) { + // 입력값 상태 관리 + const { Common, initializeCommonData } = useFoStore((state) => state); + + const { + isInit, + } = Common; + + // 시설명 + const [bscFctNm, setFcltyName] = useState(facilityNm || '난지'); + const [bscFctCd, setbscFctCd] = useState('11000SW001R'); + const [fcltyCpc, setFcltyCpc] = useState(860000); + const [trtFrfNm, setTrtFrfNm] = useState('표준활성슬러지법, MLE, A2O'); + const [efflWqltStndrdNm, setEfflWqltStndrdNm] = useState('500톤 이상(Ⅲ지역)'); + + useEffect(() => { + if (!isInit) { + initializeCommonData(); + } + }, [isInit, initializeCommonData ]); + + useEffect(() => { + if (facilityNm) { + setFcltyName(facilityNm); + } + }, [facilityNm]); + + const fncNextPage = (bscFctCd?: string, bscFctNm?: string, fcltyCpc?: number | '', trtFrfNm?: string | '', efflWqltStndrdNm?: string | '') => { + setbscFctCd(bscFctCd || ''); + setFcltyName(bscFctNm || ''); + setFcltyCpc(fcltyCpc || ''); + setTrtFrfNm(trtFrfNm || ''); + setEfflWqltStndrdNm(efflWqltStndrdNm || ''); + + if (bscFctCd && onFacilityChange) { + onFacilityChange({ + bscFctCd: bscFctCd || '', + bscFctNm: bscFctNm || '', + fcltyCpc: fcltyCpc || '', + trtFrfNm: trtFrfNm || '', + efflWqltStndrdNm: efflWqltStndrdNm || '' + }); + } + } + + console.log('bscFctNm : ', bscFctNm); + + return ( + <> + + + ); +} \ No newline at end of file diff --git a/apps/fo/app/pages/facilityPrecipitation/modal/page.tsx b/apps/fo/app/pages/facilityPrecipitation/modal/page.tsx new file mode 100644 index 000000000..ead9b56fd --- /dev/null +++ b/apps/fo/app/pages/facilityPrecipitation/modal/page.tsx @@ -0,0 +1,203 @@ +"use client" +import { useFoStore } from "@/app/store"; +import type { PrecipitationPropsDetailProps } from "@/app/store/facilityPrecipitation"; +import { DatePickerRange, UiTable } from "@common/business_components/ui"; +import ListDiv from "@common/business_components/ui/list_div"; +import { Table, TableCell, TableHead, TableRow } from "@common/components/ui"; +import { useEffect, useRef, useState } from "react"; + +type PrecipitationModalProps = { + searchYear: string; + fcltyName: string; + facilityCd: string; + detailList: PrecipitationPropsDetailProps[]; +} + +type DateRange = { + start: Date; + end: Date; +} + +export default function PrecipitationModal(props: PrecipitationModalProps) { + const { PrecipitationDetail } = useFoStore((state) => state); + const { upHeadListPrecipitationDetail } = PrecipitationDetail; + + // Refs + const startPickerRef = useRef(null); + const endPickerRef = useRef(null); + + // States + const [startDate, setStartDate] = useState(null); + const [endDate, setEndDate] = useState(null); + const [filteredDetailList, setFilteredDetailList] = useState([]); + const [copyDetailList, setCopyDetailList] = useState([]); + + const getDateRanges = (): DateRange[] => { + const standYear = parseInt(props.searchYear); + return [{ + start: new Date(standYear, 0, 1), + end: new Date(standYear, 11, 31) + }]; + }; + + const isDateInRanges = (date: Date): boolean => { + return getDateRanges().some(range => { + const start = new Date(range.start); + const end = new Date(range.end); + return date >= start && date <= end; + }); + }; + + const filterDataByDateRange = (start: Date | null, end: Date | null): PrecipitationPropsDetailProps[] => { + if (!start || !end) return filteredDetailList; + return filteredDetailList.filter((item) => { + const itemDate = new Date(item.rainDt); + return itemDate >= start && itemDate <= end; + }); + }; + + const handleStartDateSelect = (date: Date | null) => { + if (!date || !endDate) return; + + if (date > endDate) { + alert('시작일은 종료일 이후일 수 없습니다.'); + return; + } + + const filteredData = filterDataByDateRange(date, endDate); + setCopyDetailList(filteredData); + setStartDate(date); + + const button = startPickerRef.current?.querySelector('button'); + if (button) { + setTimeout(() => button.click(), 0); + } + }; + + const handleEndDateSelect = (date: Date | null) => { + if (!date || !startDate) return; + + if (date < startDate) { + alert('종료일은 시작일 이전일 수 없습니다.'); + return; + } + + const filteredData = filterDataByDateRange(startDate, date); + setCopyDetailList(filteredData); + setEndDate(date); + + const button = endPickerRef.current?.querySelector('button'); + if (button) { + setTimeout(() => button.click(), 0); + } + }; + + const calculateTotals = () => { + return copyDetailList.reduce((acc, item) => ({ + infoRnDay: acc.infoRnDay + Number(item.infoRnDay), + rainDay: acc.rainDay + Number(item.rainDay), + rainEffectDay: acc.rainEffectDay + Number(item.rainEffectDay) + }), { infoRnDay: 0, rainDay: 0, rainEffectDay: 0 }); + }; + + const getTableData = () => { + const totals = calculateTotals(); + return [ + { + bscFctCd: "", + rainDt: '합계', + ...totals + }, + ...copyDetailList + ]; + }; + + useEffect(() => { + if (props.detailList.length > 0) { + const filteredList = props.detailList.filter((item) => + props.facilityCd === item.bscFctCd + ); + + setFilteredDetailList(filteredList); + setCopyDetailList(filteredList); + + if (filteredList.length > 0) { + const firstDateStr = filteredList[0]?.rainDt; + const lastDateStr = filteredList[filteredList.length - 1]?.rainDt; + + if (firstDateStr) { + const firstDate = new Date(firstDateStr); + if (!isNaN(firstDate.getTime())) { + setStartDate(firstDate); + } + } + + if (lastDateStr) { + const lastDate = new Date(lastDateStr); + if (!isNaN(lastDate.getTime())) { + setEndDate(lastDate); + } + } + } + } + }, [props.detailList, props.facilityCd]); + + if (!startDate || !endDate) { + return
로딩 중...
; + } + + return ( + <> + +
+ + + + {'시설명'} + {props.fcltyName} + {'년월'} + +
+
+ handleStartDateSelect(date as Date)} + className="w-full p-1 border rounded bg-white" + disabled={(date) => !isDateInRanges(date)} + defaultMonth={startDate} + /> +
+ ~ +
+ handleEndDateSelect(date as Date)} + className="w-full p-1 border rounded bg-white" + disabled={(date) => !isDateInRanges(date)} + defaultMonth={endDate} + /> +
+
+
+
+ +
+
+
+ + {}} + boldArray={[0]} + /> + + + ); +} \ No newline at end of file diff --git a/apps/fo/app/pages/facilityPrecipitation/page.tsx b/apps/fo/app/pages/facilityPrecipitation/page.tsx new file mode 100644 index 000000000..c9403fd14 --- /dev/null +++ b/apps/fo/app/pages/facilityPrecipitation/page.tsx @@ -0,0 +1,249 @@ +"use client" +import { useFoStore } from "@/app/store"; +import type { TableUpperProps } from "@/app/store/common"; +import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; +import ListDiv from "@common/business_components/ui/list_div"; +import { useCallback, useEffect, useRef, useState } from "react"; +import PrecipitationModal from "./modal/page"; + +export default function FacilityPrecipitation() { + const {Common + ,FacilityPrecipitation + ,FacilityPrecipitationSearch + ,PrecipitationDetail + ,initializeCommonData + ,searchFacilityPrecipitationList + } = useFoStore((state) => state) || { processAreaList: { processAreaList: [] }}; + + const { + isInit, + selectSidoData, + selectSigunData, + selectRegionData, + selectUnitWaterShedData, + selectMiddleRegionData, + selectEnvPartData, + selectUpdownData, + selectOperationData, + selectSearchYear, + btnClass + } = Common; + + const { + labelArray, + } = FacilityPrecipitationSearch; + + const { + upHeadList1, + upHeadList2, + upHeadList3, + excelList, + facilityPrecipitation, + facilityPrecipitationCount + } = FacilityPrecipitation; + + const { + gridListPrecipitationDetail + } = PrecipitationDetail; + + const ref = useRef({ + partValue: '', + sidoValue: '', + sigunValue: '', + regionValue: '', + unitWaterShedValue: '', + middleRegionValue: '', + envPartValue: '', + sidoText: '', + sigunText: '' + }); + + const facilityPrecipitationList = FacilityPrecipitation?.facilityPrecipitation || []; + + // 그리드 관련 + const searchInputRef = useRef(null); + + // 모달 상태 추가 + const [selectedRow, setSelectedRow] = useState(null); + const [fcltyNm, setFcltyNm] = useState(""); + const [fcltyCd, setFcltyCd] = useState(""); + + // 초기화 변수 + const [resetPage, setResetPage] = useState(false); + // 표 너비 + const [widthSize, setWidthSize] = useState("w-[120%]"); + // 구분별 그리드 헤더 + const [upheadList, setUpheadList] = useState(upHeadList1); + // 용량별 + const [fcltCpct, setFcltCpct] = useState("0"); + // 시설명 + const [fcltyName, setFcltyName] = useState(""); + // 시설상태 + const [operationValue, setOperationValue] = useState("0"); + // 조회기간 + const [searchYear, setSearchYear] = useState(selectSearchYear[0]?.val || "0"); + + /** + * 페이지 함수 + */ + // 초기화 + const resetVal = () => { + setWidthSize("w-[120%]"); + setUpheadList(upHeadList1) + // 상태값 설정 + setFcltCpct(selectUpdownData[0]?.val || "0"); + setOperationValue(selectOperationData[0]?.val || "0"); + setSearchYear(selectSearchYear[0]?.val || "0"); + // SearchInputSelect 초기화 + setFcltyName(""); + if (searchInputRef.current) { + const input = searchInputRef.current.querySelector('input'); + if (input) { + input.value = ""; + } + } + searchFacilityPrecipitationList(1, 10, selectSearchYear[0]?.val || "0"); + } + + // 모달 닫기 + const closeModal = () => { + setSelectedRow(null); + }; + + // 셀 클릭 시 모달 표시 + const cellClick = (index: number) => { + if (facilityPrecipitation[index]) { + setFcltyNm(facilityPrecipitation[index].bscFctNm); + setFcltyCd(facilityPrecipitation[index].bscFctCd); + setSelectedRow(index); // 클릭한 행의 index 저장 + } + }; + + /** + * useEffect + */ + useEffect(() => { + if (!isInit) { + initializeCommonData(); + searchFacilityPrecipitationList(1, 10, selectSearchYear[0]?.val || "0"); + } + }, [isInit, initializeCommonData, searchFacilityPrecipitationList, selectSearchYear]); + + useEffect(() => { + if (excelList && excelList.length > 0) { + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: '시설별 강수현황', + sheetNameArray: ['시설별 강수현황'], + headerRange: 'A1:N1' + }); + } + }, [excelList]); + + useEffect(() => { + if (facilityPrecipitation.length > 0) { + + } + }, [facilityPrecipitation]); + + /** + * 콜백함수 + */ + // 조회 + const searchFacilityPrecipitation = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { + console.log('partValue : ', partValue); + console.log('regionValue : ', regionValue); + console.log('unitWaterShedValue : ', unitWaterShedValue); + console.log('middleRegionValue : ', middleRegionValue); + console.log('envPartValue : ', envPartValue); + console.log('sidoValue : ', sidoValue); + console.log('sigunValue : ', sigunValue); + + let nameCd, partStr + switch (partValue) { + case 'R': + if (regionValue !== '0') { + if(unitWaterShedValue==='0') nameCd = regionValue; + else if (middleRegionValue==='0') nameCd = unitWaterShedValue; + else nameCd = middleRegionValue; + } + partStr = partValue + break; + default: + if(sidoValue !== '0') nameCd = sidoValue; + if(sigunValue !== '0') nameCd = sigunValue; + partStr = envPartValue !== '0' ? envPartValue:partValue; + break; + } + if (partStr.length > 1 || operationValue!== '0' || fcltCpct !== '0' ||nameCd ||(fcltyName.trim() !== "" && fcltyName.trim() !== null)) { + searchFacilityPrecipitationList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); + } else { + searchFacilityPrecipitationList(pageNo, pageCnt, searchYear); + } + }, [operationValue, fcltyName, searchFacilityPrecipitationList, searchYear, fcltCpct]); + + const chkVal = useCallback((returntype:ReturnType) => { + setWidthSize(returntype.partValue=='A' ?"w-[120%]":"w-[130%]") + setUpheadList(returntype.partValue == 'R' ? upHeadList2 : returntype.partValue == 'G'?upHeadList3:upHeadList1); + setResetPage(true); + }, [upHeadList1, upHeadList2, upHeadList3]); + + // 엑셀다운로드 + const excelDownload = useCallback((searchReturn: ReturnType) => { + searchFacilityPrecipitation(searchReturn, 1, 10000); + }, [searchFacilityPrecipitation]); + + // 페이지 변경 + const handlePageChange = useCallback((page: number) => { + setResetPage(false); + searchFacilityPrecipitation(ref.current, page, 10); + }, [searchFacilityPrecipitation]); + + const mainList = facilityPrecipitationList || []; + const total = facilityPrecipitationCount || 0; + + return ( + + + <ContentsDiv> + <SearchBaseForm + leftChildren={<> + <SelectBox className="col-span-3" label={labelArray[3] as string} selectArray={selectUpdownData} onSelectValue={(val) => setFcltCpct(val.toString())} value={fcltCpct} selectClass={undefined} /> + <SearchInput className={"col-span-3"} label={labelArray[4] as string} textValue={fcltyName} setText={setFcltyName} /> + <SelectBox className="col-span-3" label={labelArray[6] as string} selectArray={selectSearchYear} onSelectValue={(val) => setSearchYear(val.toString())} value={searchYear} selectClass={undefined} /> + <SelectBox className="col-span-3" label={labelArray[5] as string} selectArray={selectOperationData} onSelectValue={(val) => setOperationValue(val.toString())} value={operationValue} selectClass={undefined} /> + </>} + rightChildren={undefined} + selectSidoData={selectSidoData} + selectSigunData={selectSigunData} + selectRegionData={selectRegionData} + selectUnitWaterShedData={selectUnitWaterShedData} + selectMiddleRegionData={selectMiddleRegionData} + selectEnvPartData={selectEnvPartData} + btnClass={btnClass} + queryClick={chkVal} + excelClick={excelDownload} + initClick={resetVal} + ref={ref} isAdmin={false} /> + <ListDiv> + <div className="h-full w-full overflow-x-scroll"> + <div className={widthSize}> + <UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"시설별 강수현황"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} /> + </div> + <span className="text-2xl font-bold text-gray-500">☞ 강우일은 3mm 이상만 해당 / 강우영향일은 강우일 및 강우일 후 연속 2일간으로 정의</span> + </div> + </ListDiv> + </ContentsDiv> + {selectedRow !== null && ( + <UiModal + body={<PrecipitationModal searchYear={searchYear} fcltyName={fcltyNm} facilityCd={fcltyCd} detailList={gridListPrecipitationDetail}></PrecipitationModal>} + bodyClass="sm:max-w-[90vw] w-[72vw] h-[40vw]" + open={selectedRow !== null} + onOpenChange={(open) => !open && closeModal()} + noHeaderYn="Y" + noFooterYn="Y" + /> + )} + </MainDiv> + ); +} \ No newline at end of file diff --git a/apps/fo/app/pages/facilityWaterQlty/HeadMakeColSpan.tsx b/apps/fo/app/pages/facilityWaterQlty/HeadMakeColSpan.tsx new file mode 100644 index 000000000..61076c105 --- /dev/null +++ b/apps/fo/app/pages/facilityWaterQlty/HeadMakeColSpan.tsx @@ -0,0 +1,176 @@ +import { TableHead, TableRow } from "@common/components/ui"; + +interface TableUpperProps { + id: string; + title: string; + upName?: string; + upSequnce?: number; +} + +const HeadMakeColSpan = ({ upHeadList, layoutNum }: { upHeadList: TableUpperProps[], layoutNum: number }) => { + return ( + layoutNum === 0 ? ( + <> + <TableRow className="bg-gray-50"> + {upHeadList.map((head: TableUpperProps) => { + if(!head.upName) { + return <TableHead className="bg-gray-50" rowSpan={2} style={{ whiteSpace: 'pre-line' }} key={head.id}>{head.title}</TableHead> + }else if(head.upName==="upChangeRe1"&&head.upSequnce===1) { + return <TableHead className="bg-gray-50" colSpan={2} style={{ whiteSpace: 'pre-line' }} key={head.id}>행정구역</TableHead> + }else if(head.upName==="upChangeRe3"&&head.upSequnce===1) { + return <TableHead className="bg-gray-50" colSpan={5} style={{ whiteSpace: 'pre-line' }} key={head.id}>유입</TableHead> + }else if(head.upName==="upChangeRe4"&&head.upSequnce===1) { + return <TableHead className="bg-gray-50" colSpan={5} style={{ whiteSpace: 'pre-line' }} key={head.id}>유출</TableHead> + } + })} + </TableRow> + <TableRow className="bg-gray-50"> + {upHeadList.map((head: TableUpperProps, idx: number) => { + if (head.upName === 'upChangeRe1' || head.upName === 'upChangeRe3' || head.upName === 'upChangeRe4') { + if (idx == 1 || idx == 2 || idx == 3) { + return <TableHead key={head.id} style={{ whiteSpace: 'pre-line' }} className="w-1/8 bg-gray-50">{head.title}</TableHead>; + } + else { + return <TableHead key={head.id} style={{ whiteSpace: 'pre-line' }} className="w-1/8 bg-gray-50">{head.title}</TableHead>; + } + } + })} + </TableRow> + </> + ) : layoutNum === 1 ? ( + <> + <TableRow className="bg-gray-50"> + {upHeadList.map((head: TableUpperProps) => { + if(!head.upName) { + return <TableHead className="bg-gray-50" rowSpan={2} style={{ whiteSpace: 'pre-line' }} key={head.id}>{head.title}</TableHead> + }else if(head.upName==="upChangeRe1"&&head.upSequnce===1) { + return <TableHead className="bg-gray-50" colSpan={3} style={{ whiteSpace: 'pre-line' }} key={head.id}>권역</TableHead> + }else if(head.upName==="upChangeRe3"&&head.upSequnce===1) { + return <TableHead className="bg-gray-50" colSpan={5} style={{ whiteSpace: 'pre-line' }} key={head.id}>유입</TableHead> + }else if(head.upName==="upChangeRe4"&&head.upSequnce===1) { + return <TableHead className="bg-gray-50" colSpan={5} style={{ whiteSpace: 'pre-line' }} key={head.id}>유출</TableHead> + } + })} + </TableRow> + <TableRow className="bg-gray-50"> + {upHeadList.map((head: TableUpperProps, idx: number) => { + if (head.upName === 'upChangeRe1' || head.upName === 'upChangeRe3' || head.upName === 'upChangeRe4') { + if (idx == 1 || idx == 2 || idx == 3) { + return <TableHead key={head.id} style={{ whiteSpace: 'pre-line' }} className="w-1/8 bg-gray-50">{head.title}</TableHead>; + } + else { + return <TableHead key={head.id} style={{ whiteSpace: 'pre-line' }} className="w-1/8 bg-gray-50">{head.title}</TableHead>; + } + } + })} + </TableRow> + </> + ) : layoutNum === 2 ? ( + <> + <TableRow className="bg-gray-50"> + {upHeadList.map((head: TableUpperProps) => { + if(!head.upName) { + return <TableHead className="bg-gray-50" rowSpan={2} style={{ whiteSpace: 'pre-line' }} key={head.id}>{head.title}</TableHead> + }else if(head.upName==="upChangeRe1"&&head.upSequnce===1) { + return <TableHead className="bg-gray-50" colSpan={3} style={{ whiteSpace: 'pre-line' }} key={head.id}>권역</TableHead> + }else if(head.upName==="upChangeRe2"&&head.upSequnce===1) { + return <TableHead className="bg-gray-50" colSpan={2} style={{ whiteSpace: 'pre-line' }} key={head.id}>행정구역</TableHead> + }else if(head.upName==="upChangeRe3"&&head.upSequnce===1) { + return <TableHead className="bg-gray-50" colSpan={5} style={{ whiteSpace: 'pre-line' }} key={head.id}>유입</TableHead> + }else if(head.upName==="upChangeRe4"&&head.upSequnce===1) { + return <TableHead className="bg-gray-50" colSpan={5} style={{ whiteSpace: 'pre-line' }} key={head.id}>유출</TableHead> + } + })} + </TableRow> + <TableRow className="bg-gray-50"> + {upHeadList.map((head: TableUpperProps, idx: number) => { + if (head.upName === 'upChangeRe1' || head.upName === 'upChangeRe2' || head.upName === 'upChangeRe3' || head.upName === 'upChangeRe4') { + if (idx == 1 || idx == 2 || idx == 3) { + return <TableHead key={head.id} style={{ whiteSpace: 'pre-line' }} className="w-1/8 bg-gray-50">{head.title}</TableHead>; + } + else { + return <TableHead key={head.id} style={{ whiteSpace: 'pre-line' }} className="w-1/8 bg-gray-50">{head.title}</TableHead>; + } + } + })} + </TableRow> + </> + ) : layoutNum === 3 ? ( + <> + <TableRow className="bg-gray-50"> + {upHeadList.map((head: TableUpperProps) => { + if(!head.upName) { + return <TableHead className="bg-gray-50" rowSpan={2} style={{ whiteSpace: 'pre-line' }} key={head.id}>{head.title}</TableHead> + }else if(head.upName==="upChangeRe1"&&head.upSequnce===1) { + return <TableHead className="bg-gray-50" colSpan={5} style={{ whiteSpace: 'pre-line' }} key={head.id}>유입</TableHead> + }else if(head.upName==="upChangeRe2"&&head.upSequnce===1) { + return <TableHead className="bg-gray-50" colSpan={5} style={{ whiteSpace: 'pre-line' }} key={head.id}>방류</TableHead> + } + })} + </TableRow> + <TableRow className="bg-gray-50"> + {upHeadList.map((head: TableUpperProps, idx: number) => { + if (head.upName === 'upChangeRe1' || head.upName === 'upChangeRe2') { + if (idx == 1 || idx == 2 || idx == 3) { + return <TableHead key={head.id} style={{ whiteSpace: 'pre-line' }} className="w-1/8 bg-gray-50">{head.title}</TableHead>; + } + else { + return <TableHead key={head.id} style={{ whiteSpace: 'pre-line' }} className="w-1/8 bg-gray-50">{head.title}</TableHead>; + } + } + })} + </TableRow> + </> + ) : layoutNum === 4 ? ( + <> + <TableRow className="bg-gray-50"> + {upHeadList.map((head: TableUpperProps) => { + if(!head.upName) { + return <TableHead className="bg-gray-50" rowSpan={2} style={{ whiteSpace: 'pre-line' }} key={head.id}>{head.title}</TableHead> + }else if(head.upName==="upChangeRe"&&head.upSequnce===1) { + return <TableHead className="bg-gray-50" colSpan={4} style={{ whiteSpace: 'pre-line' }} key={head.id}>방류</TableHead> + } + })} + </TableRow> + <TableRow className="bg-gray-50"> + {upHeadList.map((head: TableUpperProps, idx: number) => { + if (head.upName === 'upChangeRe') { + if (idx == 1 || idx == 2 || idx == 3) { + return <TableHead key={head.id} style={{ whiteSpace: 'pre-line' }} className="w-1/8 bg-gray-50">{head.title}</TableHead>; + } + else { + return <TableHead key={head.id} style={{ whiteSpace: 'pre-line' }} className="w-1/8 bg-gray-50">{head.title}</TableHead>; + } + } + })} + </TableRow> + </> + ) : layoutNum === 5 ? ( // 총인설비 수질현황 헤더 + <> + <TableRow className="bg-gray-50"> + {upHeadList.map((head: TableUpperProps) => { + if(!head.upName) { + return <TableHead className="w-[180px] bg-gray-50" rowSpan={2} style={{ whiteSpace: 'pre-line' }} key={head.id}>{head.title}</TableHead> + }else if(head.upName==="upChangeRe1" && head.upSequnce===1) { + return <TableHead className="bg-gray-50" colSpan={2} style={{ whiteSpace: 'pre-line' }} key={head.id}>유입</TableHead> + }else if(head.upName==="upChangeRe2" && head.upSequnce===1) { + return <TableHead className="bg-gray-50" colSpan={2} style={{ whiteSpace: 'pre-line' }} key={head.id}>방류</TableHead> + } + })} + </TableRow> + <TableRow className="bg-gray-50"> + {upHeadList.map((head: TableUpperProps) => { + if (head.upName === 'upChangeRe1' || head.upName === 'upChangeRe2') { + return <TableHead key={head.id} style={{ whiteSpace: 'pre-line' }} className="w-1/8 bg-gray-50">{head.title}</TableHead>; + } + })} + </TableRow> + </> + ): ( + <> + </> + ) + ) +} + +export { HeadMakeColSpan }; diff --git a/apps/fo/app/pages/facilityWaterQlty/modal/page.tsx b/apps/fo/app/pages/facilityWaterQlty/modal/page.tsx new file mode 100644 index 000000000..ede0175aa --- /dev/null +++ b/apps/fo/app/pages/facilityWaterQlty/modal/page.tsx @@ -0,0 +1,537 @@ +"use client" +import { useFoStore } from "@/app/store"; +import type { FacilityWaterQltyProps } from "@/app/store/facilityWaterQlty"; +import { UITab, UiTable } from "@common/business_components/ui"; +import { TabsContent } from "@common/components/ui"; +import { useCallback, useEffect, useRef, useState } from "react"; +import type { ReturnType } from "../../../components/common/FacilityTermModalHeader"; +import FacilityTermModalHeader from "../../../components/common/FacilityTermModalHeader"; +import { HeadMakeColSpan } from "../HeadMakeColSpan"; + +type ModalProps ={ + fcltyName: string; + facilityCd : string; + searchYear : string; +} + +const tabList1 = [ + { value: 'tab_num1', label: '처리시설 수질현황' }, + { value: 'tab_num2', label: '총인설비 수질현황' }, +]; + +const tabList2 = [ + { value: 'tab_term_year', label: '연간' }, + { value: 'tab_term_summer', label: '하절기' }, + { value: 'tab_term_winter', label: '동절기' }, + { value: 'tab_term_chuncheon', label: '청천시' }, + { value: 'tab_term_rain', label: '강우시' } +]; + +const tabList3 = [ + { value: 'tab_term_year_chongin', label: '연간' }, + { value: 'tab_term_summer_chongin', label: '하절기' }, + { value: 'tab_term_winter_chongin', label: '동절기' } +]; + +export default function WaterQualityModal({fcltyName='', facilityCd='', searchYear=new Date().getFullYear().toString()} : ModalProps) { + // 그리드 관련 + const {FacilityWaterQltyModal, + searchFacilityWaterQltyListHist, + } = useFoStore((state) => state); + + const { + upHeadListModalYear, + facilityWaterQltyYearList, + upHeadListModalTms, + tmsList, + msrmtDate, + upHeadListModalChongIn, + } = FacilityWaterQltyModal; + + // 필터링 된 후 최대, 최소, 평균 값 계산 + const setFilterAfterData = (filteredData: FacilityWaterQltyProps[]) => { + // 쉼표가 포함된 문자열을 숫자로 변환하는 함수 + const parseNumber = (value: string | number | null | undefined): number => { + if (value === null || value === undefined || value === '') return 0; + if (typeof value === 'number') return value; + return Number(value.replace(/,/g, '')); + }; + + let maxEfflWqltBod = 0; + let maxEfflWqltTn = 0; + let maxEfflWqltTp = 0; + let maxefflWqltCod = 0; + let maxEfflWqltSs = 0; + + let maxInflAssctAftWqltBod = 0; + let maxInflAssctAftWqltTn = 0; + let maxInflAssctBfrWqltTp = 0; + let maxInflAssctAftWqltToc = 0; + let maxInflAssctAftWqltSs = 0; + + let maxTpInflWqltBod = 0; + let maxTpInflWqltTp = 0; + let maxInfoRnDay = 0; + + // 초기값 설정 + let minEfflWqltBod = filteredData.length > 0 ? parseNumber(filteredData[0]?.efflWqltBod) : 0; + let minEfflWqltTn = filteredData.length > 0 ? parseNumber(filteredData[0]?.efflWqltTn) : 0; + let minEfflWqltTp = filteredData.length > 0 ? parseNumber(filteredData[0]?.efflWqltTp) : 0; + let minefflWqltCod = filteredData.length > 0 ? parseNumber(filteredData[0]?.efflWqltCod) : 0; + let minEfflWqltSs = filteredData.length > 0 ? parseNumber(filteredData[0]?.efflWqltSs) : 0; + + let minInflAssctAftWqltBod = filteredData.length > 0 ? parseNumber(filteredData[0]?.inflAssctAftWqltBod) : 0; + let minInflAssctAftWqltTn = filteredData.length > 0 ? parseNumber(filteredData[0]?.inflAssctAftWqltTn) : 0; + let minInflAssctBfrWqltTp = filteredData.length > 0 ? parseNumber(filteredData[0]?.inflAssctBfrWqltTp) : 0; + let minInflAssctAftWqltToc = filteredData.length > 0 ? parseNumber(filteredData[0]?.inflAssctAftWqltToc) : 0; + let minInflAssctAftWqltSs = filteredData.length > 0 ? parseNumber(filteredData[0]?.inflAssctAftWqltSs) : 0; + + let minTpInflWqltBod = filteredData.length > 0 ? parseNumber(filteredData[0]?.tpInflWqltBod) : 0; + let minTpInflWqltTp = filteredData.length > 0 ? parseNumber(filteredData[0]?.tpInflWqltTp) : 0; + + let minInfoRnDay = filteredData.length > 0 ? parseNumber(filteredData[0]?.infoRnDay) : 0; + + let avgEfflWqltBod = 0; + let avgEfflWqltTn = 0; + let avgEfflWqltTp = 0; + let avgefflWqltCod = 0; + let avgEfflWqltSs = 0; + + let avgInflAssctAftWqltBod = 0; + let avgInflAssctAftWqltTn = 0; + let avgInflAssctBfrWqltTp = 0; + let avgInflAssctAftWqltToc = 0; + let avgInflAssctAftWqltSs = 0; + + let avgTpInflWqltBod = 0; + let avgTpInflWqltTp = 0; + + let avgInfoRnDay = 0; + + filteredData.forEach((item: FacilityWaterQltyProps) => { + const efflWqltBod = parseNumber(item.efflWqltBod); + const efflWqltTn = parseNumber(item.efflWqltTn); + const efflWqltTp = parseNumber(item.efflWqltTp); + const efflWqltCod = parseNumber(item.efflWqltCod); + const efflWqltSs = parseNumber(item.efflWqltSs); + + const inflAssctAftWqltBod = parseNumber(item.inflAssctAftWqltBod); + const inflAssctAftWqltTn = parseNumber(item.inflAssctAftWqltTn); + const inflAssctBfrWqltTp = parseNumber(item.inflAssctBfrWqltTp); + const inflAssctAftWqltToc = parseNumber(item.inflAssctAftWqltToc); + const inflAssctAftWqltSs = parseNumber(item.inflAssctAftWqltSs); + + + const tpInflWqltBod = parseNumber(item.tpInflWqltBod); + const tpInflWqltTp = parseNumber(item.tpInflWqltTp); + + const infoRnDay = parseNumber(item.infoRnDay); + + maxEfflWqltBod = Math.max(maxEfflWqltBod, efflWqltBod); + maxEfflWqltTn = Math.max(maxEfflWqltTn, efflWqltTn); + maxEfflWqltTp = Math.max(maxEfflWqltTp, efflWqltTp); + maxefflWqltCod = Math.max(maxefflWqltCod, efflWqltCod); + maxEfflWqltSs = Math.max(maxEfflWqltSs, efflWqltSs); + + maxInflAssctAftWqltBod = Math.max(maxInflAssctAftWqltBod, inflAssctAftWqltBod); + maxInflAssctAftWqltTn = Math.max(maxInflAssctAftWqltTn, inflAssctAftWqltTn); + maxInflAssctBfrWqltTp = Math.max(maxInflAssctBfrWqltTp, inflAssctBfrWqltTp); + maxInflAssctAftWqltToc = Math.max(maxInflAssctAftWqltToc, inflAssctAftWqltToc); + maxInflAssctAftWqltSs = Math.max(maxInflAssctAftWqltSs, inflAssctAftWqltSs); + + maxTpInflWqltBod = Math.max(maxTpInflWqltBod, tpInflWqltBod); + maxTpInflWqltTp = Math.max(maxTpInflWqltTp, tpInflWqltTp); + + maxInfoRnDay = Math.max(maxInfoRnDay, infoRnDay); + + minEfflWqltBod = Math.min(minEfflWqltBod, efflWqltBod); + minEfflWqltTn = Math.min(minEfflWqltTn, efflWqltTn); + minEfflWqltTp = Math.min(minEfflWqltTp, efflWqltTp); + minefflWqltCod = Math.min(minefflWqltCod, efflWqltCod); + minEfflWqltSs = Math.min(minEfflWqltSs, efflWqltSs); + + minInflAssctAftWqltBod = Math.min(minInflAssctAftWqltBod, inflAssctAftWqltBod); + minInflAssctAftWqltTn = Math.min(minInflAssctAftWqltTn, inflAssctAftWqltTn); + minInflAssctBfrWqltTp = Math.min(minInflAssctBfrWqltTp, inflAssctBfrWqltTp); + minInflAssctAftWqltToc = Math.min(minInflAssctAftWqltToc, inflAssctAftWqltToc); + minInflAssctAftWqltSs = Math.min(minInflAssctAftWqltSs, inflAssctAftWqltSs); + + minTpInflWqltBod = Math.min(minTpInflWqltBod, tpInflWqltBod); + minTpInflWqltTp = Math.min(minTpInflWqltTp, tpInflWqltTp); + + minInfoRnDay = Math.min(minInfoRnDay, infoRnDay); + + avgEfflWqltBod += efflWqltBod; + avgEfflWqltTn += efflWqltTn; + avgEfflWqltTp += efflWqltTp; + avgefflWqltCod += efflWqltCod; + avgEfflWqltSs += efflWqltSs; + + avgInflAssctAftWqltBod += inflAssctAftWqltBod; + avgInflAssctAftWqltTn += inflAssctAftWqltTn; + avgInflAssctBfrWqltTp += inflAssctBfrWqltTp; + avgInflAssctAftWqltToc += inflAssctAftWqltToc; + avgInflAssctAftWqltSs += inflAssctAftWqltSs; + + avgTpInflWqltBod += tpInflWqltBod; + avgTpInflWqltTp += tpInflWqltTp; + + avgInfoRnDay += infoRnDay; + }); + + const newFilteredData = [ + { + msrDt: '평균', + efflWqltBod: filteredData.length==0?'0.0':(Math.round(avgEfflWqltBod / filteredData.length * 10) / 10).toFixed(1), + efflWqltCod: filteredData.length==0?'0.0':(Math.round(avgefflWqltCod / filteredData.length * 10) / 10).toFixed(1), + efflWqltSs: filteredData.length==0?'0.0':(Math.round(avgEfflWqltSs / filteredData.length * 10) / 10).toFixed(1), + efflWqltTn: filteredData.length==0?'0.000':(Math.round(avgEfflWqltTn / filteredData.length * 1000) / 1000).toFixed(3), + efflWqltTp: filteredData.length==0?'0.000':(Math.round(avgEfflWqltTp / filteredData.length * 1000) / 1000).toFixed(3), + inflAssctAftWqltBod: filteredData.length==0?'0.0':(Math.round(avgInflAssctAftWqltBod / filteredData.length * 10) / 10).toFixed(1), + inflAssctAftWqltTn: filteredData.length==0?'0.000':(Math.round(avgInflAssctAftWqltTn / filteredData.length * 1000) / 1000).toFixed(3), + inflAssctBfrWqltTp: filteredData.length==0?'0.000':(Math.round(avgInflAssctBfrWqltTp / filteredData.length * 1000) / 1000).toFixed(3), + inflAssctAftWqltToc: filteredData.length==0?'0.0':(Math.round(avgInflAssctAftWqltToc / filteredData.length * 10) / 10).toFixed(1), + inflAssctAftWqltSs: filteredData.length==0?'0.0':(Math.round(avgInflAssctAftWqltSs / filteredData.length * 10) / 10).toFixed(1), + bscFctCd: "", + bscFctNm: "", + lclgvrnmntNm: "", + sidoNm: "", + sggNm: "", + addr: "", + fctCpc: 0, + infoRnDay: filteredData.length==0?'0.0':(Math.round(avgInfoRnDay / filteredData.length * 10) / 10).toFixed(1), + tpInflWqltBod: filteredData.length==0?'0.0':(Math.round(avgTpInflWqltBod / filteredData.length * 10) / 10).toFixed(1), + tpInflWqltTp: filteredData.length==0?'0.000':(Math.round(avgTpInflWqltTp / filteredData.length * 1000) / 1000).toFixed(3) + }, + { + msrDt : '최대', + efflWqltBod : Math.round(maxEfflWqltBod * 10) / 10?(Math.round(maxEfflWqltBod * 10) / 10).toFixed(1):'0.0', + efflWqltCod : Math.round(maxefflWqltCod * 10) / 10?(Math.round(maxefflWqltCod * 10) / 10).toFixed(1):'0.0', + efflWqltSs : Math.round(maxEfflWqltSs * 10) / 10?(Math.round(maxEfflWqltSs * 10) / 10).toFixed(1):'0.0', + efflWqltTn : Math.round(maxEfflWqltTn * 1000) / 1000?(Math.round(maxEfflWqltTn * 1000) / 1000).toFixed(3):'0.000', + efflWqltTp : Math.round(maxEfflWqltTp * 1000) / 1000?(Math.round(maxEfflWqltTp * 1000) / 1000).toFixed(3):'0.000', + inflAssctAftWqltBod : Math.round(maxInflAssctAftWqltBod * 10) / 10?(Math.round(maxInflAssctAftWqltBod * 10) / 10).toFixed(1):'0.0', + inflAssctAftWqltTn : Math.round(maxInflAssctAftWqltTn * 1000) / 1000?(Math.round(maxInflAssctAftWqltTn * 1000) / 1000).toFixed(3):'0.000', + inflAssctBfrWqltTp : Math.round(maxInflAssctBfrWqltTp * 1000) / 1000?(Math.round(maxInflAssctBfrWqltTp * 1000) / 1000).toFixed(3):'0.000', + inflAssctAftWqltToc : Math.round(maxInflAssctAftWqltToc * 10) / 10?(Math.round(maxInflAssctAftWqltToc * 10) / 10).toFixed(1):'0.0', + inflAssctAftWqltSs : Math.round(maxInflAssctAftWqltSs * 10) / 10?(Math.round(maxInflAssctAftWqltSs * 10) / 10).toFixed(1):'0.0', + bscFctCd: "", + bscFctNm: "", + lclgvrnmntNm: "", + sidoNm: "", + sggNm: "", + addr: "", + fctCpc: 0, + infoRnDay: 0, + tpInflWqltBod: Math.round(maxTpInflWqltBod * 10) / 10?(Math.round(maxTpInflWqltBod * 10) / 10).toFixed(1):'0.0', + tpInflWqltTp: Math.round(maxTpInflWqltTp * 1000) / 1000?(Math.round(maxTpInflWqltTp * 1000) / 1000).toFixed(3):'0.000' + }, + { + msrDt : '최소', + efflWqltBod : Math.round(minEfflWqltBod * 10) / 10?(Math.round(minEfflWqltBod?minEfflWqltBod:0 * 10) / 10).toFixed(1) : '0.0', + efflWqltCod : Math.round(minefflWqltCod * 10) / 10?(Math.round(minefflWqltCod?minefflWqltCod:0 * 10) / 10).toFixed(1) : '0.0', + efflWqltSs : Math.round(minEfflWqltSs * 10) / 10?(Math.round(minEfflWqltSs * 10) / 10).toFixed(1) : '0.0', + efflWqltTn : Math.round(minEfflWqltTn * 1000) / 1000?(Math.round(minEfflWqltTn * 1000) / 1000).toFixed(3) : '0.000', + efflWqltTp : Math.round(minEfflWqltTp * 1000) / 1000?(Math.round(minEfflWqltTp * 1000) / 1000).toFixed(3) : '0.000', + inflAssctAftWqltBod : Math.round(minInflAssctAftWqltBod * 10) / 10?(Math.round(minInflAssctAftWqltBod * 10) / 10).toFixed(1) : '0.0', + inflAssctAftWqltTn : Math.round(minInflAssctAftWqltTn * 1000) / 1000?(Math.round(minInflAssctAftWqltTn * 1000) / 1000).toFixed(3) : '0.000', + inflAssctBfrWqltTp : Math.round(minInflAssctBfrWqltTp * 1000) / 1000?(Math.round(minInflAssctBfrWqltTp * 1000) / 1000).toFixed(3) : '0.000', + inflAssctAftWqltToc : Math.round(minInflAssctAftWqltToc * 10) / 10?(Math.round(minInflAssctAftWqltToc * 10) / 10).toFixed(1) : '0.0', + inflAssctAftWqltSs : Math.round(minInflAssctAftWqltSs * 10) / 10?(Math.round(minInflAssctAftWqltSs * 10) / 10).toFixed(1) : '0.0', + bscFctCd: "", + bscFctNm: "", + lclgvrnmntNm: "", + sidoNm: "", + sggNm: "", + addr: "", + fctCpc: 0, + infoRnDay: 0, + tpInflWqltBod: Math.round(minTpInflWqltBod * 10) / 10?'0.0':(Math.round(minTpInflWqltBod * 10) / 10).toFixed(1), + tpInflWqltTp: Math.round(minTpInflWqltTp * 1000) / 1000?'0.000':(Math.round(minTpInflWqltTp * 1000) / 1000).toFixed(3) + }, + ...filteredData + ]; + return newFilteredData; + } + + // 날짜 필터링 관련 상태 + const [copyYearList, setCopyYearList] = useState<FacilityWaterQltyProps[]>([]); + const [chongInWaterQltyYearList, setChongInWaterQltyYearList] = useState<FacilityWaterQltyProps[]>([]); + + useEffect(() => { + searchFacilityWaterQltyListHist(searchYear, facilityCd); + }, [searchYear, facilityCd, searchFacilityWaterQltyListHist]); + + useEffect(() => { + const filteredYearData = setFilterAfterData(facilityWaterQltyYearList); + setCopyYearList(filteredYearData as FacilityWaterQltyProps[]); + setChongInWaterQltyYearList(filteredYearData as FacilityWaterQltyProps[]); + }, [facilityWaterQltyYearList]); + + const yesterDay = new Date(); + yesterDay.setDate(yesterDay.getDate() - 1); + const yesterDayStr = yesterDay.toISOString().split('T')[0]; + + const ref = useRef<ReturnType<FacilityWaterQltyProps>>({ + startDate: new Date(), + endDate: new Date(), + tabName: '', + filteredList: [], + }); + + const filterData = useCallback((returnType: ReturnType<FacilityWaterQltyProps>) => { + const filteredData = setFilterAfterData(returnType.filteredList); + setCopyYearList(filteredData as FacilityWaterQltyProps[]); + }, []); + + return ( + <> + <UITab tabList={tabList1} defaultValue="tab_num1"> + {/* 처리시설 수질현황 */} + <TabsContent value="tab_num1"> + <UITab tabList={tabList2} defaultValue="tab_term_year"> + <TabsContent value="tab_term_year"> + <FacilityTermModalHeader<FacilityWaterQltyProps> + searchList={facilityWaterQltyYearList} + fcltyCd={facilityCd} + fcltyName={fcltyName} + tabName={"tab_term_year"} + searchYear={searchYear} + ref={ref} + queryClick={filterData} + /> + <div className="overflow-y-auto h-[350px]"> + <UiTable + headName={undefined} + tableData={copyYearList} + headlist={upHeadListModalYear} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={() => {}} + className="h-[310px]" + boldArray={[0,1,2]} + > + <HeadMakeColSpan upHeadList={upHeadListModalYear} layoutNum={3} /> + </UiTable> + </div> + <div className="card-header"> + <h3 className="text-2xl font-medium text-label">수질 TMS</h3> + <h3 className="text-2xl font-medium text-label text-right">({msrmtDate?msrmtDate.substring(0,4)+'-'+msrmtDate.substring(4,6)+'-'+msrmtDate.substring(6,8):yesterDayStr})</h3> + </div> + <div className="overflow-y-auto h-[250px]"> + <UiTable + headName={undefined} + tableData={tmsList} + headlist={upHeadListModalTms} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={() => {}} + boldArray={[0,1,2]} + > + <HeadMakeColSpan upHeadList={upHeadListModalTms} layoutNum={4} /> + </UiTable> + {msrmtDate != yesterDayStr?.replaceAll('-','')?<h3 className="text-2xl text-left text-gray-500">※전날 데이터 결측으로 인해 가장 최근 데이터 표출함</h3> : ''} + </div> + </TabsContent> + + <TabsContent value="tab_term_summer"> + <FacilityTermModalHeader<FacilityWaterQltyProps> + searchList={facilityWaterQltyYearList} + fcltyCd={facilityCd} + fcltyName={fcltyName} + tabName="tab_term_summer" + searchYear={searchYear} + ref={ref} + queryClick={filterData} + /> + <div className="overflow-y-auto h-[550px]"> + <UiTable + headName={undefined} + tableData={copyYearList} + headlist={upHeadListModalYear} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={() => { } } + className="h-[500px]" + boldArray={[0,1,2]} + > + <HeadMakeColSpan upHeadList={upHeadListModalYear} layoutNum={3} /> + </UiTable> + </div> + </TabsContent> + + <TabsContent value="tab_term_winter"> + <FacilityTermModalHeader<FacilityWaterQltyProps> + searchList={facilityWaterQltyYearList} + fcltyCd={facilityCd} + fcltyName={fcltyName} + tabName="tab_term_winter" + searchYear={searchYear} + ref={ref} + queryClick={filterData} + /> + <div className="overflow-y-auto h-[550px]"> + <UiTable + headName={undefined} + tableData={copyYearList} + headlist={upHeadListModalYear} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={() => {}} + className="h-[500px]" + boldArray={[0,1,2]} + > + <HeadMakeColSpan upHeadList={upHeadListModalYear} layoutNum={3} /> + </UiTable> + </div> + </TabsContent> + + <TabsContent value="tab_term_chuncheon"> + <FacilityTermModalHeader<FacilityWaterQltyProps> + searchList={facilityWaterQltyYearList} + fcltyCd={facilityCd} + fcltyName={fcltyName} + tabName="tab_term_chuncheon" + searchYear={searchYear} + ref={ref} + queryClick={filterData} + /> + <div className="overflow-y-auto h-[550px]"> + <UiTable + headName={undefined} + tableData={copyYearList} + headlist={upHeadListModalYear} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={() => {}} + className="h-[500px]" + boldArray={[0,1,2]} + > + <HeadMakeColSpan upHeadList={upHeadListModalYear} layoutNum={3} /> + </UiTable> + </div> + </TabsContent> + + <TabsContent value="tab_term_rain"> + <FacilityTermModalHeader<FacilityWaterQltyProps> + searchList={facilityWaterQltyYearList} + fcltyCd={facilityCd} + fcltyName={fcltyName} + tabName="tab_term_rain" + searchYear={searchYear} + ref={ref} + queryClick={filterData} + /> + <div className="overflow-y-auto h-[550px]"> + <UiTable + headName={undefined} + tableData={copyYearList} + headlist={upHeadListModalYear} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={() => {}} + className="h-[500px]" + boldArray={[0,1,2]} + > + <HeadMakeColSpan upHeadList={upHeadListModalYear} layoutNum={3} /> + </UiTable> + </div> + </TabsContent> + </UITab> + </TabsContent> + + {/* 총인설비 수질현황 */} + <TabsContent value="tab_num2"> + <UITab tabList={tabList3} defaultValue="tab_term_year_chongin"> + <TabsContent value="tab_term_year_chongin"> + <FacilityTermModalHeader<FacilityWaterQltyProps> + searchList={chongInWaterQltyYearList} + fcltyCd={facilityCd} + fcltyName={fcltyName} + tabName="tab_term_year" + searchYear={searchYear} + ref={ref} + queryClick={filterData} + /> + <div className="overflow-y-auto h-[550px]"> + <UiTable + headName={undefined} + tableData={copyYearList} + headlist={upHeadListModalChongIn} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={() => {}} + className="h-[500px]" + boldArray={[0,1,2]} + > + <HeadMakeColSpan upHeadList={upHeadListModalChongIn} layoutNum={5} /> + </UiTable> + </div> + </TabsContent> + + <TabsContent value="tab_term_summer_chongin"> + <FacilityTermModalHeader<FacilityWaterQltyProps> + searchList={chongInWaterQltyYearList} + fcltyCd={facilityCd} + fcltyName={fcltyName} + tabName="tab_term_summer" + searchYear={searchYear} + ref={ref} + queryClick={filterData} + /> + <div className="overflow-y-auto h-[550px]"> + <UiTable + headName={undefined} + tableData={copyYearList} + headlist={upHeadListModalChongIn} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={() => {}} + className="h-[500px]" + boldArray={[0,1,2]} + > + <HeadMakeColSpan upHeadList={upHeadListModalChongIn} layoutNum={5} /> + </UiTable> + </div> + </TabsContent> + + <TabsContent value="tab_term_winter_chongin"> + <FacilityTermModalHeader<FacilityWaterQltyProps> + searchList={chongInWaterQltyYearList} + fcltyCd={facilityCd} + fcltyName={fcltyName} + tabName="tab_term_winter" + searchYear={searchYear} + ref={ref} + queryClick={filterData} + /> + <div className="overflow-y-auto h-[550px]"> + <UiTable + headName={undefined} + tableData={copyYearList} + headlist={upHeadListModalChongIn} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={() => {}} + className="h-[500px]" + boldArray={[0,1,2]} + > + <HeadMakeColSpan upHeadList={upHeadListModalChongIn} layoutNum={5} /> + </UiTable> + </div> + </TabsContent> + </UITab> + </TabsContent> + </UITab> + </> + ); +} \ No newline at end of file diff --git a/apps/fo/app/pages/facilityWaterQlty/page.tsx b/apps/fo/app/pages/facilityWaterQlty/page.tsx new file mode 100644 index 000000000..2c728f679 --- /dev/null +++ b/apps/fo/app/pages/facilityWaterQlty/page.tsx @@ -0,0 +1,208 @@ +"use client" + +import { useFoStore } from "@/app/store"; +import type { TableUpperProps } from "@/app/store/common"; +import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; +import ListDiv from "@common/business_components/ui/list_div"; +import { useCallback, useEffect, useRef, useState } from "react"; +import WaterQualityModal from "./modal/page"; +import type { FacilityWaterQltyProps } from "@/app/store/facilityWaterQlty"; + +export default function ProcessFacilitySearch() { + const { Common + , FacilityWaterQltyMain + , initializeCommonData + , searchFacilityWaterQltyList + } = useFoStore((state) => state) || { FacilityWaterQltyList: { facilityWaterQltyList: [], facilityWaterQltyCount: 0 } }; + + const { + isInit, + selectUpdownData, + selectOperationData, + selectSidoData, + selectSigunData, + selectRegionData, + selectUnitWaterShedData, + selectMiddleRegionData, + selectEnvPartData, + selectSearchYear, + btnClass + } = Common; + + const { + mainLabelArray, + upHeadList1, + upHeadList2, + upHeadList3, + facilityWaterQltyList, + facilityWaterQltyCount, + excelList + } = FacilityWaterQltyMain; + + const mainList: FacilityWaterQltyProps[] = facilityWaterQltyList || []; + + // 그리드 관련 + const [resetPage, setResetPage] = useState<boolean>(false); + const searchInputRef = useRef<HTMLDivElement & HTMLInputElement>(null); + const [widthSize, setWidthSize] = useState<string>("w-[120%]"); + const [upheadList, setUpheadList] = useState<TableUpperProps[]>(upHeadList1); + const [fcltyName, setFcltyName] = useState<string>(""); + const [operationValue, setOperationValue] = useState<string>("0"); + const [searchYearValue, setSearchYearValue] = useState<string>(selectSearchYear[0]?.val || "0"); + const [fcltCpct, setFcltCpct] = useState<string>("0"); + + // 모달 상태 추가 + const [selectedRow, setSelectedRow] = useState<number | null>(null); + const [fcltyNm, setFcltyNm] = useState<string>(""); + const [fcltyCd, setFcltyCd] = useState<string>(""); + const [modalYear, setModalYear] = useState<string>(""); + + const searchFcltyQltyList = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { + let nameCd, partStr; + switch (partValue) { + case 'R': + if (regionValue !== '0') { + if(unitWaterShedValue==='0') nameCd = regionValue; + else if (middleRegionValue==='0') nameCd = unitWaterShedValue; + else nameCd = middleRegionValue; + } + partStr = partValue + break; + default: + if(sidoValue !== '0') nameCd = sidoValue; + if(sigunValue !== '0') nameCd = sigunValue; + partStr = envPartValue !== '0' ? envPartValue:partValue; + break; + } + + if (partStr.length > 1 || fcltCpct !== '0' || operationValue!== '0' ||nameCd ||(fcltyName.trim() !== "" && fcltyName.trim() !== null)) { + searchFacilityWaterQltyList(pageNo, pageCnt, searchYearValue, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); + } else { + searchFacilityWaterQltyList(pageNo, pageCnt, searchYearValue); + } + }, [operationValue, fcltyName, searchFacilityWaterQltyList, searchYearValue, fcltCpct]); + + const resetVal = () => { + setWidthSize("w-[120%]"); + setUpheadList(upHeadList1) + // 상태값 설정 + setFcltCpct(selectUpdownData[0]?.val || "0"); + setOperationValue(selectOperationData[0]?.val || "0"); + setSearchYearValue(selectSearchYear[0]?.val || "0"); + // SearchInputSelect 초기화 + setFcltyName(""); + if (searchInputRef.current) { + const input = searchInputRef.current.querySelector('input'); + if (input) { + input.value = ""; + } + } + searchFacilityWaterQltyList(1, 10, selectSearchYear[0]?.val || "0"); + } + + // 셀 클릭 시 모달 표시 + const cellClick = (index: number) => { + const facility = facilityWaterQltyList[index]; + if (facility) { + setFcltyNm(facility.bscFctNm); + setFcltyCd(facility.bscFctCd); + setModalYear(searchYearValue); + setSelectedRow(index); // 클릭한 행의 index 저장 + } + } + + // 모달 닫기 + const closeModal = () => { + setSelectedRow(null); + } + const ref = useRef<ReturnType>({ + partValue: '', + sidoValue: '', + sigunValue: '', + regionValue: '', + unitWaterShedValue: '', + middleRegionValue: '', + envPartValue: '', + sidoText: '', + sigunText: '' + }); + + useEffect(() => { + if (!isInit) { + initializeCommonData(); + searchFacilityWaterQltyList(1, 10, selectSearchYear[0]?.val || "0"); + } + }, [isInit, initializeCommonData, searchFacilityWaterQltyList, selectSearchYear]); + + useEffect(() => { + if (excelList && excelList.length > 0) { + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: '시설별 수질현황', + sheetNameArray: ['시설별 수질현황'], + headerRange: 'A1:T1' + }); + } + }, [excelList]); + + const chkVal = useCallback((returntype:ReturnType) => { + setWidthSize(returntype.partValue=='A' ?"w-[120%]":"w-[130%]") + setUpheadList(returntype.partValue == 'R' ? upHeadList2 : returntype.partValue == 'G'?upHeadList3:upHeadList1); + setResetPage(true); + }, [upHeadList1, upHeadList2, upHeadList3]); + + const excelDownload = useCallback(() => { + searchFcltyQltyList(ref.current, 1, 10000); + }, [searchFcltyQltyList]); + + const handlePageChange = useCallback((page: number) => { + setResetPage(false); + searchFcltyQltyList(ref.current, page, 10); + }, [searchFcltyQltyList]); + + const total = facilityWaterQltyCount || 1; + console.log('total : ', total); + return ( + <MainDiv> + <Title title="시설별 수질현황" /> + <ContentsDiv> + <SearchBaseForm + leftChildren={<> + <SelectBox className="col-span-3" label={mainLabelArray[3] as string} selectArray={selectUpdownData} onSelectValue={(val) => setFcltCpct(val.toString())} value={fcltCpct} selectClass={undefined} /> + <SearchInput className="col-span-3" label={mainLabelArray[4] as string} textValue={fcltyName} setText={setFcltyName} /> + <SelectBox className="col-span-3" label={mainLabelArray[5] as string} selectArray={selectSearchYear} onSelectValue={(val) => setSearchYearValue(val.toString())} value={searchYearValue} selectClass={undefined} /> + <SelectBox className="col-span-3" label={mainLabelArray[6] as string} selectArray={selectOperationData} onSelectValue={(val) => setOperationValue(val.toString())} value={operationValue} selectClass={undefined} /> + </>} + rightChildren={undefined} + selectSidoData={selectSidoData} + selectSigunData={selectSigunData} + selectRegionData={selectRegionData} + selectUnitWaterShedData={selectUnitWaterShedData} + selectMiddleRegionData={selectMiddleRegionData} + selectEnvPartData={selectEnvPartData} + btnClass={btnClass} + queryClick={chkVal} + excelClick={excelDownload} + initClick={resetVal} + ref={ref} isAdmin={false} /> + <ListDiv> + <div className="h-full w-full overflow-x-scroll"> + <div className={widthSize}> + <UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"시설별 수질현황"} tableData={mainList} headlist={upheadList} pageSize={10} total={total<10?facilityWaterQltyList.length:total} resetPageNo={resetPage} onPageChange={handlePageChange} /> + </div> + </div> + </ListDiv> + </ContentsDiv> + {selectedRow !== null && ( + <UiModal + body={<WaterQualityModal fcltyName={fcltyNm} facilityCd={fcltyCd} searchYear={modalYear}></WaterQualityModal>} + bodyClass="sm:max-w-[90vw] w-[1200px] h-[920px]" + open={selectedRow !== null} + onOpenChange={(open) => !open && closeModal()} + noHeaderYn="Y" + noFooterYn="Y" + /> + )} + </MainDiv> + ); +} \ No newline at end of file diff --git a/apps/fo/app/pages/flowRate/modal/page.tsx b/apps/fo/app/pages/flowRate/modal/page.tsx new file mode 100644 index 000000000..665ade3b5 --- /dev/null +++ b/apps/fo/app/pages/flowRate/modal/page.tsx @@ -0,0 +1,238 @@ +"use client" +import FacilityTermModalHeader from "@/app/components/common/FacilityTermModalHeader"; +import { useFoStore } from "@/app/store"; +import type { FlowRateModalInterface } from "@/app/store/flowRate"; +import { UITab, UiTable } from "@common/business_components/ui"; +import { TabsContent } from "@common/components/ui"; +import { useCallback, useEffect, useRef, useState } from "react"; +import type { ReturnType } from "../../../components/common/FacilityTermModalHeader"; + +const tabList = [ + { value: 'tab_term_year', label: '연간' }, + { value: 'tab_term_summer', label: '하절기' }, + { value: 'tab_term_winter', label: '동절기' }, + { value: 'tab_term_chuncheon', label: '청천시' }, + { value: 'tab_term_rain', label: '강우시' } +]; + +export default function FlowRateModal(props: { fcltyName: string; facilityCd: string; searchYear: string }) { + // 그리드 관련 + const { FlowRateModal, searchFlowRateModalList } = useFoStore((state) => state); + const [copyYearList, setCopyYearList] = useState<FlowRateModalInterface[]>([]); + const [isLoading, setIsLoading] = useState(true); + + const { + modalFlowRateListYear, + upHeadListFlowRateModalYear, + } = FlowRateModal; + + const ref = useRef<ReturnType<FlowRateModalInterface>>({ + startDate: new Date(), + endDate: new Date(), + tabName: '', + filteredList: [], + }); + + const filterData = useCallback((returnType: ReturnType<FlowRateModalInterface>) => { + if (!returnType.filteredList) return; + const filteredData = setFilterAfterData(returnType.filteredList); + setCopyYearList(filteredData); + }, []); + + // 필터링 된 후 최대, 최소, 평균 값 계산 + const setFilterAfterData = (filteredData: FlowRateModalInterface[]) => { + if (!filteredData || filteredData.length === 0) return []; + + // 쉼표가 포함된 문자열을 숫자로 변환하는 함수 + const parseNumber = (value: string | number | null | undefined): number => { + if (value === null || value === undefined || value === '') return 0; + if (typeof value === 'number') return value; + return Number(value.replace(/,/g, '')); + }; + + let maxtotInflAmnt = 0; + let maxinflAmnt = 0; + let maxsumFlow = 0; + let maxreturnAmnt = 0; + let maxefflAmnt = 0; + + // 초기값 설정 + let mintotInflAmnt = parseNumber(filteredData[0]?.totInflAmnt); + let mininflAmnt = parseNumber(filteredData[0]?.inflAmnt); + let minsumFlow = parseNumber(filteredData[0]?.sumFlow); + let minreturnAmnt = parseNumber(filteredData[0]?.returnAmnt); + let minefflAmnt = parseNumber(filteredData[0]?.efflAmnt); + + let avgtotInflAmnt = 0; + let avginflAmnt = 0; + let avgsumFlow = 0; + let avgreturnAmnt = 0; + let avgefflAmnt = 0; + + filteredData.forEach((item: FlowRateModalInterface) => { + const totInflAmnt = parseNumber(item.totInflAmnt); + const inflAmnt = parseNumber(item.inflAmnt); + const sumFlow = parseNumber(item.sumFlow); + const returnAmnt = parseNumber(item.returnAmnt); + const efflAmnt = parseNumber(item.efflAmnt); + + maxtotInflAmnt = Math.max(maxtotInflAmnt, totInflAmnt); + maxinflAmnt = Math.max(maxinflAmnt, inflAmnt); + maxsumFlow = Math.max(maxsumFlow, sumFlow); + maxreturnAmnt = Math.max(maxreturnAmnt, returnAmnt); + maxefflAmnt = Math.max(maxefflAmnt, efflAmnt); + + mintotInflAmnt = Math.min(mintotInflAmnt, totInflAmnt); + mininflAmnt = Math.min(mininflAmnt, inflAmnt); + minsumFlow = Math.min(minsumFlow, sumFlow); + minreturnAmnt = Math.min(minreturnAmnt, returnAmnt); + minefflAmnt = Math.min(minefflAmnt, efflAmnt); + + avgtotInflAmnt += totInflAmnt; + avginflAmnt += inflAmnt; + avgsumFlow += sumFlow; + avgreturnAmnt += returnAmnt; + avgefflAmnt += efflAmnt; + }); + + const newFilteredData = [ + { + msrDt: '평균', + totInflAmnt: Math.round(avgtotInflAmnt / filteredData.length * 10) / 10, + inflAmnt: Math.round(avginflAmnt / filteredData.length * 10) / 10, + sumFlow: Math.round(avgsumFlow / filteredData.length * 10) / 10, + returnAmnt: Math.round(avgreturnAmnt / filteredData.length * 10) / 10, + efflAmnt: Math.round(avgefflAmnt / filteredData.length * 10) / 10, + }, + { + msrDt: '최대', + totInflAmnt: Math.round(maxtotInflAmnt * 10) / 10, + inflAmnt: Math.round(maxinflAmnt * 10) / 10, + sumFlow: Math.round(maxsumFlow * 10) / 10, + returnAmnt: Math.round(maxreturnAmnt * 10) / 10, + efflAmnt: Math.round(maxefflAmnt * 10) / 10, + }, + { + msrDt: '최소', + totInflAmnt: Math.round(mintotInflAmnt * 10) / 10, + inflAmnt: Math.round(mininflAmnt * 10) / 10, + sumFlow: Math.round(minsumFlow * 10) / 10, + returnAmnt: Math.round(minreturnAmnt * 10) / 10, + efflAmnt: Math.round(minefflAmnt * 10) / 10, + }, + ...filteredData + ]; + return newFilteredData; + } + + useEffect(() => { + const fetchData = async () => { + setIsLoading(true); + try { + await searchFlowRateModalList(props.facilityCd, props.searchYear); + } finally { + setIsLoading(false); + } + }; + fetchData(); + }, [props.facilityCd, props.searchYear, searchFlowRateModalList]); + + if (isLoading) { + return <div>로딩 중...</div>; + } + + return ( + <> + <UITab tabList={tabList} defaultValue="tab_term_year"> + <TabsContent value="tab_term_year"> + <FacilityTermModalHeader<FlowRateModalInterface> + searchList={modalFlowRateListYear} + fcltyCd={props.facilityCd} + fcltyName={props.fcltyName} + tabName={"tab_term_year"} + searchYear={props.searchYear} + ref={ref} + queryClick={filterData} + /> + <div className="h-[370px] overflow-y-auto overflow-x-hidden"> + <UiTable + headName="유량현황" + tableData={copyYearList} + headlist={upHeadListFlowRateModalYear} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={() => {}} + className="h-[370px]" + boldArray={[0,1,2]} + /> + </div> + </TabsContent> + <TabsContent value="tab_term_summer"> + <FacilityTermModalHeader<FlowRateModalInterface> + searchList={modalFlowRateListYear} + fcltyCd={props.facilityCd} + fcltyName={props.fcltyName} + tabName={"tab_term_summer"} + searchYear={props.searchYear} + ref={ref} + queryClick={filterData} + /> + <div className="h-[370px] overflow-y-auto overflow-x-hidden"> + <UiTable headName="유량현황" tableData={copyYearList} headlist={upHeadListFlowRateModalYear} pageSize={0} total={0} cellClick={undefined} onPageChange={() => {}} className="h-[370px]" boldArray={[0,1,2]}> + {null} + </UiTable> + </div> + </TabsContent> + <TabsContent value="tab_term_winter"> + <FacilityTermModalHeader<FlowRateModalInterface> + searchList={modalFlowRateListYear} + fcltyCd={props.facilityCd} + fcltyName={props.fcltyName} + tabName={"tab_term_winter"} + searchYear={props.searchYear} + ref={ref} + queryClick={filterData} + /> + <div className="h-[370px] overflow-y-auto overflow-x-hidden"> + <UiTable headName="유량현황" tableData={copyYearList} headlist={upHeadListFlowRateModalYear} pageSize={0} total={0} cellClick={undefined} onPageChange={() => {}} className="h-[370px]" boldArray={[0,1,2]}> + {null} + </UiTable> + </div> + </TabsContent> + <TabsContent value="tab_term_chuncheon"> + <FacilityTermModalHeader<FlowRateModalInterface> + searchList={modalFlowRateListYear} + fcltyCd={props.facilityCd} + fcltyName={props.fcltyName} + tabName={"tab_term_chuncheon"} + searchYear={props.searchYear} + ref={ref} + queryClick={filterData} + /> + <div className="h-[370px] overflow-y-auto overflow-x-hidden"> + <UiTable headName="유량현황" tableData={copyYearList} headlist={upHeadListFlowRateModalYear} pageSize={0} total={0} cellClick={undefined} onPageChange={() => {}} className="h-[370px]" boldArray={[0,1,2]}> + {null} + </UiTable> + </div> + </TabsContent> + <TabsContent value="tab_term_rain"> + <FacilityTermModalHeader<FlowRateModalInterface> + searchList={modalFlowRateListYear} + fcltyCd={props.facilityCd} + fcltyName={props.fcltyName} + tabName={"tab_term_rain"} + searchYear={props.searchYear} + ref={ref} + queryClick={filterData} + /> + <div className="h-[370px] overflow-y-auto overflow-x-hidden"> + <UiTable headName="유량현황" tableData={copyYearList} headlist={upHeadListFlowRateModalYear} pageSize={0} total={0} cellClick={undefined} onPageChange={() => {}} className="h-[370px]" boldArray={[0,1,2]}> + {null} + </UiTable> + </div> + </TabsContent> + </UITab> + </> + ); +} \ No newline at end of file diff --git a/apps/fo/app/pages/flowRate/page.tsx b/apps/fo/app/pages/flowRate/page.tsx new file mode 100644 index 000000000..3910944cf --- /dev/null +++ b/apps/fo/app/pages/flowRate/page.tsx @@ -0,0 +1,207 @@ +"use client" +import { useFoStore } from "@/app/store"; +import type { TableUpperProps } from "@/app/store/common"; +import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; +import ListDiv from "@common/business_components/ui/list_div"; +import { useCallback, useEffect, useRef, useState } from "react"; +import FlowRateModal from "./modal/page"; +import type { ExcelType } from "@/app/store/flowRate"; + +export default function ProcessFacilitySearch() { + const {Common + ,FlowRateSearch + ,FlowRateList + ,initializeCommonData + ,searchFlowRateList + } = useFoStore((state) => state); + + const searchInputRef = useRef<HTMLDivElement & HTMLInputElement>(null); + + const { + isInit, + selectUpdownData, + selectSearchYear, + selectOperationData, + selectSidoData, + selectSigunData, + selectRegionData, + selectUnitWaterShedData, + selectMiddleRegionData, + selectEnvPartData, + btnClass + } = Common; + + const { + flowRateSearchLabelArray + } = FlowRateSearch; + + // 그리드 관련 + const { + upHeadList1, + upHeadList2, + upHeadList3, + flowRateList, + flowRateCount, + excelList + } = FlowRateList; + + // 입력값 상태 관리 + const [fcltCpct, setFcltCpct] = useState<string>("0"); + const [fcltyName, setFcltyName] = useState<string>(""); + const [operationValue, setOperationValue] = useState<string>("0"); + const [searchYearValue, setSearchYearValue] = useState<string>(selectSearchYear[0]?.val || "0"); + const [widthSize, setWidthSize] = useState<string>("w-[120%]"); + const [upheadList, setUpheadList] = useState<TableUpperProps[]>(upHeadList1); + const [resetPage, setResetPage] = useState<boolean>(false); + const prevExcelListRef = useRef<ExcelType[] | null>(null); + + // 모달 상태 추가 + const [selectedRow, setSelectedRow] = useState<number | null>(null); + const [fcltyNm, setFcltyNm] = useState<string>(""); + const [fcltyCd, setFcltyCd] = useState<string>(""); + + const searchFlowRate = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { + let nameCd, partStr + switch (partValue) { + case 'R': + if (regionValue !== '0') { + if(unitWaterShedValue==='0') nameCd = regionValue; + else if (middleRegionValue==='0') nameCd = unitWaterShedValue; + else nameCd = middleRegionValue; + } + partStr = partValue + break; + default: + if(sidoValue !== '0') nameCd = sidoValue; + if(sigunValue !== '0') nameCd = sigunValue; + partStr = envPartValue !== '0' ? envPartValue:partValue; + break; + } + if (partStr.length > 1 || fcltCpct !== '0' || operationValue!== '0' ||nameCd ||(fcltyName.trim() !== "" && fcltyName.trim() !== null)) { + searchFlowRateList(pageNo, pageCnt, searchYearValue, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); + } else { + searchFlowRateList(pageNo, pageCnt, searchYearValue); + } + }, [operationValue, fcltyName, searchFlowRateList, searchYearValue, fcltCpct]); + + const resetVal = () => { + setWidthSize("w-[120%]"); + setUpheadList(upHeadList1) + // 상태값 설정 + setFcltCpct(selectUpdownData[0]?.val || "0"); + setOperationValue(selectOperationData[0]?.val || "0"); + setSearchYearValue(selectSearchYear[0]?.val || "0"); + // SearchInputSelect 초기화 + setFcltyName(""); + if (searchInputRef.current) { + const input = searchInputRef.current.querySelector('input'); + if (input) { + input.value = ""; + } + } + searchFlowRateList(1, 10, selectSearchYear[0]?.val || "0"); + } + + // 셀 클릭 시 모달 표시 + const cellClick = (index: number) => { + if (flowRateList[index]) { + setFcltyNm(flowRateList[index].bscFctNm); + setFcltyCd(flowRateList[index].bscFctCd); + setSelectedRow(index); // 클릭한 행의 index 저장 + } + }; + + // 페이지 네비게이션션 + const handlePageChange = useCallback((page: number) => { + setResetPage(false); + searchFlowRate(ref.current, page, 10); + }, [searchFlowRate]); + + // 모달 닫기 + const closeModal = () => { + setSelectedRow(null); + }; + + // 시도 데이터 초기화 + useEffect(() => { + if(!isInit) { + initializeCommonData(); + searchFlowRateList(1, 10, selectSearchYear[0]?.val || "0"); + } + }, [isInit, initializeCommonData, searchFlowRateList, selectSearchYear]); + + useEffect(() => { + if (excelList && excelList.length > 0) { + downloadExcel({ data: JSON.parse(JSON.stringify(excelList)), fileName: '시설별 유량현황', sheetNameArray: ['시설별 유량현황'], headerRange: 'A1:O1' }); + } else if (prevExcelListRef.current && prevExcelListRef.current.length > 0) { + alert('다운받을 데이터가 없습니다.'); + } + prevExcelListRef.current = excelList; + }, [excelList]); + + const ref = useRef<ReturnType>({ + partValue: '', + sidoValue: '', + sigunValue: '', + regionValue: '', + unitWaterShedValue: '', + middleRegionValue: '', + envPartValue: '', + sidoText: '', + sigunText: '' + }); + + const chkVal = useCallback((returntype:ReturnType) => { + setWidthSize(returntype.partValue=='A' ?"w-[120%]":"w-[130%]") + setUpheadList(returntype.partValue == 'R' ? upHeadList2 : returntype.partValue == 'G'?upHeadList3:upHeadList1); + setResetPage(true); + }, [upHeadList1, upHeadList2, upHeadList3]); + + const excelDownload = useCallback(() => { + searchFlowRate(ref.current, 1, 10000); + }, [searchFlowRate]); + + const total = flowRateCount; + + return ( + <MainDiv> + <Title title="시설별 유량현황" /> + <ContentsDiv> + <SearchBaseForm + leftChildren={<> + <SelectBox className="col-span-3" label={flowRateSearchLabelArray[3] as string} selectArray={selectUpdownData} onSelectValue={(val) => setFcltCpct(val.toString())} value={fcltCpct} selectClass={undefined} /> + <SearchInput className="col-span-3" label={flowRateSearchLabelArray[4] as string} textValue={fcltyName} setText={setFcltyName} /> + <SelectBox className="col-span-3" label={flowRateSearchLabelArray[5] as string} selectArray={selectSearchYear} onSelectValue={(val) => setSearchYearValue(val.toString())} value={searchYearValue} selectClass={undefined} /> + <SelectBox className="col-span-3" label={flowRateSearchLabelArray[6] as string} selectArray={selectOperationData} onSelectValue={(val) => setOperationValue(val.toString())} value={operationValue} selectClass={undefined} /> + </>} + rightChildren={undefined} + selectSidoData={selectSidoData} + selectSigunData={selectSigunData} + selectRegionData={selectRegionData} + selectUnitWaterShedData={selectUnitWaterShedData} + selectMiddleRegionData={selectMiddleRegionData} + selectEnvPartData={selectEnvPartData} + btnClass={btnClass} + queryClick={chkVal} + excelClick={excelDownload} + initClick={resetVal} + ref={ref} isAdmin={false} /> + <ListDiv> + <div className="h-full w-full overflow-x-scroll"> + <div className={widthSize}> + <UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"시설별 유량현황"} tableData={flowRateList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} /> + </div> + </div> + </ListDiv> + </ContentsDiv> + {selectedRow !== null && ( + <UiModal + body={<FlowRateModal fcltyName={fcltyNm} facilityCd={fcltyCd} searchYear={searchYearValue}></FlowRateModal>} + bodyClass="sm:max-w-[90vw] w-[1050px] h-[700px]" + open={selectedRow !== null} + onOpenChange={(open: boolean) => !open && closeModal()} + /> + )} + </MainDiv> + ); +} diff --git a/apps/fo/app/pages/map/page.tsx b/apps/fo/app/pages/map/page.tsx new file mode 100644 index 000000000..cbbe0dd11 --- /dev/null +++ b/apps/fo/app/pages/map/page.tsx @@ -0,0 +1,145 @@ +"use client"; + +import Gis from "@common/business_components/ui/map/Gis"; +import GisApp from "@common/business_components/ui/map/lib/gis.core"; +import { useEffect, useRef, useState } from "react"; + +interface FeatureData { + fid?: string; + ftrIdn?: string; + id?: string; + getGeometry?: () => { getExtent: () => number[] }; + setStyle?: () => void; +} + +interface MapInstance { + getLayers: () => { getArray: () => Array<{ getSource?: () => { getFeatureById?: (id: string) => FeatureData | null } }> }; + getView: () => { fit: (extent: number[], options: object) => void }; +} + +const Map = () => { + const [treeData, setTreeData] = useState([]); // 초기값을 객체 또는 null로 설정 + const gisMaps = useRef<MapInstance | null>(null); + const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태 + const [isSearchModalOpen, setIsSearchModalOpen] = useState(false); // SearchModal 열림 상태 + const [featureData, setFeatureData] = useState<FeatureData | null>(null); // 선택된 피쳐 데이터 + + const fetchData = async () => { + try { + const API_URL = `${process.env.NEXT_PUBLIC_SEWERAGE_API_URL}/v1/map` + const reqUrl = `${API_URL}/lyrStngs/FO_NETWORK`; + const response = await fetch(reqUrl, { + method: "GET", + headers: { + accept: "application/json", + } + }); + + if (!response.ok) { + throw new Error(`HTTP 오류! 상태: ${response.status}`); + } + + const data = await response.json(); // 여기서 json 파싱 + setTreeData(data); // 데이터 설정 + } catch (error) { + console.error("데이터 불러오기 실패:", error); + } + }; + + // 컴포넌트 마운트 시 1회 실행 + useEffect(() => { + fetchData(); + }, []); + + // SearchModal, GisContent 등에서 호출 + const onFeatureSelect = (data: FeatureData) => { + const map = gisMaps.current; + if (!map) { + console.warn("지도가 초기화되지 않았습니다."); + return; + } + + // 항상 같은 select 객체 사용 + const select = (GisApp.Module.select as unknown) as { resetSelectedFeature: () => void; selectFeature: (feature: FeatureData, selected: boolean) => void } | undefined; + if (!select) return; + + // 1. 기존 선택 초기화 + select.resetSelectedFeature(); + + // 2. data가 OpenLayers Feature 인스턴스인지 확인 + let foundFeature: FeatureData | null = null; + if ( + data && + typeof data.getGeometry === "function" && + typeof data.setStyle === "function" + ) { + // 이미 Feature 인스턴스라면 그대로 사용 + foundFeature = data; + } else { + // 아니면 featureId로 맵에서 Feature 인스턴스를 찾아서 사용 + const featureId = data.fid || data.ftrIdn || data.id; + map + .getLayers() + .getArray() + .forEach((layer) => { + const source = layer.getSource?.(); + if (source?.getFeatureById) { + const feature = source.getFeatureById(String(featureId).trim()); + if (feature) foundFeature = feature; + } + }); + } + + // 3. 피처 선택 + if (foundFeature && foundFeature.getGeometry) { + const geometry = foundFeature.getGeometry(); + if (geometry) { + const extent = geometry.getExtent(); + + map.getView().fit(extent, { + duration: 300, + padding: [50, 50, 50, 50], + maxZoom: 16, + constrainResolution: true, + nearest: true, + }); + } + select.selectFeature(foundFeature, true); + } else { + console.warn("OpenLayers Feature를 찾을 수 없습니다:", data); + } + + setFeatureData(data); + setIsOpen(true); + setIsSearchModalOpen(false); + }; + + // onCheckedLayersChange handler + const handleCheckedLayersChange = (checkedIds: string[], checkedNodesData: unknown[]) => { + // Handle checked layers change if needed + console.log('Checked layers changed:', checkedIds, checkedNodesData); + }; + + return ( + <div className="bg-container"> + <Gis + treeData={treeData} + isSearch={false} + gisMaps={gisMaps} + isMiniMap={true} + searchView={null} + detailView={null} + onFeatureSelect={onFeatureSelect} + setIsOpen={setIsOpen} + setFeatureData={setFeatureData} + featureData={featureData} + setIsSearchModalOpen={setIsSearchModalOpen} + isOpen={isOpen} + isSearchModalOpen={isSearchModalOpen} + onCheckedLayersChange={handleCheckedLayersChange} + /> + </div> + ); +}; + +export default Map; diff --git a/apps/fo/app/pages/planSewage/page.tsx b/apps/fo/app/pages/planSewage/page.tsx new file mode 100644 index 000000000..8d7de5d80 --- /dev/null +++ b/apps/fo/app/pages/planSewage/page.tsx @@ -0,0 +1,197 @@ +"use client" +import { useFoStore } from "@/app/store"; +import type { TableUpperProps } from "@/app/store/common"; +import { downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiTable, type ReturnType } from "@common/business_components"; +import ListDiv from "@common/business_components/ui/list_div"; +import { useCallback, useEffect, useRef, useState } from "react"; + +export default function PlanSewage() { + const {Common + ,PlanSewage + ,PlanSewageSearch + ,initializeCommonData + ,searchPlanSewageList + } = useFoStore((state) => state) || { processAreaList: { processAreaList: [] }}; + + const { + isInit, + selectUpdownData, + selectOperationData, + selectSidoData, + selectSigunData, + selectRegionData, + selectUnitWaterShedData, + selectMiddleRegionData, + selectEnvPartData, + selectSearchYear, + btnClass + } = Common; + + const { + labelArray, + } = PlanSewageSearch; + + const { + upHeadList1, + upHeadList2, + upHeadList3, + planSewageList, + planSewageCount, + excelList + } = PlanSewage; + + const ref = useRef<ReturnType>({ + partValue: '', + sidoValue: '', + sigunValue: '', + regionValue: '', + unitWaterShedValue: '', + middleRegionValue: '', + envPartValue: '', + sidoText: '', + sigunText: '' + }); + + // 그리드 관련 + const searchInputRef = useRef<HTMLDivElement & HTMLInputElement>(null); + + // 모달 상태 추가 + + // 초기화 변수 + const [resetPage, setResetPage] = useState<boolean>(false); + // 표 너비 + const [widthSize, setWidthSize] = useState<string>("w-[120%]"); + // 구분별 그리드 헤더 + const [upheadList, setUpheadList] = useState<TableUpperProps[]>(upHeadList1); + // 용량별 + const [fcltCpct, setFcltCpct] = useState<string>("0"); + // 시설명 + const [fcltyName, setFcltyName] = useState<string>(""); + // 시설상태 + const [operationValue, setOperationValue] = useState<string>("0"); + // 조회기간 + const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || "0"); + + /** + * 페이지 함수 + */ + // 초기화 + const resetVal = () => { + setWidthSize("w-[120%]"); + setUpheadList(upHeadList1); + // 상태값 설정 + setFcltCpct(selectUpdownData[0]?.val || "0"); + setOperationValue(selectOperationData[0]?.val || "0"); + setSearchYear(selectSearchYear[0]?.val || "0"); + // SearchInputSelect 초기화 + setFcltyName(""); + if (searchInputRef.current) { + const input = searchInputRef.current.querySelector('input'); + if (input) { + input.value = ""; + } + } + } + + /** + * useEffect + */ + useEffect(() => { + if (!isInit) { + initializeCommonData(); + searchPlanSewageList(1, 10, searchYear, ref.current.partValue); + } + }, [isInit, initializeCommonData, searchYear, searchPlanSewageList]); + + useEffect(() => { + console.log('excelList' , excelList); + if (excelList && excelList.length > 0) { + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: '계획하수량 산정지표 현황', + sheetNameArray: ['계획하수량 산정지표 현황'], + headerRange: 'A1:M1' + }); + } + }, [excelList]); + + /** + * 콜백함수 + */ + // 조회 + const searchPlanSewage = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { + let nameCd, partStr + switch (partValue) { + case 'R': + if (regionValue !== '0') { + if(unitWaterShedValue==='0') nameCd = regionValue; + else if (middleRegionValue==='0') nameCd = unitWaterShedValue; + else nameCd = middleRegionValue; + } + partStr = partValue + break; + default: + if(sidoValue !== '0') nameCd = sidoValue; + if(sigunValue !== '0') nameCd = sigunValue; + partStr = envPartValue !== '0' ? envPartValue:partValue; + break; + } + if (partStr.length > 1 || fcltCpct !== '0' || operationValue!== '0' ||nameCd ||(fcltyName.trim() !== "" && fcltyName.trim() !== null)) { + searchPlanSewageList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); + } else { + searchPlanSewageList(pageNo, pageCnt, searchYear, partValue); + } + }, [operationValue, fcltyName, searchPlanSewageList, searchYear, fcltCpct]); + + const chkVal = useCallback((returntype:ReturnType) => { + setWidthSize(returntype.partValue=='A' ?"w-[120%]":"w-[130%]") + setUpheadList(returntype.partValue == 'R' ? upHeadList2 : returntype.partValue == 'G'?upHeadList3:upHeadList1); + setResetPage(true); + }, [upHeadList1, upHeadList2, upHeadList3]); + + // 엑셀다운로드 + const excelDownload = useCallback((searchReturn: ReturnType) => { + searchPlanSewage(searchReturn, 1, 10000); + }, [searchPlanSewage]); + + // 페이지 변경 + const handlePageChange = useCallback((page: number) => { + setResetPage(false); + searchPlanSewage(ref.current, page, 10); + }, [searchPlanSewage]); + + const mainList = planSewageList || []; + const total = planSewageCount || 0; + + return ( + <MainDiv> + <Title title="계획하수량 산정지표 현황" /> + <SearchBaseForm + leftChildren={<> + <SelectBox className="col-span-3" label={labelArray[3] as string} selectArray={selectUpdownData} onSelectValue={(val) => setFcltCpct(val.toString())} value={fcltCpct} selectClass={undefined} /> + <SearchInput className={"col-span-3"} label={labelArray[4] as string} textValue={fcltyName} setText={setFcltyName} /> + <SelectBox className="col-span-3" label={labelArray[5] as string} selectArray={selectSearchYear} onSelectValue={(val) => setSearchYear(val.toString())} value={searchYear} selectClass={undefined} /> + <SelectBox className="col-span-3" label={labelArray[6] as string} selectArray={selectOperationData} onSelectValue={(val) => setOperationValue(val.toString())} value={operationValue} selectClass={undefined} /> + </>} + rightChildren={undefined} + selectSidoData={selectSidoData} + selectSigunData={selectSigunData} + selectRegionData={selectRegionData} + selectUnitWaterShedData={selectUnitWaterShedData} + selectMiddleRegionData={selectMiddleRegionData} + selectEnvPartData={selectEnvPartData} + btnClass={btnClass} + queryClick={chkVal} + excelClick={excelDownload} + initClick={resetVal} + ref={ref} isAdmin={false}/> + <ListDiv> + <div className="h-full w-full overflow-x-scroll"> + <div className={widthSize}> + <UiTable cellClick={ undefined } headName={"계획하수량 산정지표 현황"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} /> + </div> + </div> + </ListDiv> + </MainDiv> + ); +} \ No newline at end of file diff --git a/apps/fo/app/pages/processArea/HeadMakeColSpan.tsx b/apps/fo/app/pages/processArea/HeadMakeColSpan.tsx new file mode 100644 index 000000000..ffd556b2e --- /dev/null +++ b/apps/fo/app/pages/processArea/HeadMakeColSpan.tsx @@ -0,0 +1,87 @@ +import { TableHead, TableRow } from "@common/components/ui"; +import type { TableUpperProps } from "../../store/dashboard"; + +const HeadMakeColSpan = ({ upHeadList, layoutNum }: { upHeadList: TableUpperProps[], layoutNum: number }) => { + return ( + layoutNum === 0 ? ( + <> + <TableRow className="bg-gray-50">{upHeadList.map((head: TableUpperProps) => + (head.id === 'trtFrfNm' ? <TableHead className="w-1/12" rowSpan={3} key={head.id}>{head.title}</TableHead> : + head.id === 'laeNm' ? <TableHead className="w-1/12" rowSpan={3} key={head.id}>{head.title}</TableHead> : + head.id == 'fctCpc' || head.id == 'planInputWaterQlty' || head.id == 'designInputWaterQlty' ? <TableHead rowSpan={3} className="w-40" style={{ whiteSpace: 'pre-line' }} key={head.id}>{head.title}</TableHead> : + head.id === 'trstOprEtpNm' ? <TableHead className="w-1/15" rowSpan={3} key={head.id}>{head.title}</TableHead> : + head.upName === 'upChangeRe' && head.upSequnce === 1 ? <TableHead className="bg-gray-50" style={{ whiteSpace: 'pre-line' }} key={head.id} rowSpan={2} colSpan={2}>{'행정구역'}</TableHead> : + head.upName === 'upChangeRe3' && head.upSequnce === 1 ? <TableHead className="bg-gray-50" style={{ whiteSpace: 'pre-line' }} key={head.id} rowSpan={2} colSpan={6}>{'증설계획'}</TableHead> : + head.upName === 'upChangeRe4' && head.upSequnce === 1 ? <TableHead className="bg-gray-50" style={{ whiteSpace: 'pre-line' }} key={head.id} rowSpan={1} colSpan={19}>{'시설계획'}</TableHead> : + !head.upName ? <TableHead rowSpan={3} className="w-1/20 bg-gray-20" style={{ whiteSpace: 'pre-line' }} key={head.id}>{head.title}</TableHead> : null))} + </TableRow> + <TableRow className="bg-gray-50"> + {upHeadList.map((head: TableUpperProps) => ( + head.upName === 'upChangeRe4' && head.upSequnce === 1 ? <TableHead className="bg-gray-50" style={{ whiteSpace: 'pre-line' }} key={head.id} rowSpan={1} colSpan={6}>{'증설계획(m³/일)'}</TableHead> : + head.upName === 'upChangeRe5' && head.upSequnce === 1 ? <TableHead className="bg-gray-50" style={{ whiteSpace: 'pre-line' }} key={head.id} rowSpan={1} colSpan={6}>{'처리인구(인)'}</TableHead> : + head.upName === 'upChangeRe6' && head.upSequnce === 1 ? <TableHead className="bg-gray-50" style={{ whiteSpace: 'pre-line' }} key={head.id} rowSpan={1} colSpan={7}>{'처리구역(k㎡)'}</TableHead> : + null + ))} + </TableRow> + <TableRow className="bg-gray-50"> + {upHeadList.map((head: TableUpperProps) => { + if (head.upName === 'upChangeRe' || head.upName === 'upChangeRe1' || head.upName === 'upChangeRe2' || head.upName === 'upChangeRe3' || head.upName === 'upChangeRe4' || head.upName === 'upChangeRe5' || head.upName === 'upChangeRe6') { + return <TableHead key={head.id} style={{ whiteSpace: 'pre-line' }} className="w-40 bg-gray-50">{head.title}</TableHead>; + } + })} + </TableRow> + </> + ) : layoutNum === 1 ? ( + <> + <TableRow className="bg-gray-50">{upHeadList.map((head: TableUpperProps) => + (head.id === 'trtFrfNm' ? <TableHead className="w-1/12" rowSpan={3} key={head.id}>{head.title}</TableHead> : + head.id === 'laeNm' ? <TableHead className="w-1/12" rowSpan={3} key={head.id}>{head.title}</TableHead> : + head.id == 'fctCpc' || head.id == 'planInputWaterQlty' || head.id == 'designInputWaterQlty' ? <TableHead rowSpan={3} className="w-40" style={{ whiteSpace: 'pre-line' }} key={head.id}>{head.title}</TableHead> : + head.id === 'trstOprEtpNm' ? <TableHead className="w-1/15" rowSpan={3} key={head.id}>{head.title}</TableHead> : + head.upName === 'upChangeRe' && head.upSequnce === 1 ? <TableHead className="w-75 bg-gray-50" style={{ whiteSpace: 'pre-line' }} key={head.id} rowSpan={2} colSpan={3}>{'유역'}</TableHead> : + head.upName === 'upChangeRe3' && head.upSequnce === 1 ? <TableHead className="bg-gray-50" style={{ whiteSpace: 'pre-line' }} key={head.id} rowSpan={2} colSpan={6}>{'증설계획'}</TableHead> : + !head.upName ? <TableHead rowSpan={3} className="w-1/20 bg-gray-20" style={{ whiteSpace: 'pre-line' }} key={head.id}>{head.title}</TableHead> : null))} + </TableRow> + <TableRow className="bg-gray-50"> + {upHeadList.map((head: TableUpperProps) => ( + head.upName === 'upChangeRe4' && head.upSequnce === 1 ? <TableHead className="bg-gray-50" style={{ whiteSpace: 'pre-line' }} key={head.id} rowSpan={1} colSpan={6}>{'증설계획(m³/일)'}</TableHead> : + head.upName === 'upChangeRe5' && head.upSequnce === 1 ? <TableHead className="bg-gray-50" style={{ whiteSpace: 'pre-line' }} key={head.id} rowSpan={1} colSpan={6}>{'처리인구(인)'}</TableHead> : + head.upName === 'upChangeRe6' && head.upSequnce === 1 ? <TableHead className="bg-gray-50" style={{ whiteSpace: 'pre-line' }} key={head.id} rowSpan={1} colSpan={7}>{'처리구역(k㎡)'}</TableHead> : + null + ))} + </TableRow> + <TableRow className="bg-gray-50"> + {upHeadList.map((head: TableUpperProps) => { + if (head.upName === 'upChangeRe' || head.upName === 'upChangeRe1' || head.upName === 'upChangeRe2' || head.upName === 'upChangeRe3' || head.upName === 'upChangeRe4' || head.upName === 'upChangeRe5' || head.upName === 'upChangeRe6') { + return <TableHead key={head.id} style={{ whiteSpace: 'pre-line' }} className="w-40 bg-gray-50">{head.title}</TableHead>; + } + })} + </TableRow> + </> + ) : ( + <> + <TableRow className="bg-gray-50">{upHeadList.map((head: TableUpperProps) => + (head.id === 'trtFrfNm' ? <TableHead className="w-1/12" rowSpan={2} key={head.id}>{head.title}</TableHead> : + head.id === 'laeNm' ? <TableHead className="w-1/12" rowSpan={2} key={head.id}>{head.title}</TableHead> : + head.id == 'fctCpc' || head.id == 'planInputWaterQlty' || head.id == 'designInputWaterQlty' ? <TableHead rowSpan={2} className="w-40" style={{ whiteSpace: 'pre-line' }} key={head.id}>{head.title}</TableHead> : + head.id === 'trstOprEtpNm' ? <TableHead className="w-1/15" rowSpan={2} key={head.id}>{head.title}</TableHead> : + head.upName === 'upChangeRe1' && head.upSequnce === 1 ? <TableHead className="w-75 bg-gray-50" style={{ whiteSpace: 'pre-line' }} key={head.id} rowSpan={1} colSpan={3}>{'권역'}</TableHead> : + head.upName === 'upChangeRe2' && head.upSequnce === 1 ? <TableHead className="w-75 bg-gray-50" style={{ whiteSpace: 'pre-line' }} key={head.id} rowSpan={1} colSpan={2}>{'환경청'}</TableHead> : + head.upName === 'upChangeRe3' && head.upSequnce === 1 ? <TableHead className="w-75 bg-gray-50" style={{ whiteSpace: 'pre-line' }} key={head.id} rowSpan={1} colSpan={6}>{'증설계획(m³/일)'}</TableHead> : + head.upName === 'upChangeRe5' && head.upSequnce === 1 ? <TableHead className="w-75 bg-gray-50" style={{ whiteSpace: 'pre-line' }} key={head.id} rowSpan={1} colSpan={6}>{'처리인구(인)'}</TableHead> : + head.upName === 'upChangeRe6' && head.upSequnce === 1 ? <TableHead className="w-75 bg-gray-50" style={{ whiteSpace: 'pre-line' }} key={head.id} rowSpan={1} colSpan={7}>{'처리구역(k㎡)'}</TableHead> : + !head.upName ? <TableHead rowSpan={2} className="w-1/20 bg-gray-20" style={{ whiteSpace: 'pre-line' }} key={head.id}>{head.title}</TableHead> : null))} + </TableRow> + <TableRow className="bg-gray-50"> + {upHeadList.map((head: TableUpperProps) => { + if (head.upName === 'upChangeRe1' || head.upName === 'upChangeRe2' ||head.upName === 'upChangeRe3' || head.upName === 'upChangeRe4' || head.upName === 'upChangeRe5' || head.upName === 'upChangeRe6') { + return <TableHead key={head.id} style={{ whiteSpace: 'pre-line' }} className="w-40 bg-gray-50">{head.title}</TableHead>; + } + })} + </TableRow> + </> + ) + ); +} + +export { HeadMakeColSpan }; \ No newline at end of file diff --git a/apps/fo/app/pages/processArea/modal/page.tsx b/apps/fo/app/pages/processArea/modal/page.tsx new file mode 100644 index 000000000..06e26bac6 --- /dev/null +++ b/apps/fo/app/pages/processArea/modal/page.tsx @@ -0,0 +1,55 @@ +"use client" +import { useFoStore } from "@/app/store"; +import { UiTable } from "@common/business_components/ui"; +import ListDiv from "@common/business_components/ui/list_div"; +import { Table, TableCell, TableHead, TableHeader, TableRow } from "@common/components/ui"; +import { useEffect } from "react"; + +export default function ProcessFacilityInfoModal(props: { fcltyName: string; facilityCd : string;}) { + // 그리드 관련 + const {ProcessAreaDetail, initModalData} = useFoStore((state) => state); + + useEffect(() => { + initModalData(props.facilityCd); + }, [initModalData, props.facilityCd]); + + const { + upHeadListFcltyImproveInfo, + gridListFcltyImproveInfo, + upHeadListProcessPopulation, + gridListProcessPopulation, + upHeadListProcessAreaPlan, + gridListProcessAreaPlan, + } = ProcessAreaDetail + + return ( + <> + <ListDiv> + <div className="card !m-[1.2rem] max-h-[40rem] overflow-auto !p-0r"> + <Table> + <TableHeader> + <TableRow> + <TableHead className="w-1/6">{'시설명'}</TableHead> + <TableCell className="w-1/3">{props.fcltyName}</TableCell> + <TableHead className="w-1/6">{'시설코드'}</TableHead> + <TableCell className="w-1/3">{props.facilityCd}</TableCell> + </TableRow> + </TableHeader> + </Table> + </div> + </ListDiv> + <ListDiv> + <UiTable headName={"시설증설 계획"} tableData={gridListFcltyImproveInfo} headlist={upHeadListFcltyImproveInfo} pageSize={0} total={0} cellClick={undefined} onPageChange={()=>{}}> + </UiTable> + </ListDiv> + <ListDiv> + <UiTable headName={"처리인구 계획"} tableData={gridListProcessPopulation} headlist={upHeadListProcessPopulation} pageSize={0} total={0} cellClick={undefined} onPageChange={()=>{}}> + </UiTable> + </ListDiv> + <ListDiv> + <UiTable headName={"처리구역 계획"} tableData={gridListProcessAreaPlan} headlist={upHeadListProcessAreaPlan} pageSize={0} total={0} cellClick={undefined} onPageChange={()=>{}}> + </UiTable> + </ListDiv> + </> + ); +} \ No newline at end of file diff --git a/apps/fo/app/pages/processArea/page.tsx b/apps/fo/app/pages/processArea/page.tsx new file mode 100644 index 000000000..92369cb45 --- /dev/null +++ b/apps/fo/app/pages/processArea/page.tsx @@ -0,0 +1,172 @@ +"use client" +import { useFoStore } from "@/app/store"; +import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; +import ListDiv from "@common/business_components/ui/list_div"; +import { useCallback, useEffect, useRef, useState } from "react"; +import ProcessFacilityInfoModal from "./modal/page"; + +export default function ProcessArea() { + const {Common, + ProcessArea, + ProcessAreaSearch, + initializeCommonData, + searchProcessAreaList + } = useFoStore((state) => state) || { + Common: { isInit: false, selectSidoData: [], selectSigunData: [], selectRegionData: [], selectUnitWaterShedData: [], selectMiddleRegionData: [], selectEnvPartData: [], selectSearchYear: [{ val: "0" }], btnClass: "" }, + ProcessArea: { processAreaList: [], processAreaCount: 0, excelList: [], upHeadList1: [] }, + ProcessAreaSearch: { processFacilityLabelArray: [] }, + initializeCommonData: () => {}, + searchProcessAreaList: () => {} + }; + + const { + isInit, + selectSidoData, + selectSigunData, + selectRegionData, + selectUnitWaterShedData, + selectMiddleRegionData, + selectEnvPartData, + selectSearchYear, + btnClass, + } = Common; + + const { + processFacilityLabelArray, + } = ProcessAreaSearch; + + const { + upHeadList1, + processAreaList, + processAreaCount, + excelList + } = ProcessArea; + + const mainList: Record<string, unknown>[] = processAreaList || []; + // 그리드 관련 + const searchInputRef = useRef<HTMLDivElement & HTMLInputElement>(null); + + // 모달 상태 추가 + const [selectedRow, setSelectedRow] = useState<number | null>(null); + const [fcltyNm, setFcltyNm] = useState<string>(""); + const [fcltyCd, setFcltyCd] = useState<string>(""); + + const [resetPage, setResetPage] = useState<boolean>(false); + const [searchYearValue, setSearchYearValue] = useState<string>(selectSearchYear[0]?.val || "0"); + + const ref = useRef<ReturnType>({ + partValue: '', + sidoValue: '', + sigunValue: '', + regionValue: '', + unitWaterShedValue: '', + middleRegionValue: '', + envPartValue: '', + sidoText: '', + sigunText: '' + }); + + const searchProcessArea = useCallback(({ sidoText, sigunText}: ReturnType, pageNo: number, pageCnt:number=20) => { + searchProcessAreaList(pageNo, pageCnt, sidoText, sigunText, searchYearValue); + }, [searchProcessAreaList, searchYearValue]); + + // 조회 + const chkVal = useCallback(() => { + setResetPage(true); + }, []); + + // 초기화 + const resetVal = () => { + if (searchInputRef.current) { + const input = searchInputRef.current.querySelector('input'); + if (input) { + input.value = ""; + } + } + setSearchYearValue(selectSearchYear[0]?.val || "0"); + searchProcessAreaList(1, 10, '', '', selectSearchYear[0]?.val); + } + + // 셀 클릭 시 모달 표시 + const cellClick = (index: number) => { + if (processAreaList[index]) { + setFcltyNm(processAreaList[index].swtrmtFcltNm); + setFcltyCd(processAreaList[index].swtrmtFcltCd); + setSelectedRow(index); // 클릭한 행의 index 저장 + } + }; + + // 모달 닫기 + const closeModal = () => { + setSelectedRow(null); + }; + + useEffect(() => { + if (!isInit) { + initializeCommonData(); + searchProcessAreaList(1, 10, '', '', selectSearchYear[0]?.val); + } + }, [isInit, initializeCommonData, searchProcessAreaList, selectSearchYear]); + + useEffect(() => { + if (excelList && excelList.length > 0) { + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: '처리구역정보', + sheetNameArray: ['처리구역정보'], + headerRange: 'A1:W1' + }); + } + }, [excelList]); + + const excelDownload = useCallback(() => { + searchProcessArea(ref.current, 1, 10000); + }, [searchProcessArea]); + + const handlePageChange = useCallback((pageNo: number) => { + setResetPage(false); + searchProcessArea(ref.current, pageNo, 10); + }, [searchProcessArea]); + + const total = processAreaCount; + return ( + <MainDiv> + <Title title="처리구역정보" /> + <ContentsDiv> + <SearchBaseForm + leftChildren={<> + <SelectBox className="col-span-3" label={processFacilityLabelArray[6] as string} selectArray={selectSearchYear} onSelectValue={(val) => setSearchYearValue(val.toString())} value={searchYearValue} selectClass={undefined}/> + </>} + rightChildren={undefined} + selectSidoData={selectSidoData} + selectSigunData={selectSigunData} + selectRegionData={selectRegionData} + selectUnitWaterShedData={selectUnitWaterShedData} + selectMiddleRegionData={selectMiddleRegionData} + selectEnvPartData={selectEnvPartData} + btnClass={btnClass} + queryClick={chkVal} + excelClick={excelDownload} + initClick={resetVal} + ref={ref} + isAdmin={true} + /> + <ListDiv> + <div className="h-full w-full overflow-x-scroll"> + <div className="w-[180%]"> + <UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"처리구역정보"} tableData={mainList} headlist={upHeadList1} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} /> + </div> + </div> + </ListDiv> + </ContentsDiv> + {selectedRow !== null && ( + <UiModal + body={<ProcessFacilityInfoModal fcltyName={fcltyNm} facilityCd={fcltyCd}></ProcessFacilityInfoModal>} + bodyClass="sm:max-w-[90vw] w-[1200px] h-[900px]" + open={selectedRow !== null} + onOpenChange={(open: boolean) => !open && closeModal()} + /> + )} + </MainDiv> + ); +} \ No newline at end of file diff --git a/apps/fo/app/pages/processFacility/modal/page.tsx b/apps/fo/app/pages/processFacility/modal/page.tsx new file mode 100644 index 000000000..3afed1166 --- /dev/null +++ b/apps/fo/app/pages/processFacility/modal/page.tsx @@ -0,0 +1,211 @@ +"use client" +import { useFoStore } from "@/app/store"; +import type { TableUpperProps } from "@/app/store/dashboard"; +import { UITab, UiTable } from "@common/business_components/ui"; +import ListDiv from "@common/business_components/ui/list_div"; +import { + TabsContent +} from "@common/components"; +import { Table, TableCell, TableHead, TableRow } from "@common/components/ui"; + +type ModalType = { + fcltyName: string; + facilityCd : string; + sido : string; + gugun : string; + daddr : string; + fctCpc : number | ''; + trtFrfNm : string; + rnDt : string; + cmplDt : string; + trstOprEtpNm : string; + bscFctClsNm : string; + mnstr : string; + efflWtrrgn : string; + lgbsn : string; + efflWqltStndrdNm : string; + rgnNm : string; + rvbsn : string; +} + +// 시설계획 table header 변경 +const headMakeList = (upHeadList: TableUpperProps[], gridNum:number) => { + if(gridNum===1){ + return ( <> + <TableRow>{ + upHeadList.map((head: TableUpperProps) => + (!head.upSequnce?<TableHead rowSpan={2}key={head.id}>{head.title}</TableHead>: + head.upName === 'upChangeRe'&& head.upSequnce=== 1?<TableHead key={head.id} rowSpan={1} colSpan={6} style={{ whiteSpace: 'pre-line' }}>{'증설계획(m³/일)'}</TableHead>:null))} + </TableRow> + <TableRow> + {upHeadList.map((head: TableUpperProps) => + (head.upName === 'upChangeRe'?<TableHead className="w-150" key={head.id}>{head.title}</TableHead>:null))} + </TableRow> + </> ) + } else if(gridNum===2){ + return ( <> + <TableRow>{ + upHeadList.map((head: TableUpperProps) => + (!head.upSequnce?<TableHead rowSpan={2}key={head.id}>{head.title}</TableHead>: + head.upName === 'upChangeRe1'&& head.upSequnce=== 1?<TableHead key={head.id} rowSpan={1} colSpan={6} style={{ whiteSpace: 'pre-line' }}>{'계획유입수질(mg/L)'}</TableHead>: + head.upName === 'upChangeRe2'&& head.upSequnce=== 1?<TableHead key={head.id} rowSpan={1} colSpan={6} style={{ whiteSpace: 'pre-line' }}>{'설계유입수질(mg/L)'}</TableHead>:null))} + </TableRow> + <TableRow> + {upHeadList.map((head: TableUpperProps) => + (head.upName === 'upChangeRe1'||head.upName === 'upChangeRe2'?<TableHead style={{ whiteSpace: 'pre-line' }} key={head.id}>{head.title}</TableHead>:null))} + </TableRow> + </> ) + } else if(gridNum===3){ + return ( <> + <TableRow>{ + upHeadList.map((head: TableUpperProps) => + (!head.upSequnce?<TableHead key={head.id}>{head.title}</TableHead>: + head.upName === 'upChangeRe1'&& head.upSequnce=== 1?<TableHead key={head.id} colSpan={2} style={{ whiteSpace: 'pre-line' }}>{'사업기간'}</TableHead>:null))} + </TableRow> + </> ) + } else if(gridNum===4){ + return ( <> + <TableRow>{ + upHeadList.map((head: TableUpperProps) => + (!head.upSequnce?<TableHead rowSpan={2}key={head.id}>{head.title}</TableHead>: + head.upName === 'upChangeRe1'&& head.upSequnce=== 1?<TableHead key={head.id} rowSpan={1} colSpan={6} style={{ whiteSpace: 'pre-line' }}>{'계획유입수질(mg/L)'}</TableHead>: + head.upName === 'upChangeRe2'&& head.upSequnce=== 1?<TableHead key={head.id} rowSpan={1} colSpan={6} style={{ whiteSpace: 'pre-line' }}>{'설계유입수질(mg/L)'}</TableHead>: + head.upName === 'upChangeRe3'&& head.upSequnce=== 1?<TableHead key={head.id} rowSpan={1} colSpan={6} style={{ whiteSpace: 'pre-line' }}>{'계획방류수질(mg/L)'}</TableHead>:null))} + </TableRow> + <TableRow> + {upHeadList.map((head: TableUpperProps) => + (head.upName === 'upChangeRe1'||head.upName === 'upChangeRe2'||head.upName === 'upChangeRe3'?<TableHead style={{ whiteSpace: 'pre-line' }} key={head.id}>{head.title}</TableHead>:null))} + </TableRow> + </> ) + } +} + +export default function ProcessFacilityInfoModal(props: ModalType) { + // 그리드 관련 + const {ProcessFacilityDetail} = useFoStore((state) => state); + + const { + upHeadListPlanInfo, + gridListPlanInfo, + upHeadListFcltyAreaInfo, + gridListFcltyAreaInfo, + + upHeadListFcltyHistInfo, + gridListFcltyHistInfo, + upHeadListFcltyWaterQltyInfo, + gridListFcltyWaterQltyInfo, + + upHeadListLegalWaterQlty, + gridListLegalWaterQlty, + } = ProcessFacilityDetail; + + gridListFcltyAreaInfo.map((item) => { + item.efflWtrrgn = props.efflWtrrgn; + item.lgbsn = props.lgbsn; + item.efflWqltStndrdNm = props.efflWqltStndrdNm; + item.rgnNm = props.rgnNm; + item.rvbsn = props.rvbsn; + }) + + const tabList = [ + { value: 'common_info', label: '기본정보' }, + { value: 'history_info', label: '이력정보' }, + ]; + const fctCpc = props.fctCpc ? props.fctCpc.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") : ''; + const upHeadListPlanInfoChange = headMakeList(upHeadListPlanInfo, 2); + const upHeadListFcltyHistInfoChange = headMakeList(upHeadListFcltyHistInfo, 3); + const upHeadListFcltyWaterQltyInfoChange = headMakeList(upHeadListFcltyWaterQltyInfo, 4); + return ( + <> + <ListDiv className="!h-[80px]"> + <div className="card !m-[1.2rem] max-h-[40rem] overflow-auto !p-0r"> + <Table> + <thead> + <TableRow className=""> + <TableHead className="w-1/6">{'시설명'}</TableHead> + <TableCell className="w-1/3">{props.fcltyName}</TableCell> + <TableHead className="w-1/6">{'시설코드'}</TableHead> + <TableCell className="w-1/3">{props.facilityCd}</TableCell> + </TableRow> + </thead> + </Table> + </div> + </ListDiv> + <div className="overflow-y-auto"> + <div className="!h-[600px]"> + <ListDiv className=""> + <UITab tabList={tabList} defaultValue="common_info"> + <TabsContent value="common_info"> + <div className="card-header"> + <h3 className="text-2xl font-medium text-label">시설 기본정보</h3> + </div> + <div className="card !m-[1.2rem] max-h-[40rem] overflow-auto !p-0r"> + <Table> + <thead> + <TableRow className=""> + <TableHead className="w-1/6">{'시설명'}</TableHead> + <TableCell className="w-1/6">{props.fcltyName}</TableCell> + <TableHead className="w-1/6">{'시설구분'}</TableHead> + <TableCell className="w-1/6">{props.bscFctClsNm}</TableCell> + <TableHead className="w-1/6">{'시설용량(m³/일)'}</TableHead> + <TableCell className="w-1/6">{fctCpc}</TableCell> + </TableRow> + </thead> + <tbody> + <TableRow className=""> + <TableHead className="w-1/6">{'시도'}</TableHead> + <TableCell className="w-1/6">{props.sido}</TableCell> + <TableHead className="w-1/6">{'시군구'}</TableHead> + <TableCell className="w-1/6">{props.gugun}</TableCell> + <TableHead className="w-1/6">{'가동개시일'}</TableHead> + <TableCell className="w-1/6">{props.rnDt}</TableCell> + </TableRow> + <TableRow className=""> + <TableHead className="w-1/6">{'주소'}</TableHead> + <TableCell className="w-1/6" colSpan={3}>{props.daddr}</TableCell> + <TableHead className="w-1/6">{'준공일'}</TableHead> + <TableCell className="w-1/6">{props.cmplDt}</TableCell> + </TableRow> + <TableRow className=""> + <TableHead className="w-1/6">{'공법'}</TableHead> + <TableCell className="w-1/6" colSpan={3}>{props.trtFrfNm}</TableCell> + <TableHead className="w-1/6">{'관리대행업자'}</TableHead> + <TableCell className="w-1/6">{props.trstOprEtpNm}</TableCell> + </TableRow> + </tbody> + </Table> + </div> + <UiTable headName={"시설 계획정보"} tableData={gridListPlanInfo} headlist={upHeadListPlanInfo} pageSize={0} total={0} cellClick={undefined} onPageChange={()=>{}}> + {upHeadListPlanInfoChange} + </UiTable> + <UiTable headName={"시설 법적방류수질"} tableData={gridListLegalWaterQlty} headlist={upHeadListLegalWaterQlty} pageSize={0} total={0} cellClick={undefined} onPageChange={()=>{}} /> + <UiTable headName={"시설 수역 및 구역정보"} tableData={gridListFcltyAreaInfo} headlist={upHeadListFcltyAreaInfo} pageSize={0} total={0} cellClick={undefined} onPageChange={()=>{}} /> + </TabsContent> + + <TabsContent value="history_info"> + <ListDiv> + <div className="h-[270px] w-full overflow-y-auto overflow-x-hidden"> + <div className="h-[130%]"> + <UiTable headName={"시설 이력관리"} tableData={gridListFcltyHistInfo} headlist={upHeadListFcltyHistInfo} pageSize={0} total={0} cellClick={undefined} onPageChange={()=>{}}> + {upHeadListFcltyHistInfoChange} + </UiTable> + </div> + </div> + </ListDiv> + <ListDiv> + <div className="h-[270px] w-full overflow-y-auto overflow-x-hidden"> + <div className="h-[130%]"> + <UiTable headName={"시설 수질정보"} tableData={gridListFcltyWaterQltyInfo} headlist={upHeadListFcltyWaterQltyInfo} pageSize={0} total={0} cellClick={undefined} onPageChange={()=>{}}> + {upHeadListFcltyWaterQltyInfoChange} + </UiTable> + </div> + </div> + </ListDiv> + </TabsContent> + </UITab> + </ListDiv> + </div> + </div> + </> + ); +} \ No newline at end of file diff --git a/apps/fo/app/pages/processFacility/page.tsx b/apps/fo/app/pages/processFacility/page.tsx new file mode 100644 index 000000000..ed58dea2b --- /dev/null +++ b/apps/fo/app/pages/processFacility/page.tsx @@ -0,0 +1,294 @@ +"use client" +import { HeadMakeColSpan } from "@/app/components/common/HeadMakeColSpan"; +import { useFoStore } from "@/app/store"; +import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; +import ListDiv from "@common/business_components/ui/list_div"; +import { useCallback, useEffect, useRef, useState } from "react"; +import ProcessFacilityInfoModal from "./modal/page"; + +export default function ProcessFacilitySearch() { + const {Common + ,ProcessFacility + ,ProcessFacilityList + ,initializeCommonData + //시설데이터 조회 + ,searchProcessFacility + //시설데이터 이력정보 조회 + ,searchProcessFacilityHist + //시설데이터 수질정보 조회 + ,searchProcessFacilityWaterQlty + } = useFoStore((state) => state) || { ProcessFacilityList: { processFacilityList: [], processFacilityCount: 0 }}; + + const { + isInit, + selectUpdownData, + selectOperationData, + selectFacilityPartData, + selectSidoData, + selectSigunData, + selectRegionData, + selectUnitWaterShedData, + selectMiddleRegionData, + selectEnvPartData, + btnClass, + } = Common; + + const ref = useRef<ReturnType>({ + partValue: '', + sidoValue: '', + sigunValue: '', + regionValue: '', + unitWaterShedValue: '', + middleRegionValue: '', + envPartValue: '', + sidoText: '', + sigunText: '' + }); + + useEffect(() => { + if(!isInit) { + initializeCommonData(); + searchProcessFacility(1, 10, 'A', '0', '0', '0', '0'); + } + }, [isInit + ,initializeCommonData + ,searchProcessFacility + ]); + + const { + processFacilityLabelArray, + } = ProcessFacility; + + const { + upHeadList1, + upHeadList2, + upHeadList3, + excelList + } = ProcessFacilityList; + + const processFacilityList = ProcessFacilityList?.processFacilityList || []; + + // 그리드 관련 + const inputRef = useRef<HTMLInputElement>(null); + const searchInputRef = useRef<HTMLDivElement & HTMLInputElement>(null); + + const [fcltCpct, setFcltCpct] = useState<string>("0"); + const [fcltyName, setFcltyName] = useState<string>(""); + const [operationValue, setOperationValue] = useState<string>("0"); + const [facilityPartValue, setFacilityPartValue] = useState<string>("0"); + + const [resetPage, setResetPage] = useState<boolean>(false); + + const [partValue, setPartValue] = useState<string>("A"); + const [widthSize, setWidthSize] = useState<string>("w-[120%]"); + const [upHeadList, setUpheadList] = useState(upHeadList1); + + /** + * 모달 상태 변수 + * selectedRow : 클릭한 행의 index + * modalFcltyNm : 시설명 + * modalFcltyCd : 시설코드 + * modalSido : 시도 + * modalGugun : 시군구 + * modalLaeNm : 주소 + * modalFctCpc : 시설용량 + * modalTrtFrfNm : 공법 + * modalRnDt : 가동개시일 + * modalCmplDt : 준공일 + * modalTrstOprEtpNm : 관리대행업자 + * modalBscFctClsNm : 시설구분 + */ + const [selectedRow, setSelectedRow] = useState<number | null>(null); + const [modalFcltyNm, setModalFcltyNm] = useState<string>(""); + const [modalFcltyCd, setModalFcltyCd] = useState<string>(""); + const [modalSido, setModalSido] = useState<string>(""); + const [modalGugun, setModalGugun] = useState<string>(""); + const [modalAddr, setModalAddr] = useState<string>(""); + const [modalFctCpc, setModalFctCpc] = useState<number | ''>(""); + const [modalTrtFrfNm, setModalTrtFrfNm] = useState<string>(""); + const [modalRnDt, setModalRnDt] = useState<string>(""); + const [modalCmplDt, setModalCmplDt] = useState<string>(""); + const [modalTrstOprEtpNm, setModalTrstOprEtpNm] = useState<string>(""); + const [modalBscFctClsNm, setModalBscFctClsNm] = useState<string>(""); + const [modalMnstr, setModalMnstr] = useState<string>(""); + const [modalEfflWtrrgn, setModalEfflWtrrgn] = useState<string>(""); + const [modalLgbsn, setModalLgbsn] = useState<string>(""); + const [modalEfflWqltStndrdNm, setModalEfflWqltStndrdNm] = useState<string>(""); + const [modalRgnNm, setModalRgnNm] = useState<string>(""); + const [modalRvbsn, setModalRvbsn] = useState<string>(""); + const [isSearch, setIsSearch] = useState<boolean>(false); + + // 표 레이아웃 상태 + const chkVal = useCallback((result:ReturnType) => { + setPartValue(result.partValue); + setResetPage(true); + setIsSearch(true); + }, []); + + useEffect(() => { + switch (partValue) { + case 'A': + setWidthSize("w-[130%]"); + setUpheadList(upHeadList1); + break; + case 'R': + setWidthSize("w-[140%]"); + setUpheadList(upHeadList2); + break; + case 'G': + setWidthSize("w-[150%]"); + setUpheadList(upHeadList3); + break; + } + }, [partValue, upHeadList1, upHeadList2, upHeadList3]); + + useEffect(() => { + if (excelList && excelList.length > 0) { + downloadExcel({ data: excelList as unknown as JSON[], fileName: '처리시설 시설정보', sheetNameArray: ['처리시설 시설정보'], headerRange: 'A1:P1' }); + } + }, [excelList]); + + const searchFcltyList = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=10) => { + let nameCd, partStr + switch (partValue) { + case 'R': + if (regionValue !== '0') { + if(unitWaterShedValue==='0') nameCd = regionValue; + else if (middleRegionValue==='0') nameCd = unitWaterShedValue; + else nameCd = middleRegionValue; + } + partStr = partValue + break; + default: + if(sidoValue !== '0') nameCd = sidoValue; + if(sigunValue !== '0') nameCd = sigunValue; + partStr = envPartValue !== '0' ? envPartValue:partValue; + break; + } + searchProcessFacility(pageNo, pageCnt, partStr, nameCd || '0', fcltCpct, operationValue, facilityPartValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); + if(isSearch) { + setIsSearch(false); + } + }, [facilityPartValue, fcltCpct, fcltyName, isSearch, operationValue, searchProcessFacility]) + + const changePage = useCallback((page: number) => { + searchFcltyList(ref.current, page); + },[searchFcltyList]) + + const resetVal = () => { + // SelectBox 초기화 - 각 selectArray의 첫 번째 옵션 값 사용 + searchProcessFacility(1, 10, 'A', '0', '0', '0', '0', ''); + setFcltCpct("0"); + setOperationValue("0"); + setFacilityPartValue("0"); + setPartValue('A'); + setUpheadList(upHeadList1); + // SearchInputSelect 초기화 + setFcltyName(""); + + // ref를 사용하여 input 값 초기화 + if (inputRef.current) { + inputRef.current.value = ""; + } + + if (searchInputRef.current) { + const input = searchInputRef.current.querySelector('input'); + if (input) { + input.value = ""; + } + } + } + + // 셀 클릭 시 모달 표시 + const cellClick = (index: number) => { + const facility = processFacilityList[index]; + if (facility) { + setModalFcltyNm(facility.bscFctNm); + setModalFcltyCd(facility.bscFctCd); + setModalSido(facility.sido); + setModalGugun(facility.gugun); + setModalAddr(facility.daddr); + setModalFctCpc(Number(facility.fctCpc)); + setModalTrtFrfNm(facility.trtFrfNm); + setModalRnDt(facility.rnDt); + setModalCmplDt(facility.cmplDt); + setModalTrstOprEtpNm(facility.trstOprEtpNm); + setModalBscFctClsNm(facility.bscFctClsNm); + setModalMnstr(facility.mnstr); + setModalEfflWtrrgn(facility.efflWtrrgn); + setModalLgbsn(facility.lgbsn); + setModalEfflWqltStndrdNm(facility.efflWqltStndrdNm); + setModalRgnNm(facility.rgnNm); + setModalRvbsn(facility.rvbsn); + + searchProcessFacilityHist(facility.bscFctCd); + searchProcessFacilityWaterQlty(facility.bscFctCd); + setSelectedRow(index); // 클릭한 행의 index 저장 + } + } + + const excelDownload = useCallback(() => { + searchFcltyList(ref.current, 1, 10000); + }, [searchFcltyList]); + + // 모달 닫기 + const closeModal = () => { + setSelectedRow(null); + } + + const total = ProcessFacilityList?.processFacilityCount || 1; + + return ( + <MainDiv> + <Title title="처리시설 시설정보" /> + <ContentsDiv> + <SearchBaseForm + leftChildren={<> + <SelectBox className="col-span-3" label={processFacilityLabelArray[3] as string} selectArray={selectUpdownData} onSelectValue={val => setFcltCpct(val.toString())} value={fcltCpct} selectClass={undefined} /> + <SearchInput className="col-span-3" label={processFacilityLabelArray[4] as string} textValue={fcltyName} setText={setFcltyName} /> + <SelectBox className="col-span-3" label={processFacilityLabelArray[5] as string} selectArray={selectOperationData} onSelectValue={val => setOperationValue(val.toString())} value={operationValue} selectClass={undefined} /> + <SelectBox className="col-span-3" label={processFacilityLabelArray[6] as string} selectArray={selectFacilityPartData} onSelectValue={val => setFacilityPartValue(val.toString())} value={facilityPartValue} selectClass={undefined} /> + </>} + rightChildren={undefined} + selectSidoData={selectSidoData} + selectSigunData={selectSigunData} + selectRegionData={selectRegionData} + selectUnitWaterShedData={selectUnitWaterShedData} + selectMiddleRegionData={selectMiddleRegionData} + selectEnvPartData={selectEnvPartData} + btnClass={btnClass} + queryClick={chkVal} + excelClick={excelDownload} + initClick={resetVal} + ref={ref} isAdmin={false} /> + <ListDiv> + <div className="h-full w-full overflow-x-scroll"> + <div className={widthSize}> + <UiTable + cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} + headName={"처리시설 시설정보"} + tableData={processFacilityList} + headlist={upHeadList} + pageSize={10} + total={total} + resetPageNo={resetPage} + onPageChange={changePage} + > + <HeadMakeColSpan upHeadList={upHeadList} layoutNum={partValue}/> + </UiTable> + </div> + </div> + </ListDiv> + <span className="text-2xl text-gray-500">※계획유입수질 및 설계유입수질은 해당 BOD를 나타냄</span> + </ContentsDiv> + {selectedRow !== null && ( + <UiModal + body={<ProcessFacilityInfoModal fcltyName={modalFcltyNm} facilityCd={modalFcltyCd} sido={modalSido} gugun={modalGugun} daddr={modalAddr} fctCpc={modalFctCpc} trtFrfNm={modalTrtFrfNm} rnDt={modalRnDt} cmplDt={modalCmplDt} trstOprEtpNm={modalTrstOprEtpNm} bscFctClsNm={modalBscFctClsNm} mnstr={modalMnstr} efflWtrrgn={modalEfflWtrrgn} lgbsn={modalLgbsn} efflWqltStndrdNm={modalEfflWqltStndrdNm} rgnNm={modalRgnNm} rvbsn={modalRvbsn}></ProcessFacilityInfoModal>} + bodyClass="sm:max-w-[70vw] sm:max-h-[95vh]" + open={selectedRow !== null} + onOpenChange={(open) => !open && closeModal()} + /> + )} + </MainDiv> + ); +} \ No newline at end of file diff --git a/apps/fo/app/pages/rdi/page.tsx b/apps/fo/app/pages/rdi/page.tsx new file mode 100644 index 000000000..d28c7241d --- /dev/null +++ b/apps/fo/app/pages/rdi/page.tsx @@ -0,0 +1,200 @@ +"use client" +import { useFoStore } from "@/app/store"; +import type { TableUpperProps } from "@/app/store/common"; +import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiTable, type ReturnType } from "@common/business_components"; +import ListDiv from "@common/business_components/ui/list_div"; +import { useCallback, useEffect, useRef, useState } from "react"; + +export default function Rdi() { + const {Common + ,initializeCommonData + ,Rdi + ,RdiSearch + ,searchRdiList + } = useFoStore((state) => state) || { processAreaList: { processAreaList: [] }}; + + const { + isInit, + selectUpdownData, + selectOperationData, + selectSidoData, + selectSigunData, + selectRegionData, + selectUnitWaterShedData, + selectMiddleRegionData, + selectEnvPartData, + selectSearchYear, + btnClass + } = Common; + + const { + labelArray, + } = RdiSearch; + + const { + upHeadList1, + upHeadList2, + upHeadList3, + rdiList, + rdiCount, + excelList, + } = Rdi; + + const ref = useRef<ReturnType>({ + partValue: '', + sidoValue: '', + sigunValue: '', + regionValue: '', + unitWaterShedValue: '', + middleRegionValue: '', + envPartValue: '', + sidoText: '', + sigunText: '' + }); + + // 그리드 관련 + const searchInputRef = useRef<HTMLDivElement & HTMLInputElement>(null); + + // 초기화 변수 + const [resetPage, setResetPage] = useState<boolean>(false); + // 표 너비 + const [widthSize, setWidthSize] = useState<string>("w-[120%]"); + // 구분별 그리드 헤더 + const [upheadList, setUpheadList] = useState<TableUpperProps[]>(upHeadList1); + // 용량별 + const [fcltCpct, setFcltCpct] = useState<string>("0"); + // 시설명 + const [fcltyName, setFcltyName] = useState<string>(""); + // 시설상태 + const [operationValue, setOperationValue] = useState<string>("0"); + // 조회기간 + const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || "0"); + + /** + * 페이지 함수 + */ + // 초기화 + const resetVal = () => { + setWidthSize("w-[120%]"); + + setUpheadList(upHeadList1) + // 상태값 설정 + setFcltCpct(selectUpdownData[0]?.val || "0"); + setOperationValue(selectOperationData[0]?.val || "0"); + setSearchYear(selectSearchYear[0]?.val || "0"); + // SearchInputSelect 초기화 + setFcltyName(""); + if (searchInputRef.current) { + const input = searchInputRef.current.querySelector('input'); + if (input) { + input.value = ""; + } + } + searchRdiList(1, 10, selectSearchYear[0]?.val || "0"); + + } + + /** + * useEffect + */ + useEffect(() => { + if (!isInit) { + initializeCommonData(); + searchRdiList(1, 10, selectSearchYear[0]?.val || "0"); + } + }, [isInit, initializeCommonData, searchRdiList, selectSearchYear]); + + useEffect(() => { + if (excelList && excelList.length > 0) { + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: 'RDII추정', + sheetNameArray: ['RDII추정'], + headerRange: 'A1:O1' + }); + } + }, [excelList]); + + /** + * 콜백함수 + */ + // 조회 + const searchRdi = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { + let nameCd, partStr + switch (partValue) { + case 'R': + if (regionValue !== '0') { + if(unitWaterShedValue==='0') nameCd = regionValue; + else if (middleRegionValue==='0') nameCd = unitWaterShedValue; + else nameCd = middleRegionValue; + } + partStr = partValue + break; + default: + if(sidoValue !== '0') nameCd = sidoValue; + if(sigunValue !== '0') nameCd = sigunValue; + partStr = envPartValue !== '0' ? envPartValue:partValue; + break; + } + if (partStr.length > 1 || fcltCpct !== '0' || operationValue!== '0' ||nameCd ||(fcltyName.trim() !== "" && fcltyName.trim() !== null)) { + searchRdiList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); + } else { + searchRdiList(pageNo, pageCnt, searchYear); + } + }, [operationValue, fcltyName, searchRdiList, searchYear, fcltCpct]); + + const chkVal = useCallback((returntype:ReturnType) => { + setWidthSize(returntype.partValue=='A' ?"w-[120%]":"w-[130%]") + setUpheadList(returntype.partValue == 'R' ? upHeadList2 : returntype.partValue == 'G'?upHeadList3:upHeadList1); + setResetPage(true); + }, [upHeadList1, upHeadList2, upHeadList3]); + + // 엑셀다운로드 + const excelDownload = useCallback(() => { + searchRdi(ref.current, 1, 10000); + }, [searchRdi]); + + // 페이지 변경 + const handlePageChange = useCallback((page: number) => { + setResetPage(false); + searchRdi(ref.current, page, 10); + }, [searchRdi]); + + const mainList: Record<string, string | number | boolean>[] = rdiList || []; + const total = rdiCount || 0; + + return ( + <MainDiv> + <Title title="RDII추정" /> + <ContentsDiv> + <SearchBaseForm + leftChildren={<> + <SelectBox className="col-span-3" label={labelArray[3] as string} selectArray={selectUpdownData} onSelectValue={(val) => setFcltCpct(val.toString())} value={fcltCpct} selectClass={undefined} /> + <SearchInput ref={searchInputRef} className={"col-span-3"} label={labelArray[4] as string} textValue={fcltyName} setText={setFcltyName} /> + <SelectBox className="col-span-3" label={labelArray[5] as string} selectArray={selectSearchYear} onSelectValue={(val) => setSearchYear(val.toString())} value={searchYear} selectClass={undefined} /> + <SelectBox className="col-span-3" label={labelArray[6] as string} selectArray={selectOperationData} onSelectValue={(val) => setOperationValue(val.toString())} value={operationValue} selectClass={undefined} /> + </>} + rightChildren={undefined} + selectSidoData={selectSidoData} + selectSigunData={selectSigunData} + selectRegionData={selectRegionData} + selectUnitWaterShedData={selectUnitWaterShedData} + selectMiddleRegionData={selectMiddleRegionData} + selectEnvPartData={selectEnvPartData} + btnClass={btnClass} + queryClick={chkVal} + excelClick={excelDownload} + initClick={resetVal} + ref={ref} isAdmin={false} /> + <ListDiv> + <div className="h-full w-full overflow-x-scroll"> + <div className={widthSize}> + <UiTable cellClick={ undefined } headName={"RDII추정"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} /> + </div> + <span className="text-2xl text-gray-500">※주) 처리장 유입부에서 측정된 유량 및 수질조사 자료를 기준으로 산정된 결과임</span> + </div> + </ListDiv> + </ContentsDiv> + </MainDiv> + ); +} \ No newline at end of file diff --git a/apps/fo/app/pages/sewageOccur/modal/page.tsx b/apps/fo/app/pages/sewageOccur/modal/page.tsx new file mode 100644 index 000000000..e8a90651e --- /dev/null +++ b/apps/fo/app/pages/sewageOccur/modal/page.tsx @@ -0,0 +1,161 @@ +"use client" +import { useFoStore } from "@/app/store"; +import type { SewageOccurDetailProps } from "@/app/store/sewageOccur"; +import { DateMonthPicker, UiTable } from "@common/business_components/ui"; +import ListDiv from "@common/business_components/ui/list_div"; +import { Table, TableCell, TableHead, TableRow } from "@common/components/ui"; +import { useEffect, useState } from "react"; + +export default function SewageOccurModal(props: { fcltyName: string; facilityCd : string; searchYear : string}) { + // 그리드 관련 + const {SewageOccurDetail} = useFoStore((state) => state); + + // searchYear 유효성 검사 및 기본값 설정 + const validSearchYear = props.searchYear && /^\d{4}$/.test(props.searchYear) ? props.searchYear : new Date().getFullYear().toString(); + + const [startYearMonth, setStartYearMonth] = useState(validSearchYear+'01'); + const [endYearMonth, setEndYearMonth] = useState(validSearchYear+'12'); + const [detailList, setDetailList] = useState<SewageOccurDetailProps[]>([]); + const { + upHeadListSewageOccurDetail, + gridListSewageOccurDetail + } = SewageOccurDetail; + + useEffect(() => { + setDetailList(gridListSewageOccurDetail); + }, [gridListSewageOccurDetail]); + + useEffect(() => { + const filteredList = gridListSewageOccurDetail.filter(item => item.msrDt.replace(/-/g, '') >= startYearMonth && item.msrDt.replace(/-/g, '') <= endYearMonth); + let maxWaterUsage = 0; + let maxSwageChangePercent = 0; + let maxEstimationSewage = 0; + + let minWaterUsage = filteredList[0]?.waterUsage || 0; + let minSwageChangePercent = filteredList[0]?.swageChangePercent || 0; + let minEstimationSewage = filteredList[0]?.estimationSewage || 0; + + let totalWaterUsage = 0; + let totalSwageChangePercent = 0; + let totalEstimationSewage = 0; + + let avgWaterUsage = 0; + let avgSwageChangePercent = 0; + let avgEstimationSewage = 0; + + filteredList.forEach(item => { + if (item.waterUsage > maxWaterUsage) { + maxWaterUsage = item.waterUsage; + } + if (item.swageChangePercent > maxSwageChangePercent) { + maxSwageChangePercent = item.swageChangePercent; + } + if (item.estimationSewage > maxEstimationSewage) { + maxEstimationSewage = item.estimationSewage; + } + + if (item.waterUsage < minWaterUsage) { + minWaterUsage = item.waterUsage; + } + if (item.swageChangePercent < minSwageChangePercent) { + minSwageChangePercent = item.swageChangePercent; + } + if (item.estimationSewage < minEstimationSewage) { + minEstimationSewage = item.estimationSewage; + } + + totalWaterUsage += item.waterUsage; + totalSwageChangePercent += item.swageChangePercent; + totalEstimationSewage += item.estimationSewage; + }); + + avgWaterUsage = totalWaterUsage?totalWaterUsage / filteredList.length:0; + avgSwageChangePercent = totalSwageChangePercent?totalSwageChangePercent / filteredList.length:0; + avgEstimationSewage = totalEstimationSewage?totalEstimationSewage / filteredList.length:0; + + const newData = [ + { + msrDt: '평균', + waterUsage: Math.round(avgWaterUsage * 100) / 100, + swageChangePercent: Math.round(avgSwageChangePercent * 100) / 100, + estimationSewage: Math.round(avgEstimationSewage * 100) / 100 + }, + { + msrDt: '최대', + waterUsage: maxWaterUsage, + swageChangePercent: maxSwageChangePercent, + estimationSewage: maxEstimationSewage + }, + { + msrDt: '최소', + waterUsage: minWaterUsage, + swageChangePercent: minSwageChangePercent, + estimationSewage: minEstimationSewage + }, + ...filteredList + ] + setDetailList(newData); + + + }, [startYearMonth, endYearMonth, gridListSewageOccurDetail]); + + return ( + <> + <ListDiv className="!h-[80px] !mt-10"> + <div className="card !m-[1.2rem] max-h-[40rem] overflow-auto !p-0r"> + <Table> + <thead> + <TableRow className=""> + <TableHead className="w-1/6">{'시설명'}</TableHead> + <TableCell className="w-1/3">{props.fcltyName}</TableCell> + <TableHead className="w-1/6">{'년월'}</TableHead> + <TableCell className="w-1/3"> + <DateMonthPicker + field={{ + value: startYearMonth || (() => { + const now = new Date(); + const year = now.getFullYear(); + const month = String(now.getMonth() + 1).padStart(2, '0'); + return `${year}${month}`; + })(), + onChange: (value: string) => { + if (value && /^\d{6}$/.test(value)) { + setStartYearMonth(value); + } + } + }} + selectClass="ml-5 w-[100px]" + startYear={1900} + />~ + <DateMonthPicker + field={{ + value: endYearMonth || (() => { + const now = new Date(); + const year = now.getFullYear(); + const month = String(now.getMonth() + 1).padStart(2, '0'); + return `${year}${month}`; + })(), + onChange: (value: string) => { + if (value && /^\d{6}$/.test(value)) { + setEndYearMonth(value); + } + } + }} + selectClass="ml-5 w-[100px]" + startYear={1900} + /> + </TableCell> + </TableRow> + </thead> + </Table> + </div> + </ListDiv> + <ListDiv className="!h-[570px] overflow-y-auto"> + <div className="h-[120%]"> + <UiTable headName={"오수발생량 추정"} tableData={detailList} headlist={upHeadListSewageOccurDetail} pageSize={0} total={0} cellClick={undefined} onPageChange={() => {}} boldArray={[0, 1, 2]}> + </UiTable> + </div> + </ListDiv> + </> + ); +} \ No newline at end of file diff --git a/apps/fo/app/pages/sewageOccur/page.tsx b/apps/fo/app/pages/sewageOccur/page.tsx new file mode 100644 index 000000000..a137d9ebe --- /dev/null +++ b/apps/fo/app/pages/sewageOccur/page.tsx @@ -0,0 +1,237 @@ +"use client" +import { useFoStore } from "@/app/store"; +import type { TableUpperProps } from "@/app/store/common"; +import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; +import ListDiv from "@common/business_components/ui/list_div"; +import { useCallback, useEffect, useRef, useState } from "react"; +import SewageOccurModal from "./modal/page"; +import type { SewageOccurProps } from "@/app/store/sewageOccur"; + +export default function PlanSewage() { + const {Common + ,SewageOccur + ,SewageOccurSearch + ,initializeCommonData + ,searchSewageOccurList + } = useFoStore((state) => state) || { + Common: { isInit: false, selectUpdownData: [], selectOperationData: [], selectSidoData: [], selectSigunData: [], selectRegionData: [], selectUnitWaterShedData: [], selectMiddleRegionData: [], selectEnvPartData: [], selectSearchYear: [{ val: "0" }], btnClass: "" }, + SewageOccur: { sewageOccurList: [], sewageOccurCount: 0, excelList: [], upHeadList1: [], upHeadList2: [], upHeadList3: [] }, + SewageOccurSearch: { labelArray: [] }, + initializeCommonData: () => {}, + searchSewageOccurList: () => {} + }; + + const { + isInit, + selectUpdownData, + selectOperationData, + selectSidoData, + selectSigunData, + selectRegionData, + selectUnitWaterShedData, + selectMiddleRegionData, + selectEnvPartData, + selectSearchYear, + btnClass + } = Common; + + const { + labelArray, + } = SewageOccurSearch; + + const { + upHeadList1, + upHeadList2, + upHeadList3, + sewageOccurList, + sewageOccurCount, + excelList + } = SewageOccur; + + const ref = useRef<ReturnType>({ + partValue: '', + sidoValue: '', + sigunValue: '', + regionValue: '', + unitWaterShedValue: '', + middleRegionValue: '', + envPartValue: '', + sidoText: '', + sigunText: '' + }); + + const sewageOccur = SewageOccur?.sewageOccurList || []; + + // 모달 상태 추가 + const [selectedRow, setSelectedRow] = useState<number | null>(null); + const [fcltyNm, setFcltyNm] = useState<string>(""); + const [fcltyCd, setFcltyCd] = useState<string>(""); + + // 그리드 관련 + const searchInputRef = useRef<HTMLDivElement & HTMLInputElement>(null); + + // 초기화 변수 + const [resetPage, setResetPage] = useState<boolean>(false); + // 표 너비 + const [widthSize, setWidthSize] = useState<string>("w-[120%]"); + // 구분별 그리드 헤더 + const [upheadList, setUpheadList] = useState<TableUpperProps[]>(upHeadList1); + // 용량별 + const [fcltCpct, setFcltCpct] = useState<string>("0"); + // 시설명 + const [fcltyName, setFcltyName] = useState<string>(""); + // 시설상태 + const [operationValue, setOperationValue] = useState<string>("0"); + // 조회기간 + const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || "0"); + + /** + * 페이지 함수 + */ + // 초기화 + const resetVal = () => { + setWidthSize("w-[120%]"); + setUpheadList(upHeadList1) + // 상태값 설정 + setFcltCpct(selectUpdownData[0]?.val || "0"); + setOperationValue(selectOperationData[0]?.val || "0"); + setSearchYear(selectSearchYear[0]?.val || "0"); + // SearchInputSelect 초기화 + setFcltyName(""); + if (searchInputRef.current) { + const input = searchInputRef.current.querySelector('input'); + if (input) { + input.value = ""; + } + } + } + + // 모달 닫기 + const closeModal = () => { + setSelectedRow(null); + }; + + // 셀 클릭 시 모달 표시 + const cellClick = (index: number) => { + if (sewageOccur[index]) { + setFcltyNm(sewageOccur[index].bscFctNm); + setFcltyCd(sewageOccur[index].bscFctCd); + setSelectedRow(index); // 클릭한 행의 index 저장 + } + }; + + /** + * useEffect + */ + useEffect(() => { + if (!isInit) { + initializeCommonData(); + searchSewageOccurList(1, 10, selectSearchYear[0]?.val || "0"); + } + }, [isInit, initializeCommonData, searchSewageOccurList, selectSearchYear]); + + useEffect(() => { + if (excelList && excelList.length > 0) { + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: '오수발생량 추정', + sheetNameArray: ['오수발생량 추정'], + headerRange: 'A1:O1' + }); + } + }, [excelList]); + + /** + * 콜백함수 + */ + // 조회 + const searchFacilityPrecipitation = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { + let nameCd, partStr + switch (partValue) { + case 'R': + if (regionValue !== '0') { + if(unitWaterShedValue==='0') nameCd = regionValue; + else if (middleRegionValue==='0') nameCd = unitWaterShedValue; + else nameCd = middleRegionValue; + } + partStr = partValue + break; + default: + if(sidoValue !== '0') nameCd = sidoValue; + if(sigunValue !== '0') nameCd = sigunValue; + partStr = envPartValue !== '0' ? envPartValue:partValue; + break; + } + if (partStr.length > 1 || fcltCpct !== '0' || operationValue!== '0' ||nameCd ||(fcltyName.trim() !== "" && fcltyName.trim() !== null)) { + searchSewageOccurList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); + } else { + searchSewageOccurList(pageNo, pageCnt, searchYear); + } + }, [fcltCpct, operationValue, fcltyName, searchSewageOccurList, searchYear]); + + const chkVal = useCallback((returntype:ReturnType) => { + setWidthSize(returntype.partValue=='A' ?"w-[120%]":"w-[130%]") + setUpheadList(returntype.partValue == 'R' ? upHeadList2 : returntype.partValue == 'G'?upHeadList3:upHeadList1); + setResetPage(true); + }, [upHeadList1, upHeadList2, upHeadList3]); + + // 엑셀다운로드 + const excelDownload = useCallback(() => { + searchFacilityPrecipitation(ref.current, 1, 10000); + }, [searchFacilityPrecipitation]); + + // 페이지 변경 + const handlePageChange = useCallback((page: number) => { + setResetPage(false); + searchFacilityPrecipitation(ref.current, page, 10); + }, [searchFacilityPrecipitation]); + + const mainList: SewageOccurProps[] = sewageOccurList || []; + const total = sewageOccurCount || 0; + + return ( + <MainDiv> + <Title title="오수발생량 추정" /> + <ContentsDiv> + <SearchBaseForm + leftChildren={<> + <SelectBox className="col-span-3" label={labelArray[3] as string} selectArray={selectUpdownData} onSelectValue={(val) => setFcltCpct(val.toString())} value={fcltCpct} selectClass={undefined} /> + <SearchInput className={"col-span-3"} label={labelArray[4] as string} textValue={fcltyName} setText={setFcltyName} /> + <SelectBox className="col-span-3" label={labelArray[5] as string} selectArray={selectSearchYear} onSelectValue={(val) => setSearchYear(val.toString())} value={searchYear} selectClass={undefined} /> + <SelectBox className="col-span-3" label={labelArray[6] as string} selectArray={selectOperationData} onSelectValue={(val) => setOperationValue(val.toString())} value={operationValue} selectClass={undefined} /> + </>} + rightChildren={undefined} + selectSidoData={selectSidoData} + selectSigunData={selectSigunData} + selectRegionData={selectRegionData} + selectUnitWaterShedData={selectUnitWaterShedData} + selectMiddleRegionData={selectMiddleRegionData} + selectEnvPartData={selectEnvPartData} + btnClass={btnClass} + queryClick={chkVal} + excelClick={excelDownload} + initClick={resetVal} + ref={ref} + isAdmin={false} + /> + <ListDiv> + <div className="h-full w-full overflow-x-scroll"> + <div className={widthSize}> + <UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"오수발생량 추정"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} /> + </div> + </div> + </ListDiv> + </ContentsDiv> + {selectedRow !== null && ( + <UiModal + body={<SewageOccurModal fcltyName={fcltyNm} facilityCd={fcltyCd} searchYear={searchYear}></SewageOccurModal>} + bodyClass="sm:max-w-[90vw] w-[1000px] h-[770px]" + open={selectedRow !== null} + onOpenChange={(open) => !open && closeModal()} + noHeaderYn="Y" + noFooterYn="Y" + /> + )} + </MainDiv> + ); +} \ No newline at end of file diff --git a/apps/fo/app/pages/underWaterInput/modal/page.tsx b/apps/fo/app/pages/underWaterInput/modal/page.tsx new file mode 100644 index 000000000..9e49fb1bc --- /dev/null +++ b/apps/fo/app/pages/underWaterInput/modal/page.tsx @@ -0,0 +1,317 @@ +"use client" +import { useFoStore } from "@/app/store"; +import type { UnderWaterInputModalProps } from "@/app/store/underWaterInput"; +import { DateMonthPicker, UITab, UiTable } from "@common/business_components/ui"; +import ListDiv from "@common/business_components/ui/list_div"; +import { Table, TableCell, TableHead, TableRow, TabsContent } from "@common/components/ui"; +import { useEffect, useState } from "react"; + +type ModalProps ={ + fcltyName: string; + searchYear : string; +} + +const tabList1 = [ + { value: 'tab_term_year', label: '연간' }, + { value: 'tab_term_summer', label: '하절기' }, + { value: 'tab_term_winter', label: '동절기' }, +]; + +export default function UnderWaterInputModal({fcltyName='', searchYear=new Date().getFullYear().toString()} : ModalProps) { + // 그리드 관련 + const {UnderWaterDetail} = useFoStore((state) => state); + + const [startYmDate, setStartYmDate] = useState<string>(searchYear+'01'); + const [endYmDate, setEndYmDate] = useState<string>(searchYear+'12'); + const [tabTerm, setTabTerm] = useState<string>('tab_term_year'); + + // 이전 값들을 저장하기 위한 상태 + const [prevStartYmDate, setPrevStartYmDate] = useState<string>(searchYear+'01'); + const [prevEndYmDate, setPrevEndYmDate] = useState<string>(searchYear+'12'); + + const { + upHeadListUnderWaterDetail, + gridListUnderWaterDetail, + } = UnderWaterDetail; + + // 필터링 된 후 최대, 최소, 평균 값 계산 + const setFilterAfterData = (filteredData: UnderWaterInputModalProps[]) => { + let maxRealSewageInput = Number(filteredData[0]?.realSewageInput ?? 0); + let maxSewageOccur = Number(filteredData[0]?.sewageOccur ?? 0); + let maxUnderWaterInput = Number(filteredData[0]?.underWaterInput ?? 0); + + let minRealSewageInput = Number(filteredData[0]?.realSewageInput ?? 0); + let minSewageOccur = Number(filteredData[0]?.sewageOccur ?? 0); + let minUnderWaterInput = Number(filteredData[0]?.underWaterInput ?? 0); + + let avgRealSewageInput = 0; + let avgSewageOccur = 0; + let avgUnderWaterInput = 0; + + filteredData.forEach((item: UnderWaterInputModalProps) => { + maxRealSewageInput = Math.max(Number(maxRealSewageInput), Number(item.realSewageInput)); + maxSewageOccur = Math.max(Number(maxSewageOccur), Number(item.sewageOccur)); + maxUnderWaterInput = Math.max(Number(maxUnderWaterInput), Number(item.underWaterInput)); + + minRealSewageInput = Math.min(Number(minRealSewageInput) || 0, Number(item.realSewageInput)); + minSewageOccur = Math.min(Number(minSewageOccur) || 0, Number(item.sewageOccur)); + minUnderWaterInput = Math.min(Number(minUnderWaterInput) || 0, Number(item.underWaterInput)); + + avgRealSewageInput += Number(item.realSewageInput ?? 0); + avgSewageOccur += Number(item.sewageOccur ?? 0); + avgUnderWaterInput += Number(item.underWaterInput ?? 0); + }) + + const newFilteredData = [ + { + msrDt: '평균', + realSewageInput: filteredData.length==0?0:Math.round(Number(avgRealSewageInput) / filteredData.length * 10) / 10, + sewageOccur: filteredData.length==0?0:Math.round(Number(avgSewageOccur) / filteredData.length * 1000) / 1000 , + underWaterInput: filteredData.length==0?0:Math.round(Number(avgUnderWaterInput) / filteredData.length * 1000) / 1000, + }, + { + msrDt : '최대', + realSewageInput : Math.round(maxRealSewageInput * 10) / 10, + sewageOccur : Math.round(maxSewageOccur * 1000) / 1000 , + underWaterInput : Math.round(maxUnderWaterInput * 1000) / 1000, + }, + { + msrDt : '최소', + realSewageInput : Math.round(minRealSewageInput * 10) / 10, + sewageOccur : Math.round(minSewageOccur * 1000) / 1000 , + underWaterInput : Math.round(minUnderWaterInput * 1000) / 1000, + }, + ...filteredData + ]; + return newFilteredData; + } + + // 날짜 필터링 관련 상태 + const [copyYearList, setCopyYearList] = useState<UnderWaterInputModalProps[]>([]); + + useEffect(() => { + const filteredYearData = setFilterAfterData(gridListUnderWaterDetail); + setCopyYearList(filteredYearData as UnderWaterInputModalProps[]); + }, [gridListUnderWaterDetail]); + + useEffect(() => { + switch (tabTerm) { + case 'tab_term_summer': + setStartYmDate(searchYear+'06'); + setEndYmDate(searchYear+'08'); + setPrevStartYmDate(searchYear+'06'); + setPrevEndYmDate(searchYear+'08'); + break; + case 'tab_term_winter': + setStartYmDate(searchYear+'01'); + setEndYmDate(searchYear+'02'); + setPrevStartYmDate(searchYear+'01'); + setPrevEndYmDate(searchYear+'02'); + break; + default: + setStartYmDate(searchYear+'01'); + setEndYmDate(searchYear+'12'); + setPrevStartYmDate(searchYear+'01'); + setPrevEndYmDate(searchYear+'12'); + } + }, [searchYear, tabTerm]); + + useEffect(() => { + if(endYmDate < startYmDate) { + alert('종료일이 시작일보다 작습니다.') + // 이전 값으로 되돌리기 + setStartYmDate(prevStartYmDate); + setEndYmDate(prevEndYmDate); + return; + } + + // 유효한 경우 현재 값을 이전 값으로 저장 + setPrevStartYmDate(startYmDate); + setPrevEndYmDate(endYmDate); + + const filteredData = gridListUnderWaterDetail.filter((item: UnderWaterInputModalProps) => { + // msrDt가 "2024-01" 형태이므로 "202401" 형태로 변환 + const itemDate = item.msrDt.replace('-', ''); + return itemDate >= startYmDate && itemDate <= endYmDate; + }); + const filteredYearData = setFilterAfterData(filteredData); + setCopyYearList(filteredYearData as UnderWaterInputModalProps[]); + }, [startYmDate, endYmDate, gridListUnderWaterDetail, prevStartYmDate, prevEndYmDate]); + + return ( + <> + <UITab tabList={tabList1} defaultValue="tab_term_year" onValueChange={(val) => {setTabTerm(val)}}> + <TabsContent value="tab_term_year"> + <ListDiv className="!h-[100px]"> + <div className="card !m-[1.2rem] max-h-[40rem] overflow-auto !p-0r"> + <Table> + <thead> + <TableRow> + <TableHead className="w-[120px]">{'시설명'}</TableHead> + <TableCell className="w-[300px]">{fcltyName}</TableCell> + <TableHead className="w-[120px]">{'년/월'}</TableHead> + <TableCell className=""> + <div className="flex"> + <DateMonthPicker + field={{ + value: startYmDate, + onChange: (value: string) => { + setStartYmDate(value); + } + }} + selectClass="ml-5 w-[100px]" + startYear={Number(searchYear)} // 시작 연도 설정 + /> + <h3 className="justify-center px-5">~</h3> + <DateMonthPicker + field={{ + value: endYmDate, + onChange: (value: string) => { + setEndYmDate(value); + } + }} + selectClass="ml-5 w-[100px]" + startYear={Number(searchYear)} // 시작 연도 설정 + /> + </div> + </TableCell> + </TableRow> + </thead> + </Table> + </div> + </ListDiv> + <div className="overflow-y-auto h-[500px]"> + <UiTable + headName={undefined} + tableData={copyYearList} + headlist={upHeadListUnderWaterDetail} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={() => {}} + className="h-[200px]" + boldArray={[0,1,2]} + /> + </div> + </TabsContent> + + <TabsContent value="tab_term_summer"> + {/* <FacilityTermModalHeader<UnderWaterInputModalProps> + searchList={gridListUnderWaterDetail} + fcltyCd={facilityCd} + fcltyName={fcltyName} + tabName="tab_term_summer" + searchYear={searchYear} + ref={ref} + queryClick={filterData} + /> */} + <ListDiv className="!h-[100px]"> + <div className="card !m-[1.2rem] max-h-[40rem] overflow-auto !p-0r"> + <Table> + <thead> + <TableRow> + <TableHead className="w-[120px]">{'시설명'}</TableHead> + <TableCell className="w-[300px]">{fcltyName}</TableCell> + <TableHead className="w-[120px]">{'년/월'}</TableHead> + <TableCell className=""> + <div className="flex"> + <DateMonthPicker + field={{ + value: startYmDate, + onChange: (value: string) => { + setStartYmDate(value); + } + }} + selectClass="ml-5 w-[100px]" + startYear={Number(searchYear)} // 시작 연도 설정 + /> + <h3 className="justify-center px-5">~</h3> + <DateMonthPicker + field={{ + value: endYmDate, + onChange: (value: string) => { + setEndYmDate(value); + } + }} + selectClass="ml-5 w-[100px]" + startYear={Number(searchYear)} // 시작 연도 설정 + /> + </div> + </TableCell> + </TableRow> + </thead> + </Table> + </div> + </ListDiv> + <div className="overflow-y-auto h-[500px]"> + <UiTable + headName={undefined} + tableData={copyYearList} + headlist={upHeadListUnderWaterDetail} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={() => { } } + className="h-[500px]" + boldArray={[0,1,2]} + /> + </div> + </TabsContent> + + <TabsContent value="tab_term_winter"> + <ListDiv className="!h-[100px]"> + <div className="card !m-[1.2rem] max-h-[40rem] overflow-auto !p-0r"> + <Table> + <thead> + <TableRow> + <TableHead className="w-[120px]">{'시설명'}</TableHead> + <TableCell className="w-[300px]">{fcltyName}</TableCell> + <TableHead className="w-[120px]">{'년/월'}</TableHead> + <TableCell className=""> + <div className="flex"> + <DateMonthPicker + field={{ + value: startYmDate, + onChange: (value: string) => { + setStartYmDate(value); + } + }} + selectClass="ml-5 w-[100px]" + startYear={Number(searchYear)} // 시작 연도 설정 + /> + <h3 className="justify-center px-5">~</h3> + <DateMonthPicker + field={{ + value: endYmDate, + onChange: (value: string) => { + setEndYmDate(value); + } + }} + selectClass="ml-5 w-[100px]" + startYear={Number(searchYear)} // 시작 연도 설정 + /> + </div> + </TableCell> + </TableRow> + </thead> + </Table> + </div> + </ListDiv> + <div className="overflow-y-auto h-[500px]"> + <UiTable + headName={undefined} + tableData={copyYearList} + headlist={upHeadListUnderWaterDetail} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={() => {}} + className="h-[500px]" + boldArray={[0,1,2]} + /> + </div> + </TabsContent> + </UITab> + </> + ); +} \ No newline at end of file diff --git a/apps/fo/app/pages/underWaterInput/page.tsx b/apps/fo/app/pages/underWaterInput/page.tsx new file mode 100644 index 000000000..1e821734b --- /dev/null +++ b/apps/fo/app/pages/underWaterInput/page.tsx @@ -0,0 +1,237 @@ +"use client" +import { useFoStore } from "@/app/store"; +import type { TableUpperProps } from "@/app/store/common"; +import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; +import ListDiv from "@common/business_components/ui/list_div"; +import { useCallback, useEffect, useRef, useState } from "react"; +import UnderWaterInputModal from "./modal/page"; +import type { UnderWaterProps } from "@/app/store/underWaterInput"; + +export default function UnderWaterInput() { + const {Common + ,UnderWater + ,UnderWaterSearch + ,initializeCommonData + ,searchUnderWaterList + } = useFoStore((state) => state) || { + Common: { isInit: false, selectUpdownData: [], selectOperationData: [], selectSidoData: [], selectSigunData: [], selectRegionData: [], selectUnitWaterShedData: [], selectMiddleRegionData: [], selectEnvPartData: [], selectSearchYear: [{ val: "0" }], btnClass: "" }, + UnderWater: { underWaterList: [], underWaterCount: 0, excelList: [], upHeadList1: [], upHeadList2: [], upHeadList3: [] }, + UnderWaterSearch: { labelArray: [] }, + initializeCommonData: () => {}, + searchUnderWaterList: () => {} + }; + + const { + isInit, + selectUpdownData, + selectOperationData, + selectSidoData, + selectSigunData, + selectRegionData, + selectUnitWaterShedData, + selectMiddleRegionData, + selectEnvPartData, + selectSearchYear, + btnClass + } = Common; + + const { + labelArray, + } = UnderWaterSearch; + + const { + upHeadList1, + upHeadList2, + upHeadList3, + underWaterList, + underWaterCount, + excelList, + } = UnderWater; + + const ref = useRef<ReturnType>({ + partValue: '', + sidoValue: '', + sigunValue: '', + regionValue: '', + unitWaterShedValue: '', + middleRegionValue: '', + envPartValue: '', + sidoText: '', + sigunText: '' + }); + + const underWater = UnderWater?.underWaterList || []; + + // 모달 상태 추가 + const [selectedRow, setSelectedRow] = useState<number | null>(null); + const [fcltyNm, setFcltyNm] = useState<string>(""); + + // 그리드 관련 + const searchInputRef = useRef<HTMLDivElement & HTMLInputElement>(null); + + // 초기화 변수 + const [resetPage, setResetPage] = useState<boolean>(false); + // 표 너비 + const [widthSize, setWidthSize] = useState<string>("w-[120%]"); + // 구분별 그리드 헤더 + const [upheadList, setUpheadList] = useState<TableUpperProps[]>(upHeadList1); + // 용량별 + const [fcltCpct, setFcltCpct] = useState<string>("0"); + // 시설명 + const [fcltyName, setFcltyName] = useState<string>(""); + // 시설상태 + const [operationValue, setOperationValue] = useState<string>("0"); + // 조회기간 + const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || "0"); + + /** + * 페이지 함수 + */ + // 초기화 + const resetVal = () => { + setWidthSize("w-[120%]"); + setUpheadList(upHeadList1) + // 상태값 설정 + setFcltCpct(selectUpdownData[0]?.val || "0"); + setOperationValue(selectOperationData[0]?.val || "0"); + setSearchYear(selectSearchYear[0]?.val || "0"); + // SearchInputSelect 초기화 + setFcltyName(""); + if (searchInputRef.current) { + const input = searchInputRef.current.querySelector('input'); + if (input) { + input.value = ""; + } + } + searchUnderWaterList(1, 10, selectSearchYear[0]?.val || "0"); + } + + // 모달 닫기 + const closeModal = () => { + setSelectedRow(null); + }; + + // 셀 클릭 시 모달 표시 + const cellClick = (index: number) => { + if (underWater[index]) { + setFcltyNm(underWater[index].bscFctNm); + setSelectedRow(index); // 클릭한 행의 index 저장 + } + }; + + /** + * useEffect + */ + useEffect(() => { + if (!isInit) { + initializeCommonData(); + searchUnderWaterList(1, 10, selectSearchYear[0]?.val || "0"); + } + }, [isInit, initializeCommonData, searchUnderWaterList, selectSearchYear]); + + useEffect(() => { + if (excelList && excelList.length > 0) { + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: '지하수유입량 추정', + sheetNameArray: ['지하수유입량 추정'], + headerRange: 'A1:V1' + }); + } + }, [excelList]); + + /** + * 콜백함수 + */ + // 조회 + const searchFacilityPrecipitation = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { + let nameCd, partStr + switch (partValue) { + case 'R': + if (regionValue !== '0') { + if(unitWaterShedValue==='0') nameCd = regionValue; + else if (middleRegionValue==='0') nameCd = unitWaterShedValue; + else nameCd = middleRegionValue; + } + partStr = partValue + break; + default: + if(sidoValue !== '0') nameCd = sidoValue; + if(sigunValue !== '0') nameCd = sigunValue; + partStr = envPartValue !== '0' ? envPartValue:partValue; + break; + } + if (partStr.length > 1 || fcltCpct !== '0' || operationValue!== '0' ||nameCd ||(fcltyName.trim() !== "" && fcltyName.trim() !== null)) { + searchUnderWaterList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); + } else { + searchUnderWaterList(pageNo, pageCnt, searchYear); + } + }, [fcltCpct, operationValue, fcltyName, searchUnderWaterList, searchYear]); + + const chkVal = useCallback((returntype:ReturnType) => { + setWidthSize(returntype.partValue=='A' ?"w-[120%]":"w-[130%]") + setUpheadList(returntype.partValue == 'R' ? upHeadList2 : returntype.partValue == 'G'?upHeadList3:upHeadList1); + setResetPage(true); + }, [upHeadList1, upHeadList2, upHeadList3]); + + // 엑셀다운로드 + const excelDownload = useCallback(() => { + searchFacilityPrecipitation(ref.current, 1, 10000); + }, [searchFacilityPrecipitation]); + + // 페이지 변경 + const handlePageChange = useCallback((page: number) => { + setResetPage(false); + searchFacilityPrecipitation(ref.current, page, 10); + }, [searchFacilityPrecipitation]); + + const mainList: UnderWaterProps[] = underWaterList || []; + const total = underWaterCount || 0; + + return ( + <MainDiv> + <Title title="지하수유입량 추정" /> + <ContentsDiv> + <SearchBaseForm + leftChildren={<> + <SelectBox className="col-span-3" label={labelArray[3] as string} selectArray={selectUpdownData} onSelectValue={(val) => setFcltCpct(val.toString())} value={fcltCpct} selectClass={undefined} /> + <SearchInput className={"col-span-3"} label={labelArray[4] as string} textValue={fcltyName} setText={setFcltyName} /> + <SelectBox className="col-span-3" label={labelArray[5] as string} selectArray={selectSearchYear} onSelectValue={(val) => setSearchYear(val.toString())} value={searchYear} selectClass={undefined} /> + <SelectBox className="col-span-3" label={labelArray[6] as string} selectArray={selectOperationData} onSelectValue={(val) => setOperationValue(val.toString())} value={operationValue} selectClass={undefined} /> + </>} + rightChildren={undefined} + selectSidoData={selectSidoData} + selectSigunData={selectSigunData} + selectRegionData={selectRegionData} + selectUnitWaterShedData={selectUnitWaterShedData} + selectMiddleRegionData={selectMiddleRegionData} + selectEnvPartData={selectEnvPartData} + btnClass={btnClass} + queryClick={chkVal} + excelClick={excelDownload} + initClick={resetVal} + ref={ref} + isAdmin={false} + /> + <ListDiv> + <div className="h-full w-full overflow-x-scroll"> + <div className={widthSize}> + <UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"지하수유입량 추정"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} /> + </div> + </div> + <span className="text-2xl text-gray-500">※지하수 유입량 = 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율)</span> + </ListDiv> + </ContentsDiv> + {selectedRow !== null && ( + <UiModal + body={<UnderWaterInputModal fcltyName={fcltyNm} searchYear={searchYear}></UnderWaterInputModal>} + bodyClass="sm:max-w-[90vw] w-[1000px] h-[770px]" + open={selectedRow !== null} + onOpenChange={(open) => !open && closeModal()} + noHeaderYn="Y" + noFooterYn="Y" + /> + )} + </MainDiv> + ); +} \ No newline at end of file diff --git a/apps/fo/app/store/common/index.tsx b/apps/fo/app/store/common/index.tsx new file mode 100644 index 000000000..df1126195 --- /dev/null +++ b/apps/fo/app/store/common/index.tsx @@ -0,0 +1,375 @@ +/**==================================== + * 보편적으로 쓰는 store 공간 + ====================================**/ + +import { getFetch } from "@/app/components/api"; + +/** + * STORE - TYPE + */ + +// selectBox +export type SelectDataType = { + text: string; + val: string; +} +// grid header +export type TableUpperProps = { + id: string; + title: string; + upName?: string; + upSequnce?: number; +} + +// 시도 데이터 +export type sidoDataType = { + adstDstrCd: number, + sido: string, +} + +// 시군구 데이터 +export type sigunDataType = { + adstDstrCd: number, + gugun: string +} + +// 권역 데이터 +export type regionDataType = { + rvbsnCd: string, + rvbsn: string, +} + +// 단위유역 데이터 +export type unitWaterShedDataType = { + rvbsnCd: string, + lgbsn: string, +} + +// 중권역 데이터 +export type middleRegionDataType = { + rvbsnCd: string, + mdmbsn: string, +} + +// 환경청 데이터 +export type envPartDataType = { + lclgvrnmntCd: string, + lclgvrnmntNm: string, + adstDliStrCd: string, + adstDstrCd: string, +} + +export type envPartSelectDataType = SelectDataType & { + adstDliStrCd: string, +} + +/** + * STORE - DATA + */ + +// 시도 데이터 +let selectSidoData: SelectDataType[] = [ + { text: "전체", val: '0' } +]; + +// 시군구 데이터 +let selectSigunData: SelectDataType[] = [ + { text: "전체", val: '0' } +]; + +// 권역 데이터 +const selectRegionData: SelectDataType[] = [ + { text: "전체", val: '0' } +]; + +// 단위유역 데이터 +const selectUnitWaterShedData: SelectDataType[] = [ +]; + +// 환경청 데이터 +let selectEnvPartData: envPartSelectDataType[] = [ + { text: "전체", val: '0', adstDliStrCd: '' } +]; + +// 환경청 내 시도 데이터 +const selectEnvPartSidoData: SelectDataType[] = [ + { text: "전체", val: '0' } +]; + +// 환경청 내 시군구 데이터 +const selectEnvPartSigunData: SelectDataType[] = [ + { text: "전체", val: '0' } +]; + +// 구분 데이터 +// const selectPartData:SelectDataType[] = [ +// { text: "행정별", val: '0' }, +// { text: "유역별", val: '01' }, +// { text: "환경청별", val: '02' }, +// ]; + +// 상향 하향 데이터 +const selectUpdownData:SelectDataType[] = [ + { text: "전체", val: '0' }, + { text: "500이하", val: '400' }, + { text: "500이상", val: '500' }, +]; + +// 운영 상태 데이터 +const selectOperationData:SelectDataType[] = [ + { text: "전체", val: '0' }, + { text: "가동중", val: '1' }, + { text: "재가동", val: '2' }, + { text: "가동중지", val: '3' }, + { text: "시설폐쇄", val: '4' }, +]; + +// 시설 구분 데이터 +const selectFacilityPartData:SelectDataType[] = [ + { text: "전체", val: '0' }, + { text: "공공하수처리시설", val: 'SW' }, + { text: "오수처리장", val: 'SS' }, + { text: "개인하수처리시설", val: 'PB' }, + { text: "분뇨처리장", val: 'NS' }, + { text: "폐수처리장", val: 'LW' }, + { text: "침출수처리장", val: 'LC' }, + { text: "기타기초시설", val: 'ET' }, +]; + +// 년도 데이터 +const getYearData = () => { + const year = new Date().getFullYear(); + const year1 = year - 1; + const year2 = year - 2; + const year3 = year - 3; + const year4 = year - 4; + const year5 = year - 5; + return [ + { text: year1 + "년", val: year1.toString() }, + { text: year2 + "년", val: year2.toString() }, + { text: year3 + "년", val: year3.toString() }, + { text: year4 + "년", val: year4.toString() }, + { text: year5 + "년", val: year5.toString() }, + ] +} + +const selectSearchYear:SelectDataType[] = getYearData(); + +// 유량 기간 구분 +const selectFlowTerm : SelectDataType[] = [ + { text: "연간", val: '0' }, + { text: "하절기", val: '01' }, + { text: "동절기", val: '02' }, + { text: "청천시", val: '03' }, + { text: "강우시", val: '04' }, +]; + +// 유량 기간 구분 +const selectFlowPanel : SelectDataType[] = [ + { text: "전체", val: '0'}, + { text: "3mm미만", val: '1'}, + { text: "3~10mm미만", val: '2'}, + { text: "10~20mm미만", val: '3'}, + { text: "20~30mm미만", val: '4'}, + { text: "30~40mm미만", val: '5'}, + { text: "40~50mm미만", val: '6'}, + { text: "50~60mm미만", val: '7'}, + { text: "60mm이상", val: '8'}, +]; + +// 중권역 데이터 +const selectMiddleRegionData: SelectDataType[] = [ + { text: "전체", val: '0' } +]; + +/** + * STORE - API + */ + +// 시도 API 호출 함수 추가 +const fetchSidoData = async (): Promise<SelectDataType[]> => { + try { + const res = await getFetch('fo', '/addr/city'); + const data = res.data; + selectSidoData = [ + { text: "전체", val: '0'}, + ...data.map((item: sidoDataType) => ({ + text: item.sido || '', + val: String(item.adstDstrCd) || '' + })) + ]; + return selectSidoData; + } catch (error) { + console.error('시도 데이터를 가져오는데 실패했습니다:', error); + return selectSidoData; + } +}; + +// 시군구 API 호출 함수 추가 +const fetchSigunData = async (): Promise<SelectDataType[]> => { + try { + const res = await getFetch('fo', '/addr/sgg'); + const data = res.data; + selectSigunData = [ + { text: "전체", val: '0' }, + ...data + .map((item: sigunDataType) => ({ + text: item.gugun || '', + val: String(item.adstDstrCd) || '' + })) + ]; + return selectSigunData; + } catch (error) { + console.error('시군구 데이터를 가져오는데 실패했습니다:', error); + return selectSigunData; + } +}; + +// 권역 API 호출 함수 추가 +const fetchRegionData = async (): Promise<SelectDataType[]> => { + try { + const res = await getFetch('fo', '/addr/sarea'); + const data = res.data; + return [ + { text: "전체", val: '0'}, + ...data.map((item: regionDataType) => ({ + text: item.rvbsn || '', + val: String(item.rvbsnCd) || '' + })) + ]; + } catch (error) { + console.error('권역 데이터를 가져오는데 실패했습니다:', error); + return selectRegionData; + } +}; + +// 중권역 API 호출 함수 추가 +const fetchMiddleRegionData = async (): Promise<SelectDataType[]> => { + try { + const res = await getFetch('fo', '/addr/midArea'); + const data = res.data; + return [ + { text: "전체", val: '0' }, + ...data + .map((item: middleRegionDataType) => ({ + text: item.mdmbsn || '', + val: String(item.rvbsnCd) || '' + })) + ]; + } catch (error) { + console.error('중권역 데이터를 가져오는데 실패했습니다:', error); + return selectMiddleRegionData; + } +}; + +// 단위유역 API 호출 함수 추가 +const fetchUnitWaterShedData = async (): Promise<SelectDataType[]> => { + try { + const res = await getFetch('fo', '/addr/largeArea'); + const data = res.data; + return [ + { text: "전체", val: '0' }, + ...data + .map((item: unitWaterShedDataType) => ({ + text: item.lgbsn || '', + val: String(item.rvbsnCd) || '' + })) + ]; + } catch (error) { + console.error('단위유역 데이터를 가져오는데 실패했습니다:', error); + return selectUnitWaterShedData; + } +}; + +// 환경청 데이터 +const fetchEnvPartData = async (): Promise<envPartSelectDataType[]> => { + try { + const res = await getFetch('fo', '/addr/govArea'); + const data = res.data; + selectEnvPartData = [ + { text: "전체", val: '0', adstDliStrCd: '' }, + ...data + .map((item: envPartDataType) => ({ + text: item.lclgvrnmntNm || '', + val: String(item.lclgvrnmntCd) || '', + adstDliStrCd: item.adstDliStrCd || '' + })) + ]; + return selectEnvPartData; + } catch (error) { + console.error('환경청 데이터를 가져오는데 실패했습니다:', error); + return selectEnvPartData; + } +}; + +/**==================================== + * Store - expaort + ====================================*/ +export type CommonAction = { + initializeCommonData: () => Promise<void>; +} + +export type CommonType = { + Common: { + isInit: boolean; + selectSidoData: SelectDataType[]; + selectSigunData: SelectDataType[]; + selectUpdownData: SelectDataType[]; + selectOperationData: SelectDataType[]; + selectFacilityPartData: SelectDataType[]; + selectSearchYear: SelectDataType[]; + selectUnitWaterShedData: SelectDataType[]; + selectRegionData: SelectDataType[]; + selectMiddleRegionData: SelectDataType[]; + selectEnvPartSidoData: SelectDataType[]; + selectEnvPartSigunData: SelectDataType[]; + selectFlowTerm: SelectDataType[]; + selectFlowPanel: SelectDataType[]; + selectEnvPartData: envPartSelectDataType[]; + btnClass: string; + } +} + +export const commonState:CommonType = { + Common: { + isInit: false, + selectSidoData: selectSidoData, + selectSigunData: selectSigunData, + selectUpdownData: selectUpdownData, + selectOperationData: selectOperationData, + selectFacilityPartData: selectFacilityPartData, + selectSearchYear: selectSearchYear, + selectRegionData: selectRegionData, + selectUnitWaterShedData: selectUnitWaterShedData, + selectMiddleRegionData: selectMiddleRegionData, + selectEnvPartSidoData : selectEnvPartSidoData, + selectEnvPartSigunData : selectEnvPartSigunData, + selectFlowTerm: selectFlowTerm, + selectFlowPanel: selectFlowPanel, + selectEnvPartData : selectEnvPartData, + btnClass: "p-4 m-2 text-white rounded-sm text-lg font-medium" + } +} + +export const CommonReducer:(set:(fn: (state: CommonType) => CommonType) => void)=>CommonAction=(set: (fn: (state: CommonType) => CommonType) => void) => { + return { + // 시도 변경 이벤트 + initializeCommonData: async () => { + const promiseSet = await Promise.all([fetchSidoData(), fetchSigunData(), fetchRegionData(), fetchUnitWaterShedData(), fetchMiddleRegionData(), fetchEnvPartData()]); + const [sidoData, sggData, regionData, unitData, midData, envData] = promiseSet; + set((state: CommonType) => ({ + Common: { + ...state.Common, + selectSidoData: sidoData, + selectSigunData: sggData, + selectRegionData: regionData, + selectMiddleRegionData: midData, + selectUnitWaterShedData: unitData, + selectEnvPartData: envData + } + })) + }, + } +} + +export type CommonStore = CommonType & CommonAction; diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx new file mode 100644 index 000000000..8b04da6ff --- /dev/null +++ b/apps/fo/app/store/dashboard/index.tsx @@ -0,0 +1,1866 @@ +/** + * Store - 타입 + */ + +import { getFetch, getFetchAreaList } from "@/app/components/api"; +import DataForm from "@/app/components/common/DataForm"; +import type { FacilityWaterQltyProps } from "../facilityWaterQlty"; + +// selectBox +export type SelectDataType = { + text: string; + val: string; +} + +// grid header +export type TableUpperProps = { + id: string; + title: string; + upName?: string; + upSequnce?: number; + align? : string; + row? : number; + rowSpan?: number; + colSpan?: number; +} + +// ===TAB1 +// main fclty +export type mainFcltyProps = { + fcltyNm : string, + facilityCapacity : string, + publicMethod : string, + location : string +} + +// 시설계획 +export type planFcltyListProps = { + item : string, + provisionalApproval : string | number | '', + now : string | number | '', + stepOne : string | number | '', + stepTwo : string | number | '', + stepThree : string | number | '', + stepFour : string | number | '', +} + +// 운영실태 +export type OperationalStatusListProps = { + flowRate : string, + waterQlty : string, + yearAvg : number | string | '', + yearMax : number | string | '', + yearMin : number | string | '', + summerAll : number | string | '', + summerThree : number | string | '', + summerRain : number | string | '', + winterAll : number | string | '', + winterSunnyAvg : number | string | '', + winterSunnyMax : number | string | '', + winterSunnyMin : number | string | '', + groundWaterAvg : number | string | '', + groundWaterSummer : number | string | '', + groundWaterWinter : number | string | '', + rdi : number | string | '', + rdiRain : number | string | '', +} + +export interface operationalStatusListProps { + flowRate : string, + waterQlty : string, + yearAvg : number | '', + yearMax : number | '', + yearMin : number | '', + summerAll : number | '', + summerThree : number | '', + summerRain : number | '', + winterAll : number | '', + winterSunnyAvg : number | '', + winterSunnyMax : number | '', + winterSunnyMin : number | '', + groundWaterAvg : number | string | '', + groundWaterSummer : number | string | '', + groundWaterWinter : number | string | '', + rdi : number | '', +} + +// 차트 +export type lineBarChartDataProps = { + label : string, + lineVal : number + barVal : number + barVal0 : number + barVal1 : number + lineVal0 : number + lineVal1 : number +} + +export type lineChartDataProps = { + label : string, + val : number +} + +export interface RainManageListProps { + rainItem : string, + rainRate : string, + rainDay : number, + bscFctCd?: string, + bscFctNm?: string, + msrDt?: string + sidoNm?: string, + sggNm?: string, + addr?: string, + fctCpc?: number, + inflAssctAftWqltBod: number | '', + inflAssctAftWqltToc: number | '', + inflAssctAftWqltSs: number | '', + inflAssctAftWqltTn: number | '', + inflAssctAftWqltTp: number | '', + efflWqltBod: number | '', + efflWqltCod: number | '', + efflWqltSs: number | '', + efflWqltTn: number | '', + efflWqltTp: number | '', + rgnNm?:string|'', + rvbsn?:string|'', + lgbsn?:string|'', + mdmbsn?:string|'', + inflAmnt: number | '', + lclgvrnmntNm?: string, + infoRnDay?: number | '', + tpInflWqltTmprtr?: number | '', + tpInflWqltPh?: number | '', + tpInflWqltBod?: number | '', + tpInflWqltCod?: number | '', + tpInflWqltSs?: number | '', + tpInflWqltTn?: number | '', + tpInflWqltTp?: number | '', + tpInflWqltEclgyTox?: number | '', + tpInflWqltClfgrpcnt?: number | '', + dsInflWqltBod: number | '', + dsInflWqltCod: number | '', + dsInflWqltSs: number | '', + dsInflWqltTn: number | '', + dsInflWqltTp: number | '', + extnsSeqno?: number | '', +} + +export interface RainManageExcelType { + 강우량: string, + 강우조건비율: number | '', + 일수: number | '', + 유입유량: number | '', + 시설용량대비: number | '', + 설계유입수질BOD: number | '', + 설계유입수질TOC: number | '', + 설계유입수질SS: number | '', + 설계유입수질TN: string | number | '', + 설계유입수질TP: string | number | '', + 유입수질BOD: number | '', + 유입수질TOC: number | '', + 유입수질SS: number | '', + 유입수질TN: string | number | '', + 유입수질TP: string | number | '', + 방류수질BOD: number | '', + 방류수질TOC: number | '', + 방류수질SS: number | '', + 방류수질TN: string | number | '', + 방류수질TP: string | number | '', +} + +export interface DrainageEquipmentListProps { + part1 : string | '', + part2 : string | '', + nowSum : number | '', + nowJoin : number | '', + nowSep : number | '', + stepOneSum : number | '', + stepOneJoin : number | '', + stepOneSep : number | '', + stepTwoSum : number | '', + stepTwoJoin : number | '', + stepTwoSep : number | '', + stepThreeSum : number | '', + stepThreeJoin : number | '', + stepThreeSep : number | '', + stepFourSum : number | '', + stepFourJoin : number | '', + stepFourSep : number | '', + etc : string | '', +} + +export interface DrainageEquipmentExcelType { + partOne : string | '', + partTwo : string | '', + nowSum : number | '', + nowJoin : number | '', + nowSep : number | '', + stepOneSum : number | '', + stepOneJoin : number | '', + stepOneSep : number | '', + stepTwoSum : number | '', + stepTwoJoin : number | '', + stepTwoSep : number | '', + stepThreeSum : number | '', + stepThreeJoin : number | '', + stepThreeSep : number | '', + stepFourSum : number | '', + stepFourJoin : number | '', + stepFourSep : number | '', +} + +/** + * Store - data + */ +// Main +const DashBoardTopLabelArray:string[] = ['구분', '시도', '시군구', '년도', '시설명']; + +// === Tab1 +// grid header +const upHeadListFclty:TableUpperProps[] = [ + { id : "fcltyNm", title : "시설명"}, + { id : "facilityCapacity", title : "시설용량(m³/일)"}, + { id : "publicMethod", title : "공법"}, + { id : "location", title : "지역구"}, +] + +const fcltyList : mainFcltyProps[] = [ +] + +let planYearList : string[] = [ + "2021", + "2022", + "2023", + "2024", + "2025", + "2026" +] + +const upHeadListPlanFclty : TableUpperProps[] = [ + { id: "item", title: "", upName:"upChangeRe", upSequnce:1 }, + { id: "provisionalApproval", title: "기승인\n4단계", upName:"upChangeRe", upSequnce:2 }, + { id: "now", title: "현재", upName:"upChangeRe", upSequnce:3 }, + { id: "stepOne", title: "1단계", upName:"upChangeRe", upSequnce:4 }, + { id: "stepTwo", title: "2단계", upName:"upChangeRe", upSequnce:5 }, + { id: "stepThree", title: "3단계", upName:"upChangeRe", upSequnce:6 }, + { id: "stepFour", title: "4단계", upName:"upChangeRe", upSequnce:7 }, +] + +const planFcltyList:planFcltyListProps[] = [ + { + item : "1.증설계획\n(㎥/일)", + provisionalApproval: "", + now: "", + stepOne: "", + stepTwo: "", + stepThree: "", + stepFour : "", + }, + { + item : "2.처리인구(인)", + provisionalApproval: "", + now: "", + stepOne: "", + stepTwo: "", + stepThree: "", + stepFour : "", + }, + { + item : "3.처리구역\n(km²)", + provisionalApproval: "", + now: "", + stepOne: "", + stepTwo: "", + stepThree: "", + stepFour : "", + }, + { + item : "4.분류식화율\n(%)", + provisionalApproval: "", + now: "", + stepOne: "", + stepTwo: "", + stepThree: "", + stepFour : "", + }, + { + item : "5.물사용량", + provisionalApproval: "", + now: "", + stepOne: "", + stepTwo: "", + stepThree: "", + stepFour : "", + }, + { + item : "년도\n(최근 3개년)", + provisionalApproval: "물사용량\n(㎥/일)", + now: "", + stepOne: "", + stepTwo: "비고", + stepThree: "", + stepFour : "", + }, + { + item : "2021", + provisionalApproval: "", + now: "", + stepOne: "", + stepTwo: "", + stepThree: "", + stepFour : "", + }, + { + item : "2022", + provisionalApproval: "", + now: "", + stepOne: "", + stepTwo: "", + stepThree: "", + stepFour : "", + }, + { + item : "2023", + provisionalApproval: "", + now: "", + stepOne: "", + stepTwo: "", + stepThree: "", + stepFour : "", + }, +] + +const upHeadListOperationStatus : TableUpperProps[] = [ + { id: "flowRate", title: "유량 및 수질", upName:"upChangeRe1", upSequnce:1 }, + { id: "waterQlty", title: "유량 및 수질", upName:"upChangeRe1", upSequnce:2 }, + { id: "yearAvg", title: "평균", upName:"upChangeRe2", upSequnce:1 }, + { id: "yearMax", title: "최대", upName:"upChangeRe2", upSequnce:2 }, + { id: "yearMin", title: "최소", upName:"upChangeRe2", upSequnce:3 }, + { id: "summerAll", title: "전기간", upName:"upChangeRe3", upSequnce:1 }, + { id: "summerThree", title: "강우시\n(3mm이상)", upName:"upChangeRe3", upSequnce:2 }, + { id: "summerRain", title: "청천시", upName:"upChangeRe3", upSequnce:3 }, + { id: "winterAll", title: "전기간", upName:"upChangeRe4", upSequnce:1 }, + { id: "winterSunnyAvg", title: "청천시\n평균", upName:"upChangeRe4", upSequnce:2 }, + { id: "winterSunnyMax", title: "청천시\n최대", upName:"upChangeRe4", upSequnce:3 }, + { id: "winterSunnyMin", title: "청천시\n최소", upName:"upChangeRe4", upSequnce:4 }, + { id: "groundWaterAvg", title: "연평균", upName:"upChangeRe5", upSequnce:1 }, + { id: "groundWaterSummer", title: "하절기\n평균", upName:"upChangeRe5", upSequnce:2 }, + { id: "groundWaterWinter", title: "동절기\n평균", upName:"upChangeRe5", upSequnce:3 }, + { id: "rdi", title: "RDII 추정" }, +] + +const upHeadListRainManage : TableUpperProps[] = [ + { id: "rainItem", title: "강우량", row:0, rowSpan:2 }, + { id: "rainRate", title: "강우조건\n비율(%)", row:0, rowSpan:2 }, + { id: "rainDay", title: "일수", row:0, rowSpan:2 }, + { id: "A", title: "유입(㎥/일)", row:0, colSpan:2 }, + { id: "inflAmnt", title: "유입유량", row:1 }, + { id: "fctCpc", title: "시설용량대비", row:1 }, + { id: "B", title: "설계유입수질(㎎/L)", row:0, colSpan:5 }, + { id: "dsInflWqltBod", title: "BOD", row:1 }, + { id: "dsInflWqltCod", title: "TOC\n(COD)", row:1 }, + { id: "dsInflWqltSs", title: "SS", row:1 }, + { id: "dsInflWqltTn", title: "T-N", row:1 }, + { id: "dsInflWqltTp", title: "T-P", row:1 }, + { id: "C", title: "유입수질(㎎/L)", row:0, colSpan:5 }, + { id: "inflAssctAftWqltBod", title: "BOD", row:1 }, + { id: "inflAssctAftWqltToc", title: "TOC\n(COD)", row:1 }, + { id: "inflAssctAftWqltSs", title: "SS", row:1 }, + { id: "inflAssctAftWqltTn", title: "T-N", row:1 }, + { id: "inflAssctAftWqltTp", title: "T-P", row:1 }, + { id: "D", title: "방류수질(㎎/L)", row:0, colSpan:5 }, + { id: "efflWqltBod", title: "BOD", row:1 }, + { id: "efflWqltCod", title: "TOC\n(COD)", row:1 }, + { id: "efflWqltSs", title: "SS", row:1 }, + { id: "efflWqltTn", title: "T-N", row:1 }, + { id: "efflWqltTp", title: "T-P", row:1 }, +] + +const upHeadListDrainageEquipment : TableUpperProps[] = [ + { id: "part1", title: "구분", row:0, upName:"upChangeRe1", upSequnce:1 }, + { id: "part2", title: "구분", row:0, upName:"upChangeRe1", upSequnce:2 }, + { id: "nowSum", title: "계", row:2, upName:"upChangeRe2", upSequnce:1 }, + { id: "nowJoin", title: "합류식\n가구수", row:2, upName:"upChangeRe2", upSequnce:2 }, + { id: "nowSep", title: "분리식\n가구수", row:2, upName:"upChangeRe2", upSequnce:3 }, + { id: "stepOneSum", title: "계", row:2, upName:"upChangeRe3", upSequnce:1 }, + { id: "stepOneJoin", title: "합류식\n가구수", row:2, upName:"upChangeRe3", upSequnce:2 }, + { id: "stepOneSep", title: "분리식\n가구수", row:2, upName:"upChangeRe3", upSequnce:3 }, + { id: "stepTwoSum", title: "계", row:2, upName:"upChangeRe4", upSequnce:1 }, + { id: "stepTwoJoin", title: "합류식\n가구수", row:2, upName:"upChangeRe4", upSequnce:2 }, + { id: "stepTwoSep", title: "분리식\n가구수", row:2, upName:"upChangeRe4", upSequnce:3 }, + { id: "stepThreeSum", title: "계", row:2, upName:"upChangeRe5", upSequnce:1 }, + { id: "stepThreeJoin", title: "합류식\n가구수", row:2, upName:"upChangeRe5", upSequnce:2 }, + { id: "stepThreeSep", title: "분리식\n가구수", row:2, upName:"upChangeRe5", upSequnce:3 }, + { id: "stepFourSum", title: "계", row:2, upName:"upChangeRe6", upSequnce:1 }, + { id: "stepFourJoin", title: "합류식\n가구수", row:2, upName:"upChangeRe6", upSequnce:2 }, + { id: "stepFourSep", title: "분리식\n가구수", row:2, upName:"upChangeRe6", upSequnce:3 }, + { id: "etc", title: "비고", row:0, upName:"upChangeRe7", upSequnce:1 }, +] + +const operationalStatusList : OperationalStatusListProps[] = [ + { + flowRate : '유량\n(㎥/일)', + waterQlty : '유입', + yearAvg : '', + yearMax : '', + yearMin : '', + summerAll : '', + summerThree : '', + summerRain : '', + winterAll : '', + winterSunnyAvg : '', + winterSunnyMax : '', + winterSunnyMin : '', + groundWaterAvg : '', + groundWaterSummer : '', + groundWaterWinter : '', + rdi : '', + rdiRain : '', + }, + { + flowRate : '유량\n(㎥/일)', + waterQlty : '순수하수', + yearAvg : '', + yearMax : '', + yearMin : '', + summerAll : '', + summerThree : '', + summerRain : '', + winterAll : '', + winterSunnyAvg : '', + winterSunnyMax : '', + winterSunnyMin : '', + groundWaterAvg : '', + groundWaterSummer : '', + groundWaterWinter : '', + rdi : '', + rdiRain : '', + }, + { + flowRate : '유량\n(㎥/일)', + waterQlty : '연계처리수', + yearAvg : '', + yearMax : '', + yearMin : '', + summerAll : '', + summerThree : '', + summerRain : '', + winterAll : '', + winterSunnyAvg : '', + winterSunnyMax : '', + winterSunnyMin : '', + groundWaterAvg : '', + groundWaterSummer : '', + groundWaterWinter : '', + rdi : '', + rdiRain : '', + }, + { + flowRate : '유량\n(㎥/일)', + waterQlty : '총인설비\n반류수', + yearAvg : '', + yearMax : '', + yearMin : '', + summerAll : '', + summerThree : '', + summerRain : '', + winterAll : '', + winterSunnyAvg : '', + winterSunnyMax : '', + winterSunnyMin : '', + groundWaterAvg : '', + groundWaterSummer : '', + groundWaterWinter : '', + rdi : '', + rdiRain : '', + }, + { + flowRate : '유량\n(㎥/일)', + waterQlty : '방류', + yearAvg : '', + yearMax : '', + yearMin : '', + summerAll : '', + summerThree : '', + summerRain : '', + winterAll : '', + winterSunnyAvg : '', + winterSunnyMax : '', + winterSunnyMin : '', + groundWaterAvg : '', + groundWaterSummer : '', + groundWaterWinter : '', + rdi : '', + rdiRain : '', + }, + { + flowRate : '수질\n(mg/L)', + waterQlty : '유입\n(BOD)', + yearAvg : '', + yearMax : '', + yearMin : '', + summerAll : '', + summerThree : '', + summerRain : '', + winterAll : '', + winterSunnyAvg : '', + winterSunnyMax : '', + winterSunnyMin : '', + groundWaterAvg : '', + groundWaterSummer : '', + groundWaterWinter : '', + rdi : '', + rdiRain : '', + }, + { + flowRate : '수질\n(mg/L)', + waterQlty : '방류\n(BOD)', + yearAvg : '', + yearMax : '', + yearMin : '', + summerAll : '', + summerThree : '', + summerRain : '', + winterAll : '', + winterSunnyAvg : '', + winterSunnyMax : '', + winterSunnyMin : '', + groundWaterAvg : '', + groundWaterSummer : '', + groundWaterWinter : '', + rdi : '', + rdiRain : '', + }, + { + flowRate : '수질\n(mg/L)', + waterQlty : '유입\n(T-N)', + yearAvg : '', + yearMax : '', + yearMin : '', + summerAll : '', + summerThree : '', + summerRain : '', + winterAll : '', + winterSunnyAvg : '', + winterSunnyMax : '', + winterSunnyMin : '', + groundWaterAvg : '', + groundWaterSummer : '', + groundWaterWinter : '', + rdi : '', + rdiRain : '', + }, + { + flowRate : '수질\n(mg/L)', + waterQlty : '방류\n(T-N)', + yearAvg : '', + yearMax : '', + yearMin : '', + summerAll : '', + summerThree : '', + summerRain : '', + winterAll : '', + winterSunnyAvg : '', + winterSunnyMax : '', + winterSunnyMin : '', + groundWaterAvg : '', + groundWaterSummer : '', + groundWaterWinter : '', + rdi : '', + rdiRain : '', + }, + { + flowRate : '수질\n(mg/L)', + waterQlty : '유입\n(T-P)', + yearAvg : '', + yearMax : '', + yearMin : '', + summerAll : '', + summerThree : '', + summerRain : '', + winterAll : '', + winterSunnyAvg : '', + winterSunnyMax : '', + winterSunnyMin : '', + groundWaterAvg : '', + groundWaterSummer : '', + groundWaterWinter : '', + rdi : '', + rdiRain : '', + }, + { + flowRate : '수질\n(mg/L)', + waterQlty : '방류\n(T-P)', + yearAvg : '', + yearMax : '', + yearMin : '', + summerAll : '', + summerThree : '', + summerRain : '', + winterAll : '', + winterSunnyAvg : '', + winterSunnyMax : '', + winterSunnyMin : '', + groundWaterAvg : '', + groundWaterSummer : '', + groundWaterWinter : '', + rdi : '', + rdiRain : '', + }, + { + flowRate : '총인\n시설\n수질\n(mg/L)', + waterQlty : '총인설비\n유입(T-P)', + yearAvg : '', + yearMax : '', + yearMin : '', + summerAll : '', + summerThree : '', + summerRain : '', + winterAll : '', + winterSunnyAvg : '', + winterSunnyMax : '', + winterSunnyMin : '', + groundWaterAvg : '', + groundWaterSummer : '', + groundWaterWinter : '', + rdi : '', + rdiRain : '', + }, + { + flowRate : '총인\n시설\n수질\n(mg/L)', + waterQlty : '총인설비\n방류(T-P)', + yearAvg : '', + yearMax : '', + yearMin : '', + summerAll : '', + summerThree : '', + summerRain : '', + winterAll : '', + winterSunnyAvg : '', + winterSunnyMax : '', + winterSunnyMin : '', + groundWaterAvg : '', + groundWaterSummer : '', + groundWaterWinter : '', + rdi : '', + rdiRain : '', + }, +] + +const chart_inflowRain : lineBarChartDataProps[] = []; +const chart_bodRain : lineBarChartDataProps[] = []; +const chart_inflTp : lineChartDataProps[] = []; +const chart_chongInTp : lineChartDataProps[] = []; +const chart_efflTp : lineChartDataProps[] = []; +const chart_inflTn : lineChartDataProps[] = []; +const chart_efflTn : lineChartDataProps[] = []; +const chart_inflBod : lineChartDataProps[] = []; +const chart_efflBod : lineChartDataProps[] = []; + +const rainManageList : RainManageListProps[] = []; + +const drainageEquipmentList : DrainageEquipmentListProps[] = [ + { + part1 : '청천시청', + part2 : '청천시청', + nowSum : 101, + nowJoin : 102, + nowSep : 103, + stepOneSum : 104, + stepOneJoin : 105, + stepOneSep : 106, + stepTwoSum : 107, + stepTwoJoin : 108, + stepTwoSep : 109, + stepThreeSum : 110, + stepThreeJoin : 111, + stepThreeSep : 112, + stepFourSum : 113, + stepFourJoin : 114, + stepFourSep : 115, + etc : '1050', + } +]; + +/**==================================== +* Store - api (데이터 호출) +====================================*/ +/* 시설정보 및 운영현황 - 계획 */ +const fetchFacilityPlan = async (targetYear : string | undefined, fcltyCd : string | undefined) => { + try { + targetYear = targetYear ? targetYear : "2024"; + const baseUrl = 'https://apigateway.rsonesoft.com/dc-service/api/v1/nowDmgMtncGnsvy'; + const queryParams = new URLSearchParams(); + + if (fcltyCd) queryParams.append('swtrmtFcltCd', fcltyCd); + if (targetYear) queryParams.append('targetYear',targetYear); + const queryString = queryParams.toString(); + const url = queryString ? `${baseUrl}?${queryString}` : baseUrl; + const res = await getFetchAreaList(url); + return res + } catch (error) { + console.error('시설계획정보를 가져오는데 실패했습니다:', error); + return {data: [], count: 0}; + } +}; + +/* 시설정보 및 운영현황 - 운영실태 */ +const fetchOperationStatus = async (searchYear: string|undefined, fcltyCd: string|undefined) => { + try{ + const url = '/dashBoard/mngInfo/' + (searchYear?searchYear:'2024') + '/' + (fcltyCd?fcltyCd:''); + const res = await getFetch('fo', url); + return { data: res.data, count: res.count } + } catch (error) { + console.error('운영실태 데이터를 가져오는데 실패했습니다:', error); + return { data: [], count: 0 }; + } +} + +// 주요그래프 데이터 +const fetchMainGraph = async (searchYear: string|undefined, fcltyCd: string|undefined) => { + try { + const url = '/fclt/qlty/hist/' + (searchYear?searchYear:'2024') + '/' + (fcltyCd?fcltyCd:'11680PB001R'); + const res = await getFetch('fo', url); + return { data: res.data, count: res.count } + } catch (error) { + console.error('주요그래프 데이터를 가져오는데 실패했습니다:', error); + return { data: [], count: 0 }; + } +} + +// 배수설비 정비현황 +const fetchDrainageEquipment = async (searchYear: string|undefined, fcltyCd: string|undefined) => { + try{ + /* const url = '/fclt/qlty/hist/' + (searchYear?searchYear:'2024') + '/' + (fcltyCd?fcltyCd:'11680PB001R'); + const res = await getFetch('fo', url); + return { data: res.data, count: res.count } */ + console.log(searchYear, fcltyCd); + return { data : drainageEquipmentList, count : drainageEquipmentList.length } + } catch (error) { + console.error('배수설비 정비현황 데이터를 가져오는데 실패했습니다:', error); + return { data: [], count: 0 }; + } +} + +/**==================================== +* Store - action +====================================*/ +export type DashBoardActions = { + initializeDashBoardData(): Promise<void>; + /** 시설정보 및 운영현황 - 계획정보 */ + searchPlanInfo(targetYear: string, fcltyCd: string): Promise<void>; + /** 시설정보 및 운영현황 - 운영실태 */ + searchOperationStatus(isExcel: boolean, searchYear: string, fcltyCd: string): Promise<void>; + /** 주요그래프 데이터 */ + searchMainGraph(searchYear: string, fcltyCd: string): Promise<void>; + /**강우일 운영현황 */ + searchRainManage(searchYear: string, fcltyCd: string, isExcel: boolean): Promise<void>; + /**배수설비 정비현황 */ + searchDrainageEquipment(searchYear: string, fcltyCd: string, isExcel: boolean): Promise<void>; +} + +export type DashBoardType = { + DashboardMain: { + isInit: boolean; + topLabelArray:string[]; + }, + + FcltyMain : { + isInit : boolean; + upHeadListFclty : TableUpperProps[]; + fcltyList : mainFcltyProps[]; + }, + + PlanFclty : { + isInit : boolean; + planYearList : string[]; + upHeadListPlanFclty : TableUpperProps[]; + planFcltyList : planFcltyListProps[]; + }, + + OperationStatus : { + isInit : boolean; + upHeadListOperationStatus : TableUpperProps[]; + operationalStatusList : OperationalStatusListProps[]; + } + + MainGraph : { + isInit : boolean; + chart_inflowRain : lineBarChartDataProps[]; + chart_bodRain : lineBarChartDataProps[]; + chart_inflTp : lineChartDataProps[]; + chart_chongInTp : lineChartDataProps[]; + chart_efflTp : lineChartDataProps[]; + chart_inflTn : lineChartDataProps[]; + chart_efflTn : lineChartDataProps[]; + chart_inflBod : lineChartDataProps[]; + chart_efflBod : lineChartDataProps[]; + }, + + RainManage : { + isInit : boolean; + upHeadListRainManage : TableUpperProps[]; + rainManageList : RainManageListProps[]; + excelList : RainManageExcelType[]; + }, + + DrainageEquipment : { + isInit : boolean; + upHeadListDrainageEquipment : TableUpperProps[]; + drainageEquipmentList : DrainageEquipmentListProps[]; + drainageEquipmentExcelList : DrainageEquipmentExcelType[]; + } +} + +export type DashBoardStore = DashBoardType & DashBoardActions; + +export const dashBoardInitState:DashBoardType = { + DashboardMain: { + isInit: false, + topLabelArray: DashBoardTopLabelArray, + }, + + FcltyMain : { + isInit : false, + upHeadListFclty : upHeadListFclty, + fcltyList : fcltyList, + }, + + PlanFclty : { + isInit : true, + planYearList : planYearList, + upHeadListPlanFclty : upHeadListPlanFclty, + planFcltyList : planFcltyList + }, + + OperationStatus : { + isInit : false, + upHeadListOperationStatus : upHeadListOperationStatus, + operationalStatusList : operationalStatusList + }, + + MainGraph : { + isInit : false, + chart_inflowRain : chart_inflowRain, + chart_bodRain : chart_bodRain, + chart_inflTp : chart_inflTp, + chart_chongInTp : chart_chongInTp, + chart_efflTp : chart_efflTp, + chart_inflTn : chart_inflTn, + chart_efflTn : chart_efflTn, + chart_inflBod : chart_inflBod, + chart_efflBod : chart_efflBod + }, + + RainManage : { + isInit : false, + upHeadListRainManage : upHeadListRainManage, + rainManageList : rainManageList, + excelList : [] + }, + + DrainageEquipment : { + isInit : false, + upHeadListDrainageEquipment : upHeadListDrainageEquipment, + drainageEquipmentList : drainageEquipmentList, + drainageEquipmentExcelList : [] + } +} + +/** + * 데이터 폼 포맷설정 + */ +export const dataFormSettingPlan=(item : planFcltyListProps) => { + DataForm({ type: 'float2', column: 'provisionalApproval', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float2', column: 'now', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'stepOne', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'stepTwo', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'stepThree', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'stepFour', item: item as unknown as Record<string, unknown>}); +} + +export const dataFormSetting=(item : OperationalStatusListProps)=> { + DataForm({ type: 'float2', column: 'yearAvg', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float2', column: 'yearMax', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'yearMin', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'summerAll', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'summerThree', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'summerRain', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'winterAll', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'winterSunnyAvg', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'winterSunnyMax', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'winterSunnyMin', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'groundWaterAvg', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'groundWaterSummer', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'groundWaterWinter', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'rainRate', item: item as unknown as Record<string, unknown>}); +}; + +export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) => void)=>DashBoardActions=(set: (fn: (state: DashBoardType) => DashBoardType) => void) => { + return { + initializeDashBoardData: async () => { + set((state: DashBoardType) => ({ + ...state, + DashboardMain: { + ...state.DashboardMain, + isInit: true, + } + })); + }, + + /** 시설정보 및 운영현황 - 계획정보 */ + searchPlanInfo : async (targetYear: string, fcltyCd: string) => { + const res = await fetchFacilityPlan(targetYear, fcltyCd); + + planFcltyList.map((el, index) => { + planYearList = []; + planYearList.push(res[0]?res[0].yrDt4.toString():""); + planYearList.push(res[0]?res[0].yrDc1.toString():""); + planYearList.push(res[0]?res[0].yrDc2.toString():""); + planYearList.push(res[0]?res[0].yrDc3.toString():""); + planYearList.push(res[0]?res[0].yrDc4.toString():""); + + if(index === 0){ + el.provisionalApproval = res&&res.length>0?res[0].planSwageQntSumDt4:''; + el.now = res&&res.length>0?res[0].planSwageQntSum:''; + el.stepOne = res&&res.length>0?res[0].planSwageQntSumDc1:''; + el.stepTwo = res&&res.length>0?res[0].planSwageQntSumDc2:''; + el.stepThree = res&&res.length>0?res[0].planSwageQntSumDc3:''; + el.stepFour = res&&res.length>0?res[0].planSwageQntSumDc4:''; + } + if(index === 1){ + el.provisionalApproval = res&&res.length>0?res[0].swtrmtPpltnCntDt4:''; + el.now = res&&res.length>0?res[0].swtrmtPpltnCnt:''; + el.stepOne = res&&res.length>0?res[0].swtrmtPpltnCntDc1:''; + el.stepTwo = res&&res.length>0?res[0].swtrmtPpltnCntDc2:''; + el.stepThree = res&&res.length>0?res[0].swtrmtPpltnCntDc3:''; + el.stepFour = res&&res.length>0?res[0].swtrmtPpltnCntDc4:''; + } + if(index === 2){ + el.provisionalApproval = res&&res.length>0?res[0].swtrmtZoneAreaDt4:''; + el.now = res&&res.length>0?res[0].swtrmtZoneArea:''; + el.stepOne = res&&res.length>0?res[0].swtrmtZoneAreaDc1:''; + el.stepTwo = res&&res.length>0?res[0].swtrmtZoneAreaDc2:''; + el.stepThree = res&&res.length>0?res[0].swtrmtZoneAreaDc3:''; + el.stepFour = res&&res.length>0?res[0].swtrmtZoneAreaDc4:''; + } + if(index === 4){ + el.provisionalApproval = res&&res.length>0?res[0].ugwtUseSum:''; + } + + // 임시시 + dataFormSettingPlan(el); + }); + + set((state: DashBoardType) => ({ + ...state, + PlanFclty : { + ...state.PlanFclty, + planFcltyList : planFcltyList + } + })); + }, + + /** 시설정보 및 운영현황 - 운영실태 */ + searchOperationStatus: async (isExcel: boolean, searchYear: string, fcltyCd: string) => { + const res = await fetchOperationStatus(searchYear, fcltyCd); + const data = res.data; + if(data && operationalStatusList){ + // 유량 - 유입 + if (operationalStatusList?.[0]) { + // 연간 + operationalStatusList[0].yearAvg = data.yearData===null?'':data.yearData.AVG_INFL_AMNT?data.yearData.AVG_INFL_AMNT:0+data.yearData.AVG_SUM_FLOW?data.yearData.AVG_SUM_FLOW:0+data.yearData.AVG_TP_INFL_WQLT_TP?data.yearData.AVG_TP_INFL_WQLT_TP:0; + operationalStatusList[0].yearMax = data.yearData===null?'':data.yearData.MAX_INFL_AMNT?data.yearData.MAX_INFL_AMNT:0+data.yearData.MAX_SUM_FLOW?data.yearData.MAX_SUM_FLOW:0+data.yearData.MAX_TP_INFL_WQLT_TP?data.yearData.MAX_TP_INFL_WQLT_TP:0; + operationalStatusList[0].yearMin = data.yearData===null?'':data.yearData.MIN_INFL_AMNT?data.yearData.MIN_INFL_AMNT:0+data.yearData.MIN_SUM_FLOW?data.yearData.MIN_SUM_FLOW:0+data.yearData.MIN_TP_INFL_WQLT_TP?data.yearData.MIN_TP_INFL_WQLT_TP:0; + // 여름 + operationalStatusList[0].summerAll = data.summer===null?'':data.summer.AVG_INFL_AMNT?data.summer.AVG_INFL_AMNT:0+data.summer.AVG_SUM_FLOW?data.summer.AVG_SUM_FLOW:0+data.summer.AVG_TP_INFL_WQLT_TP?data.summer.AVG_TP_INFL_WQLT_TP:0; + operationalStatusList[0].summerThree = data.summerRainy===null?'':data.summerRainy.AVG_INFL_AMNT?data.summerRainy.AVG_INFL_AMNT:0+data.summerRainy.AVG_SUM_FLOW?data.summerRainy.AVG_SUM_FLOW:0+data.summerRainy.AVG_TP_INFL_WQLT_TP?data.summerRainy.AVG_TP_INFL_WQLT_TP:0; + operationalStatusList[0].summerRain = data.summerSunny===null?'':data.summerSunny.AVG_INFL_AMNT?data.summerSunny.AVG_INFL_AMNT:0+data.summerSunny.AVG_SUM_FLOW?data.summerSunny.AVG_SUM_FLOW:0+data.summerSunny.AVG_TP_INFL_WQLT_TP?data.summerSunny.AVG_TP_INFL_WQLT_TP:0; + // 겨울 + operationalStatusList[0].winterAll = data.winter===null?'':data.winter.AVG_INFL_AMNT?data.winter.AVG_INFL_AMNT:0+data.winter.AVG_SUM_FLOW?data.winter.AVG_SUM_FLOW:0+data.winter.AVG_TP_INFL_WQLT_TP?data.winter.AVG_TP_INFL_WQLT_TP:0; + operationalStatusList[0].winterSunnyMin = data.winterSunny===null?'':data.winterSunny.MIN_INFL_AMNT?data.winterSunny.MIN_INFL_AMNT:0+data.winterSunny.MIN_SUM_FLOW?data.winterSunny.MIN_SUM_FLOW:0+data.winterSunny.MIN_TP_INFL_WQLT_TP?data.winterSunny.MIN_TP_INFL_WQLT_TP:0; + operationalStatusList[0].winterSunnyAvg = data.winterSunny===null?'':data.winterSunny.AVG_INFL_AMNT?data.winterSunny.AVG_INFL_AMNT:0+data.winterSunny.AVG_SUM_FLOW?data.winterSunny.AVG_SUM_FLOW:0+data.winterSunny.AVG_TP_INFL_WQLT_TP?data.winterSunny.AVG_TP_INFL_WQLT_TP:0; + operationalStatusList[0].winterSunnyMax = data.winterSunny===null?'':data.winterSunny.MAX_INFL_AMNT?data.winterSunny.MAX_INFL_AMNT:0+data.winterSunny.MAX_SUM_FLOW?data.winterSunny.MAX_SUM_FLOW:0+data.winterSunny.MAX_TP_INFL_WQLT_TP?data.winterSunny.MAX_TP_INFL_WQLT_TP:0; + // 지하수 + operationalStatusList[0].groundWaterAvg = 10; + operationalStatusList[0].groundWaterSummer = 11; + operationalStatusList[0].groundWaterWinter = 12; + // 오염물질 + // RDII 추정 = 하절기(6~8월) 중 최저 유입 BOD일때 유입유량 x ((동절기 청천시 유입BOD - 하절기(6~8월) 중 최저 유입BOD) / (동절기 청천시 유입BOD)) + const summerLowFlow = data.summerBod&&data.summerBod.INFL_AMNT&&data.summerBod.INFL_AMNT!='null'?Number(data.summerBod.INFL_AMNT):0; + const winterAvgBod = data.winterSunny&&data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD&&data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD!='null'?Number(data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD):0; + const summerLowBod = data.summerBod&&data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD&&data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD!='null'?Number(data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD):0; + const summerLowRain = data.summerBod&&data.summerBod.INFO_RN_DAY&&data.summerBod.INFO_RN_DAY!='null'?Number(data.summerBod.INFO_RN_DAY):0; + operationalStatusList[0].rdi = winterAvgBod===0?0:summerLowFlow * ((winterAvgBod - summerLowBod) / winterAvgBod); + operationalStatusList[0].rdiRain = summerLowRain; + dataFormSetting(operationalStatusList[0]); + } + + // 유량 - 순수하수 + if (operationalStatusList?.[1]) { + // 연간 + operationalStatusList[1].yearAvg = data.yearData?data.yearData.AVG_INFL_AMNT:''; + operationalStatusList[1].yearMax = data.yearData?data.yearData.MAX_INFL_AMNT:''; + operationalStatusList[1].yearMin = data.yearData?data.yearData.MIN_INFL_AMNT:''; + // 여름 + operationalStatusList[1].summerAll = data.summer?data.summer.AVG_INFL_AMNT:''; + operationalStatusList[1].summerThree = data.summerRainy?data.summerRainy.AVG_INFL_AMNT:''; + operationalStatusList[1].summerRain = data.summerSunny?data.summerSunny.AVG_INFL_AMNT:''; + // 겨울 + operationalStatusList[1].winterAll = data.winter?data.winter.AVG_INFL_AMNT:''; + operationalStatusList[1].winterSunnyMin = data.winterSunny?data.winterSunny.MIN_INFL_AMNT:''; + operationalStatusList[1].winterSunnyAvg = data.winterSunny?data.winterSunny.AVG_INFL_AMNT:''; + operationalStatusList[1].winterSunnyMax = data.winterSunny?data.winterSunny.MAX_INFL_AMNT:''; + // 지하수 + operationalStatusList[1].groundWaterAvg = 10; + operationalStatusList[1].groundWaterSummer = 11; + operationalStatusList[1].groundWaterWinter = 12; + // 오염물질 + // RDII 추정 = 하절기(6~8월) 중 최저 유입 BOD일때 유입유량 x ((동절기 청천시 유입BOD - 하절기(6~8월) 중 최저 유입BOD) / (동절기 청천시 유입BOD)) + const summerLowFlow = data.summerBod&&data.summerBod.INFL_AMNT&&data.summerBod.INFL_AMNT!='null'?Number(data.summerBod.INFL_AMNT):0; + const winterAvgBod = data.winterSunny&&data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD&&data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD!='null'?Number(data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD):0; + const summerLowBod = data.summerBod&&data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD&&data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD!='null'?Number(data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD):0; + const summerLowRain = data.summerBod&&data.summerBod.INFO_RN_DAY&&data.summerBod.INFO_RN_DAY!='null'?Number(data.summerBod.INFO_RN_DAY):0; + operationalStatusList[1].rdi = winterAvgBod===0?0:summerLowFlow * ((winterAvgBod - summerLowBod) / winterAvgBod); + operationalStatusList[1].rdiRain = summerLowRain; + dataFormSetting(operationalStatusList[1]); + } + + // 유량 - 연계처리수 + if (operationalStatusList?.[2]) { + // 연간 + operationalStatusList[2].yearAvg = data.yearData?data.yearData.AVG_SUM_FLOW:''; + operationalStatusList[2].yearMax = data.yearData?data.yearData.MAX_SUM_FLOW:''; + operationalStatusList[2].yearMin = data.yearData?data.yearData.MIN_SUM_FLOW:''; + // 여름 + operationalStatusList[2].summerAll = data.summer?data.summer.AVG_SUM_FLOW:''; + operationalStatusList[2].summerThree = data.summerRainy?data.summerRainy.AVG_SUM_FLOW:''; + operationalStatusList[2].summerRain = data.summerSunny?data.summerSunny.AVG_SUM_FLOW:''; + // 겨울 + operationalStatusList[2].winterAll = data.winter?data.winter.AVG_SUM_FLOW:''; + operationalStatusList[2].winterSunnyMin = data.winterSunny?data.winterSunny.MIN_SUM_FLOW:''; + operationalStatusList[2].winterSunnyAvg = data.winterSunny?data.winterSunny.AVG_SUM_FLOW:''; + operationalStatusList[2].winterSunnyMax = data.winterSunny?data.winterSunny.MAX_SUM_FLOW:''; + // 지하수 + operationalStatusList[2].groundWaterAvg = 10; + operationalStatusList[2].groundWaterSummer = 11; + operationalStatusList[2].groundWaterWinter = 12; + // 오염물질 + // RDII 추정 = 하절기(6~8월) 중 최저 유입 BOD일때 유입유량 x ((동절기 청천시 유입BOD - 하절기(6~8월) 중 최저 유입BOD) / (동절기 청천시 유입BOD)) + const summerLowFlow = data.summerBod&&data.summerBod.INFL_AMNT&&data.summerBod.INFL_AMNT!='null'?Number(data.summerBod.INFL_AMNT):0; + const winterAvgBod = data.winterSunny&&data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD&&data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD!='null'?Number(data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD):0; + const summerLowBod = data.summerBod&&data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD&&data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD!='null'?Number(data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD):0; + const summerLowRain = data.summerBod&&data.summerBod.INFO_RN_DAY&&data.summerBod.INFO_RN_DAY!='null'?Number(data.summerBod.INFO_RN_DAY):0; + operationalStatusList[2].rdi = winterAvgBod===0?0:summerLowFlow * ((winterAvgBod - summerLowBod) / winterAvgBod); + operationalStatusList[2].rdiRain = summerLowRain; + dataFormSetting(operationalStatusList[2]); + } + + // 유량 - 총인설비방류수 + if (operationalStatusList?.[3]) { + // 연간 + operationalStatusList[3].yearAvg = data.yearData?data.yearData.AVG_TP_INFL_WQLT_TP:''; + operationalStatusList[3].yearMax = data.yearData?data.yearData.MAX_TP_INFL_WQLT_TP:''; + operationalStatusList[3].yearMin = data.yearData?data.yearData.MIN_TP_INFL_WQLT_TP:''; + // 여름 + operationalStatusList[3].summerAll = data.summer?data.summer.AVG_TP_INFL_WQLT_TP:''; + operationalStatusList[3].summerThree = data.summerRainy?data.summerRainy.AVG_TP_INFL_WQLT_TP:''; + operationalStatusList[3].summerRain = data.summerSunny?data.summerSunny.AVG_TP_INFL_WQLT_TP:''; + // 겨울 + operationalStatusList[3].winterAll = data.winter?data.winter.AVG_TP_INFL_WQLT_TP:''; + operationalStatusList[3].winterSunnyMin = data.winterSunny?data.winterSunny.MIN_TP_INFL_WQLT_TP:''; + operationalStatusList[3].winterSunnyAvg = data.winterSunny?data.winterSunny.AVG_TP_INFL_WQLT_TP:''; + operationalStatusList[3].winterSunnyMax = data.winterSunny?data.winterSunny.MAX_TP_INFL_WQLT_TP:''; + // 지하수 + operationalStatusList[3].groundWaterAvg = 10; + operationalStatusList[3].groundWaterSummer = 11; + operationalStatusList[3].groundWaterWinter = 12; + // 오염물질 + // RDII 추정 = 하절기(6~8월) 중 최저 유입 BOD일때 유입유량 x ((동절기 청천시 유입BOD - 하절기(6~8월) 중 최저 유입BOD) / (동절기 청천시 유입BOD)) + const summerLowFlow = data.summerBod&&data.summerBod.INFL_AMNT&&data.summerBod.INFL_AMNT!='null'?Number(data.summerBod.INFL_AMNT):0; + const winterAvgBod = data.winterSunny&&data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD&&data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD!='null'?Number(data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD):0; + const summerLowBod = data.summerBod&&data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD&&data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD!='null'?Number(data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD):0; + const summerLowRain = data.summerBod&&data.summerBod.INFO_RN_DAY&&data.summerBod.INFO_RN_DAY!='null'?Number(data.summerBod.INFO_RN_DAY):0; + operationalStatusList[3].rdi = winterAvgBod===0?0:summerLowFlow * ((winterAvgBod - summerLowBod) / winterAvgBod); + operationalStatusList[3].rdiRain = summerLowRain; + dataFormSetting(operationalStatusList[3]); + } + + // 유량 - 방류수 + if (operationalStatusList?.[4]) { + // 연간 + operationalStatusList[4].yearAvg = data.yearData?data.yearData.AVG_EFFL_AMNT:''; + operationalStatusList[4].yearMax = data.yearData?data.yearData.MAX_EFFL_AMNT:''; + operationalStatusList[4].yearMin = data.yearData?data.yearData.MIN_EFFL_AMNT:''; + // 여름 + operationalStatusList[4].summerAll = data.summer?data.summer.AVG_EFFL_AMNT:''; + operationalStatusList[4].summerThree = data.summerRainy?data.summerRainy.AVG_EFFL_AMNT:''; + operationalStatusList[4].summerRain = data.summerSunny?data.summerSunny.AVG_EFFL_AMNT:''; + // 겨울 + operationalStatusList[4].winterAll = data.winter?data.winter.AVG_EFFL_AMNT:''; + operationalStatusList[4].winterSunnyMin = data.winterSunny?data.winterSunny.MIN_EFFL_AMNT:''; + operationalStatusList[4].winterSunnyAvg = data.winterSunny?data.winterSunny.AVG_EFFL_AMNT:''; + operationalStatusList[4].winterSunnyMax = data.winterSunny?data.winterSunny.MAX_EFFL_AMNT:''; + // 지하수 + operationalStatusList[4].groundWaterAvg = 10; + operationalStatusList[4].groundWaterSummer = 11; + operationalStatusList[4].groundWaterWinter = 12; + // 오염물질 + // RDII 추정 = 하절기(6~8월) 중 최저 유입 BOD일때 유입유량 x ((동절기 청천시 유입BOD - 하절기(6~8월) 중 최저 유입BOD) / (동절기 청천시 유입BOD)) + const summerLowFlow = data.summerBod&&data.summerBod.INFL_AMNT&&data.summerBod.INFL_AMNT!='null'?Number(data.summerBod.INFL_AMNT):0; + const winterAvgBod = data.winterSunny&&data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD&&data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD!='null'?Number(data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD):0; + const summerLowBod = data.summerBod&&data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD&&data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD!='null'?Number(data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD):0; + const summerLowRain = data.summerBod&&data.summerBod.INFO_RN_DAY&&data.summerBod.INFO_RN_DAY!='null'?Number(data.summerBod.INFO_RN_DAY):0; + operationalStatusList[4].rdi = winterAvgBod===0?0:summerLowFlow * ((winterAvgBod - summerLowBod) / winterAvgBod); + operationalStatusList[4].rdiRain = summerLowRain; + dataFormSetting(operationalStatusList[4]); + } + + /* + * 수질 - 유입(BOD) + */ + if (operationalStatusList?.[5]) { + // 연간 + operationalStatusList[5].yearAvg = data.yearData?data.yearData.AVG_INFL_ASSCT_BFR_WQLT_BOD:''; + operationalStatusList[5].yearMax = data.yearData?data.yearData.MAX_INFL_ASSCT_BFR_WQLT_BOD:''; + operationalStatusList[5].yearMin = data.yearData?data.yearData.MIN_INFL_ASSCT_BFR_WQLT_BOD:''; + dataFormSetting(operationalStatusList[5]); + // 여름 + operationalStatusList[5].summerAll = data.summer?data.summer.AVG_INFL_ASSCT_BFR_WQLT_BOD:''; + operationalStatusList[5].summerThree = data.summerRainy?data.summerRainy.AVG_INFL_ASSCT_BFR_WQLT_BOD:''; + operationalStatusList[5].summerRain = data.summerSunny?data.summerSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD:''; + // 겨울 + operationalStatusList[5].winterAll = data.winter?data.winter.AVG_INFL_ASSCT_BFR_WQLT_BOD:''; + operationalStatusList[5].winterSunnyMin = data.winterSunny?data.winterSunny.MIN_INFL_ASSCT_BFR_WQLT_BOD:''; + operationalStatusList[5].winterSunnyAvg = data.winterSunny?data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD:''; + operationalStatusList[5].winterSunnyMax = data.winterSunny?data.winterSunny.MAX_INFL_ASSCT_BFR_WQLT_BOD:''; + // 오염물질 + // RDII 추정 = 하절기(6~8월) 중 최저 유입 BOD일때 유입유량 x ((동절기 청천시 유입BOD - 하절기(6~8월) 중 최저 유입BOD) / (동절기 청천시 유입BOD)) + const summerLowFlow = data.summerBod&&data.summerBod.INFL_AMNT&&data.summerBod.INFL_AMNT!='null'?Number(data.summerBod.INFL_AMNT):0; + const winterAvgBod = data.winterSunny&&data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD&&data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD!='null'?Number(data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD):0; + const summerLowBod = data.summerBod&&data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD&&data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD!='null'?Number(data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD):0; + const summerLowRain = data.summerBod&&data.summerBod.INFO_RN_DAY&&data.summerBod.INFO_RN_DAY!='null'?Number(data.summerBod.INFO_RN_DAY):0; + operationalStatusList[5].rdi = winterAvgBod===0?0:summerLowFlow * ((winterAvgBod - summerLowBod) / winterAvgBod); + operationalStatusList[5].rdiRain = summerLowRain; + dataFormSetting(operationalStatusList[5]); + } + + /** + * 수질-방류(BOD) + */ + if (operationalStatusList?.[6]) { + // 연간 + operationalStatusList[6].yearAvg = data.yearData?data.yearData.AVG_EFFL_WQLT_BOD:''; + operationalStatusList[6].yearMax = data.yearData?data.yearData.MAX_EFFL_WQLT_BOD:''; + operationalStatusList[6].yearMin = data.yearData?data.yearData.MIN_EFFL_WQLT_BOD:''; + dataFormSetting(operationalStatusList[6]); + // 여름 + operationalStatusList[6].summerAll = data.summer?data.summer.AVG_EFFL_WQLT_BOD:''; + operationalStatusList[6].summerThree = data.summerRainy?data.summerRainy.AVG_EFFL_WQLT_BOD:''; + operationalStatusList[6].summerRain = data.summerSunny?data.summerSunny.AVG_EFFL_WQLT_BOD:''; + // 겨울 + operationalStatusList[6].winterAll = data.winter?data.winter.AVG_EFFL_WQLT_BOD:''; + operationalStatusList[6].winterSunnyMin = data.winterSunny?data.winterSunny.MIN_EFFL_WQLT_BOD:''; + operationalStatusList[6].winterSunnyAvg = data.winterSunny?data.winterSunny.AVG_EFFL_WQLT_BOD:''; + operationalStatusList[6].winterSunnyMax = data.winterSunny?data.winterSunny.MAX_EFFL_WQLT_BOD:''; + dataFormSetting(operationalStatusList[6]); + } + + // 수질-유입(T-N) + if (operationalStatusList?.[7]) { + // 연간 + operationalStatusList[7].yearAvg = data.yearData?Number(Math.round(data.yearData.AVG_INFL_ASSCT_BFR_WQLT_TN * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[7].yearMax = data.yearData?Number(Math.round(data.yearData.MAX_INFL_ASSCT_BFR_WQLT_TN * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[7].yearMin = data.yearData?Number(Math.round(data.yearData.MIN_INFL_ASSCT_BFR_WQLT_TN * 1000) / 1000).toFixed(3).toString():''; + // 여름 + operationalStatusList[7].summerAll = data.summer?Number(Math.round(data.summer.AVG_INFL_ASSCT_BFR_WQLT_TN * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[7].summerThree = data.summerRainy?Number(Math.round(data.summerRainy.AVG_INFL_ASSCT_BFR_WQLT_TN * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[7].summerRain = data.summerSunny?Number(Math.round(data.summerSunny.AVG_INFL_ASSCT_BFR_WQLT_TN * 1000) / 1000).toFixed(3).toString():''; + // 겨울 + operationalStatusList[7].winterAll = data.winter?Number(Math.round(data.winter.AVG_INFL_ASSCT_BFR_WQLT_TN * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[7].winterSunnyMin = data.winterSunny?Number(Math.round(data.winterSunny.MIN_INFL_ASSCT_BFR_WQLT_TN * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[7].winterSunnyAvg = data.winterSunny?Number(Math.round(data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_TN * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[7].winterSunnyMax = data.winterSunny?Number(Math.round(data.winterSunny.MAX_INFL_ASSCT_BFR_WQLT_TN * 1000) / 1000).toFixed(3).toString():''; + } + + // 수질-방류(T-N) + if (operationalStatusList?.[8]) { + // 연간 + operationalStatusList[8].yearAvg = data.yearData?Number(Math.round(data.yearData.AVG_EFFL_WQLT_TN * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[8].yearMax = data.yearData?Number(Math.round(data.yearData.MAX_EFFL_WQLT_TN * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[8].yearMin = data.yearData?Number(Math.round(data.yearData.MIN_EFFL_WQLT_TN * 1000) / 1000).toFixed(3).toString():''; + // 여름 + operationalStatusList[8].summerAll = data.summer?Number(Math.round(data.summer.AVG_EFFL_WQLT_TN * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[8].summerThree = data.summerRainy?Number(Math.round(data.summerRainy.AVG_EFFL_WQLT_TN * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[8].summerRain = data.summerSunny?Number(Math.round(data.summerSunny.AVG_EFFL_WQLT_TN * 1000) / 1000).toFixed(3).toString():''; + // 겨울 + operationalStatusList[8].winterAll = data.winter?Number(Math.round(data.winter.AVG_EFFL_WQLT_TN * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[8].winterSunnyMin = data.winterSunny?Number(Math.round(data.winterSunny.MIN_EFFL_WQLT_TN * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[8].winterSunnyAvg = data.winterSunny?Number(Math.round(data.winterSunny.AVG_EFFL_WQLT_TN * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[8].winterSunnyMax = data.winterSunny?Number(Math.round(data.winterSunny.MAX_EFFL_WQLT_TN * 1000) / 1000).toFixed(3).toString():''; + } + + // 수질-유입(T-P) + if (operationalStatusList?.[9]) { + // 연간 + operationalStatusList[9].yearAvg = data.yearData?Number(Math.round(data.yearData.AVG_INFL_ASSCT_BFR_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[9].yearMax = data.yearData?Number(Math.round(data.yearData.MAX_INFL_ASSCT_BFR_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[9].yearMin = data.yearData?Number(Math.round(data.yearData.MIN_INFL_ASSCT_BFR_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + // 여름 + operationalStatusList[9].summerAll = data.summer?Number(Math.round(data.summer.AVG_INFL_ASSCT_BFR_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[9].summerThree = data.summerRainy?Number(Math.round(data.summerRainy.AVG_INFL_ASSCT_BFR_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[9].summerRain = data.summerSunny?Number(Math.round(data.summerSunny.AVG_INFL_ASSCT_BFR_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + // 겨울 + operationalStatusList[9].winterAll = data.winter?Number(Math.round(data.winter.AVG_INFL_ASSCT_BFR_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[9].winterSunnyMin = data.winterSunny?Number(Math.round(data.winterSunny.MIN_INFL_ASSCT_BFR_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[9].winterSunnyAvg = data.winterSunny?Number(Math.round(data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[9].winterSunnyMax = data.winterSunny?Number(Math.round(data.winterSunny.MAX_INFL_ASSCT_BFR_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + } + + // 수질-방류(T-P) + if (operationalStatusList?.[10]) { + // 연간 + operationalStatusList[10].yearAvg = data.yearData?Number(Math.round(data.yearData.AVG_EFFL_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[10].yearMax = data.yearData?Number(Math.round(data.yearData.MAX_EFFL_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[10].yearMin = data.yearData?Number(Math.round(data.yearData.MIN_EFFL_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + // 여름 + operationalStatusList[10].summerAll = data.summer?Number(Math.round(data.summer.AVG_EFFL_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[10].summerThree = data.summerRainy?Number(Math.round(data.summerRainy.AVG_EFFL_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[10].summerRain = data.summerSunny?Number(Math.round(data.summerSunny.AVG_EFFL_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + // 겨울 + operationalStatusList[10].winterAll = data.winter?Number(Math.round(data.winter.AVG_EFFL_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[10].winterSunnyMin = data.winterSunny?Number(Math.round(data.winterSunny.MIN_EFFL_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[10].winterSunnyAvg = data.winterSunny?Number(Math.round(data.winterSunny.AVG_EFFL_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[10].winterSunnyMax = data.winterSunny?Number(Math.round(data.winterSunny.MAX_EFFL_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + } + + /** + * 총인설비 + */ + // + // 유입 + if (operationalStatusList?.[11]) { + // 연간 + operationalStatusList[11].yearAvg = data.yearData?Number(Math.round(data.yearData.AVG_INFL_ASSCT_BFR_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[11].yearMax = data.yearData?Number(Math.round(data.yearData.MAX_INFL_ASSCT_BFR_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[11].yearMin = data.yearData?Number(Math.round(data.yearData.MIN_INFL_ASSCT_BFR_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + // 여름 + operationalStatusList[11].summerAll = data.summer?Number(Math.round(data.summer.AVG_INFL_ASSCT_BFR_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[11].summerThree = data.summerRainy?Number(Math.round(data.summerRainy.AVG_INFL_ASSCT_BFR_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[11].summerRain = data.summerSunny?Number(Math.round(data.summerSunny.AVG_INFL_ASSCT_BFR_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + // 겨울 + operationalStatusList[11].winterAll = data.winter?Number(Math.round(data.winter.AVG_INFL_ASSCT_BFR_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[11].winterSunnyMin = data.winterSunny?Number(Math.round(data.winterSunny.MIN_INFL_ASSCT_BFR_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[11].winterSunnyAvg = data.winterSunny?Number(Math.round(data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[11].winterSunnyMax = data.winterSunny?Number(Math.round(data.winterSunny.MAX_INFL_ASSCT_BFR_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + } + + // 방류 + if (operationalStatusList?.[12]) { + // 연간 + operationalStatusList[12].yearAvg = data.yearData?Number(Math.round(data.yearData.AVG_EFFL_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[12].yearMax = data.yearData?Number(Math.round(data.yearData.MAX_EFFL_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[12].yearMin = data.yearData?Number(Math.round(data.yearData.MIN_EFFL_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + // 여름 + operationalStatusList[12].summerAll = data.summer?Number(Math.round(data.summer.AVG_EFFL_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[12].summerThree = data.summerRainy?Number(Math.round(data.summerRainy.AVG_EFFL_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[12].summerRain = data.summerSunny?Number(Math.round(data.summerSunny.AVG_EFFL_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + // 겨울 + operationalStatusList[12].winterAll = data.winter?Number(Math.round(data.winter.AVG_EFFL_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[12].winterSunnyMin = data.winterSunny?Number(Math.round(data.winterSunny.MIN_EFFL_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[12].winterSunnyAvg = data.winterSunny?Number(Math.round(data.winterSunny.AVG_EFFL_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + operationalStatusList[12].winterSunnyMax = data.winterSunny?Number(Math.round(data.winterSunny.MAX_EFFL_WQLT_TP * 1000) / 1000).toFixed(3).toString():''; + } + } + //const excelDownList: RainManageExcelType[] = []; + /* if(isExcel){ + res.data.forEach(item => { + dataFormSetting(item) + item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); + item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; + item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; + excelDownList.push({ + 시설코드: item.bscFctCd, + 시설이름: item.bscFctNm, + 측정일자: item.msrDt, + 시도: item.sidoNm, + 시군구: item.sggNm, + 주소: item.addr, + 용량: item.fctCpc, + 유입BOD: item.inflAssctAftWqltBod, + 유입TN: item.inflAssctAftWqltTn, + 유입TP: item.inflAssctBfrWqltTp, + 유출BOD: item.efflWqltBod, + 유출TN: item.efflWqltTn, + 유출TP: item.efflWqltTp, + 환경청: item.rgnNm, + 유역: item.rvbsn, + 대유역: item.lgbsn, + 중유역: item.mdmbsn, + }); + }); + }else{ */ + /* data.forEach((item: OperationalStatusListProps) => { + }); */ + /* } */ + set((state: DashBoardType) => ({ + ...state, + OperationStatus: { + ...state.OperationStatus, + operationalStatusList: operationalStatusList, + operationalStatusCount: res.count + } + })) + }, + + searchMainGraph: async (searchYear: string, fcltyCd: string) => { + const res = await fetchMainGraph(searchYear, fcltyCd); + if(res == null || res.data == null || res.data.length === 0) { + set((state: DashBoardType) => ({ + ...state, + MainGraph: { + ...state.MainGraph, + chart_inflowRain: [], + chart_bodRain: [], + chart_inflTp: [], + chart_chongInTp: [], + chart_efflTp: [], + chart_inflTn: [], + chart_efflTn: [], + chart_inflBod: [], + chart_efflBod: [], + } + })); + return; + } + + const chart_inflowRain = res.data.wqltObjs.map((item: FacilityWaterQltyProps) => ({ + label: item.msrDt.substring(0, 4)+"-"+item.msrDt.substring(4, 6)+"-"+item.msrDt.substring(6, 8), + barVal0: item.infoRnDay ?? 0, + lineVal0: item.fctCpc ?? 0, + lineVal1: item.inflAmnt ?? 0, + })); + + const chart_bodRain = res.data.wqltObjs.map((item: FacilityWaterQltyProps) => ({ + label: item.msrDt.substring(0, 4)+"-"+item.msrDt.substring(4, 6)+"-"+item.msrDt.substring(6, 8), + barVal0: item.infoRnDay ?? 0, + lineVal0: item.inflAssctAftWqltBod ?? 0, + })); + + const chart_inflTp = res.data.wqltObjs.map((item: FacilityWaterQltyProps) => ({ + label: item.msrDt.substring(0, 4)+"-"+item.msrDt.substring(4, 6)+"-"+item.msrDt.substring(6, 8), + val : item.inflAssctBfrWqltTp ?? 0 + })); + + const chart_chongInTp = res.data.wqltObjs.map((item: FacilityWaterQltyProps) => ({ + label: item.msrDt.substring(0, 4)+"-"+item.msrDt.substring(4, 6)+"-"+item.msrDt.substring(6, 8), + val : item.tpInflWqltTp ?? 0 + })); + + const chart_efflTp = res.data.wqltObjs.map((item: FacilityWaterQltyProps) => ({ + label: item.msrDt.substring(0, 4)+"-"+item.msrDt.substring(4, 6)+"-"+item.msrDt.substring(6, 8), + val : item.efflWqltTp ?? 0 + })); + + const chart_inflTn = res.data.wqltObjs.map((item: FacilityWaterQltyProps) => ({ + label: item.msrDt.substring(0, 4)+"-"+item.msrDt.substring(4, 6)+"-"+item.msrDt.substring(6, 8), + val : item.inflAssctAftWqltTn ?? 0 + })); + + const chart_efflTn = res.data.wqltObjs.map((item: FacilityWaterQltyProps) => ({ + label: item.msrDt.substring(0, 4)+"-"+item.msrDt.substring(4, 6)+"-"+item.msrDt.substring(6, 8), + val : item.efflWqltTn ?? 0 + })); + + const chart_inflBod = res.data.wqltObjs.map((item: FacilityWaterQltyProps) => ({ + label: item.msrDt.substring(0, 4)+"-"+item.msrDt.substring(4, 6)+"-"+item.msrDt.substring(6, 8), + val : item.inflAssctAftWqltBod ?? 0 + })); + + const chart_efflBod = res.data.wqltObjs.map((item: FacilityWaterQltyProps) => ({ + label: item.msrDt.substring(0, 4)+"-"+item.msrDt.substring(4, 6)+"-"+item.msrDt.substring(6, 8), + val : item.efflWqltBod ?? 0 + })); + + set((state: DashBoardType) => ({ + ...state, + MainGraph: { + ...state.MainGraph, + chart_inflowRain: chart_inflowRain, + chart_bodRain: chart_bodRain, + chart_inflTp: chart_inflTp, + chart_chongInTp : chart_chongInTp, + chart_efflTp: chart_efflTp, + chart_inflTn: chart_inflTn, + chart_efflTn: chart_efflTn, + chart_inflBod: chart_inflBod, + chart_efflBod: chart_efflBod + } + })) + }, + + searchRainManage: async (searchYear: string, fcltyCd: string, isExcel : boolean) => { + const res = await fetchMainGraph(searchYear, fcltyCd); + if(res == null || res.data.wqltObjs == null || res.data.wqltObjs.length === 0) { + set((state: DashBoardType) => ({ + ...state, + RainManage: { + ...state.RainManage, + rainManageList: [], + } + })); + return; + } + const fcltyCpcValue = res.data.wqltObjs[0].fctCpc; + + const itemList = ['계', '3mm 미만', '3~10mm 미만', '10~20mm 미만', '20~30mm 미만', '30~40mm 미만', '40~50mm 미만', '50mm~60mm 미만', '60mm 이상']; + const rainRate = ['0', '0', '0', '0', '0', '0', '0', '0', '0']; + const rainDate = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const inflAmtCnt = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const inflAmnt = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const fcltyCpct = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const dsInflWqltBod: number[] = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const dsInflWqltCod: number[] = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const dsInflWqltSs: number[] = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const dsInflWqltTn: number[] = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const dsInflWqltTp: number[] = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const inflAssctAftWqltBodCnt = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const inflAssctAftWqltBod = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const inflAssctAftWqltTocCnt = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const inflAssctAftWqltToc = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const inflAssctAftWqltSsCnt = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const inflAssctAftWqltSs = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const inflAssctAftWqltTnCnt = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const inflAssctAftWqltTn = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const inflAssctAftWqltTpCnt = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const inflAssctAftWqltTp = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const efflWqltBodCnt = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const efflWqltBod = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const efflWqltCodCnt = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const efflWqltCod = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const efflWqltSsCnt = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const efflWqltSs = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const efflWqltTnCnt = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const efflWqltTn = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const efflWqltTpCnt = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + const efflWqltTp = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + // Process the data and create rain management list + res.data.wqltObjs.forEach((item: RainManageListProps) => { + // 강우일 + if(Number(item.infoRnDay) < 3){ + rainDate[1] = Number(rainDate[1] || 0) + 1; + inflAmtCnt[1] = Number(inflAmtCnt[1] || 0) + 1; + inflAmnt[1] = Number(inflAmnt[1] || 0) + Number(item.inflAmnt || 0); + fcltyCpct[1] = 0; + inflAssctAftWqltBodCnt[1] = Number(inflAssctAftWqltBodCnt[1] || 0) + 1; + inflAssctAftWqltBod[1] = Number(inflAssctAftWqltBod[1] || 0) + Number(item.inflAssctAftWqltBod || 0); + inflAssctAftWqltTocCnt[1] = Number(inflAssctAftWqltTocCnt[1] || 0) + 1; + inflAssctAftWqltToc[1] = Number(inflAssctAftWqltToc[1] || 0) + Number(item.inflAssctAftWqltToc || 0); + inflAssctAftWqltSsCnt[1] = Number(inflAssctAftWqltSsCnt[1] || 0) + 1; + inflAssctAftWqltSs[1] = Number(inflAssctAftWqltSs[1] || 0) + Number(item.inflAssctAftWqltSs || 0); + inflAssctAftWqltTnCnt[1] = Number(inflAssctAftWqltTnCnt[1] || 0) + 1; + inflAssctAftWqltTn[1] = Number(inflAssctAftWqltTn[1] || 0) + Number(item.inflAssctAftWqltTn || 0); + inflAssctAftWqltTpCnt[1] = Number(inflAssctAftWqltTpCnt[1] || 0) + 1; + inflAssctAftWqltTp[1] = Number(inflAssctAftWqltTp[1] || 0) + Number(item.inflAssctAftWqltTp || 0); + efflWqltBodCnt[1] = Number(efflWqltBodCnt[1] || 0) + 1; + efflWqltBod[1] = Number(efflWqltBod[1] || 0) + Number(item.efflWqltBod || 0); + efflWqltCodCnt[1] = Number(efflWqltCodCnt[1] || 0) + 1; + efflWqltCod[1] = Number(efflWqltCod[1] || 0) + Number(item.efflWqltCod || 0); + efflWqltSsCnt[1] = Number(efflWqltSsCnt[1] || 0) + 1; + efflWqltSs[1] = Number(efflWqltSs[1] || 0) + Number(item.efflWqltSs || 0); + efflWqltTnCnt[1] = Number(efflWqltTnCnt[1] || 0) + 1; + efflWqltTn[1] = Number(efflWqltTn[1] || 0) + Number(item.efflWqltTn || 0); + efflWqltTpCnt[1] = Number(efflWqltTpCnt[1] || 0) + 1; + efflWqltTp[1] = Number(efflWqltTp[1] || 0) + Number(item.efflWqltTp || 0); + }else if(Number(item.infoRnDay) >= 3 && Number(item.infoRnDay) < 10){ + rainDate[2] = Number(rainDate[2] || 0) + 1; + inflAmtCnt[2] = Number(inflAmtCnt[2] || 0) + 1; + inflAmnt[2] = Number(inflAmnt[2] || 0) + Number(item.inflAmnt || 0); + fcltyCpct[2] = 0; + inflAssctAftWqltBodCnt[2] = Number(inflAssctAftWqltBodCnt[2] || 0) + 1; + inflAssctAftWqltBod[2] = Number(inflAssctAftWqltBod[2] || 0) + Number(item.inflAssctAftWqltBod || 0); + inflAssctAftWqltTocCnt[2] = Number(inflAssctAftWqltTocCnt[2] || 0) + 1; + inflAssctAftWqltToc[2] = Number(inflAssctAftWqltToc[2] || 0) + Number(item.inflAssctAftWqltToc || 0); + inflAssctAftWqltSsCnt[2] = Number(inflAssctAftWqltSsCnt[2] || 0) + 1; + inflAssctAftWqltSs[2] = Number(inflAssctAftWqltSs[2] || 0) + Number(item.inflAssctAftWqltSs || 0); + inflAssctAftWqltTnCnt[2] = Number(inflAssctAftWqltTnCnt[2] || 0) + 1; + inflAssctAftWqltTn[2] = Number(inflAssctAftWqltTn[2] || 0) + Number(item.inflAssctAftWqltTn || 0); + inflAssctAftWqltTpCnt[2] = Number(inflAssctAftWqltTpCnt[2] || 0) + 1; + inflAssctAftWqltTp[2] = Number(inflAssctAftWqltTp[2] || 0) + Number(item.inflAssctAftWqltTp || 0); + efflWqltBodCnt[2] = Number(efflWqltBodCnt[2] || 0) + 1; + efflWqltBod[2] = Number(efflWqltBod[2] || 0) + Number(item.efflWqltBod || 0); + efflWqltCodCnt[2] = Number(efflWqltCodCnt[2] || 0) + 1; + efflWqltCod[2] = Number(efflWqltCod[2] || 0) + Number(item.efflWqltCod || 0); + efflWqltSsCnt[2] = Number(efflWqltSsCnt[2] || 0) + 1; + efflWqltSs[2] = Number(efflWqltSs[2] || 0) + Number(item.efflWqltSs || 0); + efflWqltTnCnt[2] = Number(efflWqltTnCnt[2] || 0) + 1; + efflWqltTn[2] = Number(efflWqltTn[2] || 0) + Number(item.efflWqltTn || 0); + efflWqltTpCnt[2] = Number(efflWqltTpCnt[2] || 0) + 1; + efflWqltTp[2] = Number(efflWqltTp[2] || 0) + Number(item.efflWqltTp || 0); + }else if(Number(item.infoRnDay) >= 10 && Number(item.infoRnDay) < 20){ + rainDate[3] = Number(rainDate[3] || 0) + 1; + inflAmtCnt[3] = Number(inflAmtCnt[3] || 0) + 1; + inflAmnt[3] = Number(inflAmnt[3] || 0) + Number(item.inflAmnt || 0); + fcltyCpct[3] = 0; + inflAssctAftWqltBodCnt[3] = Number(inflAssctAftWqltBodCnt[3] || 0) + 1; + inflAssctAftWqltBod[3] = Number(inflAssctAftWqltBod[3] || 0) + Number(item.inflAssctAftWqltBod || 0); + inflAssctAftWqltTocCnt[3] = Number(inflAssctAftWqltTocCnt[3] || 0) + 1; + inflAssctAftWqltToc[3] = Number(inflAssctAftWqltToc[3] || 0) + Number(item.inflAssctAftWqltToc || 0); + inflAssctAftWqltSsCnt[3] = Number(inflAssctAftWqltSsCnt[3] || 0) + 1; + inflAssctAftWqltSs[3] = Number(inflAssctAftWqltSs[3] || 0) + Number(item.inflAssctAftWqltSs || 0); + inflAssctAftWqltTnCnt[3] = Number(inflAssctAftWqltTnCnt[3] || 0) + 1; + inflAssctAftWqltTn[3] = Number(inflAssctAftWqltTn[3] || 0) + Number(item.inflAssctAftWqltTn || 0); + inflAssctAftWqltTpCnt[3] = Number(inflAssctAftWqltTpCnt[3] || 0) + 1; + inflAssctAftWqltTp[3] = Number(inflAssctAftWqltTp[3] || 0) + Number(item.inflAssctAftWqltTp || 0); + efflWqltBodCnt[3] = Number(efflWqltBodCnt[3] || 0) + 1; + efflWqltBod[3] = Number(efflWqltBod[3] || 0) + Number(item.efflWqltBod || 0); + efflWqltCodCnt[3] = Number(efflWqltCodCnt[3] || 0) + 1; + efflWqltCod[3] = Number(efflWqltCod[3] || 0) + Number(item.efflWqltCod || 0); + efflWqltSsCnt[3] = Number(efflWqltSsCnt[3] || 0) + 1; + efflWqltSs[3] = Number(efflWqltSs[3] || 0) + Number(item.efflWqltSs || 0); + efflWqltTnCnt[3] = Number(efflWqltTnCnt[3] || 0) + 1; + efflWqltTn[3] = Number(efflWqltTn[3] || 0) + Number(item.efflWqltTn || 0); + efflWqltTpCnt[3] = Number(efflWqltTpCnt[3] || 0) + 1; + efflWqltTp[3] = Number(efflWqltTp[3] || 0) + Number(item.efflWqltTp || 0); + }else if(Number(item.infoRnDay) >= 20 && Number(item.infoRnDay) < 30){ + rainDate[4] = Number(rainDate[4] || 0) + 1; + inflAmtCnt[4] = Number(inflAmtCnt[4] || 0) + 1; + inflAmnt[4] = Number(inflAmnt[4] || 0) + Number(item.inflAmnt || 0); + fcltyCpct[4] = 0; + inflAssctAftWqltBodCnt[4] = Number(inflAssctAftWqltBodCnt[4] || 0) + 1; + inflAssctAftWqltBod[4] = Number(inflAssctAftWqltBod[4] || 0) + Number(item.inflAssctAftWqltBod || 0); + inflAssctAftWqltTocCnt[4] = Number(inflAssctAftWqltTocCnt[4] || 0) + 1; + inflAssctAftWqltToc[4] = Number(inflAssctAftWqltToc[4] || 0) + Number(item.inflAssctAftWqltToc || 0); + inflAssctAftWqltSsCnt[4] = Number(inflAssctAftWqltSsCnt[4] || 0) + 1; + inflAssctAftWqltSs[4] = Number(inflAssctAftWqltSs[4] || 0) + Number(item.inflAssctAftWqltSs || 0); + inflAssctAftWqltTnCnt[4] = Number(inflAssctAftWqltTnCnt[4] || 0) + 1; + inflAssctAftWqltTn[4] = Number(inflAssctAftWqltTn[4] || 0) + Number(item.inflAssctAftWqltTn || 0); + inflAssctAftWqltTpCnt[4] = Number(inflAssctAftWqltTpCnt[4] || 0) + 1; + inflAssctAftWqltTp[4] = Number(inflAssctAftWqltTp[4] || 0) + Number(item.inflAssctAftWqltTp || 0); + efflWqltBodCnt[4] = Number(efflWqltBodCnt[4] || 0) + 1; + efflWqltBod[4] = Number(efflWqltBod[4] || 0) + Number(item.efflWqltBod || 0); + efflWqltCodCnt[4] = Number(efflWqltCodCnt[4] || 0) + 1; + efflWqltCod[4] = Number(efflWqltCod[4] || 0) + Number(item.efflWqltCod || 0); + efflWqltSsCnt[4] = Number(efflWqltSsCnt[4] || 0) + 1; + efflWqltSs[4] = Number(efflWqltSs[4] || 0) + Number(item.efflWqltSs || 0); + efflWqltTnCnt[4] = Number(efflWqltTnCnt[4] || 0) + 1; + efflWqltTn[4] = Number(efflWqltTn[4] || 0) + Number(item.efflWqltTn || 0); + efflWqltTpCnt[4] = Number(efflWqltTpCnt[4] || 0) + 1; + efflWqltTp[4] = Number(efflWqltTp[4] || 0) + Number(item.efflWqltTp || 0); + }else if(Number(item.infoRnDay) >= 30 && Number(item.infoRnDay) < 40){ + rainDate[5] = Number(rainDate[5] || 0) + 1; + inflAmtCnt[5] = Number(inflAmtCnt[5] || 0) + 1; + inflAmnt[5] = Number(inflAmnt[5] || 0) + Number(item.inflAmnt || 0); + fcltyCpct[5] = item.inflAmnt&&Number(item.inflAmnt) !== 0 ? Number(Math.round(Number(item.inflAmnt) / Number(item.fctCpc) * 10) / 10) : 0; + inflAssctAftWqltBodCnt[5] = Number(inflAssctAftWqltBodCnt[5] || 0) + 1; + inflAssctAftWqltBod[5] = Number(inflAssctAftWqltBod[5] || 0) + Number(item.inflAssctAftWqltBod || 0); + inflAssctAftWqltTocCnt[5] = Number(inflAssctAftWqltTocCnt[5] || 0) + 1; + inflAssctAftWqltToc[5] = Number(inflAssctAftWqltToc[5] || 0) + Number(item.inflAssctAftWqltToc || 0); + inflAssctAftWqltSsCnt[5] = Number(inflAssctAftWqltSsCnt[5] || 0) + 1; + inflAssctAftWqltSs[5] = Number(inflAssctAftWqltSs[5] || 0) + Number(item.inflAssctAftWqltSs || 0); + inflAssctAftWqltTnCnt[5] = Number(inflAssctAftWqltTnCnt[5] || 0) + 1; + inflAssctAftWqltTn[5] = Number(inflAssctAftWqltTn[5] || 0) + Number(item.inflAssctAftWqltTn || 0); + inflAssctAftWqltTpCnt[5] = Number(inflAssctAftWqltTpCnt[5] || 0) + 1; + inflAssctAftWqltTp[5] = Number(inflAssctAftWqltTp[5] || 0) + Number(item.inflAssctAftWqltTp || 0); + efflWqltBodCnt[5] = Number(efflWqltBodCnt[5] || 0) + 1; + efflWqltBod[5] = Number(efflWqltBod[5] || 0) + Number(item.efflWqltBod || 0); + efflWqltCodCnt[5] = Number(efflWqltCodCnt[5] || 0) + 1; + efflWqltCod[5] = Number(efflWqltCod[5] || 0) + Number(item.efflWqltCod || 0); + efflWqltSsCnt[5] = Number(efflWqltSsCnt[5] || 0) + 1; + efflWqltSs[5] = Number(efflWqltSs[5] || 0) + Number(item.efflWqltSs || 0); + efflWqltTnCnt[5] = Number(efflWqltTnCnt[5] || 0) + 1; + efflWqltTn[5] = Number(efflWqltTn[5] || 0) + Number(item.efflWqltTn || 0); + efflWqltTpCnt[5] = Number(efflWqltTpCnt[5] || 0) + 1; + efflWqltTp[5] = Number(efflWqltTp[5] || 0) + Number(item.efflWqltTp || 0); + }else if(Number(item.infoRnDay) >= 40 && Number(item.infoRnDay) < 50){ + rainDate[6] = Number(rainDate[6] || 0) + 1; + inflAmtCnt[6] = Number(inflAmtCnt[6] || 0) + 1; + inflAmnt[6] = Number(inflAmnt[6] || 0) + Number(item.inflAmnt || 0); + fcltyCpct[6] = 0; + inflAssctAftWqltBodCnt[6] = Number(inflAssctAftWqltBodCnt[6] || 0) + 1; + inflAssctAftWqltBod[6] = Number(inflAssctAftWqltBod[6] || 0) + Number(item.inflAssctAftWqltBod || 0); + inflAssctAftWqltTocCnt[6] = Number(inflAssctAftWqltTocCnt[6] || 0) + 1; + inflAssctAftWqltToc[6] = Number(inflAssctAftWqltToc[6] || 0) + Number(item.inflAssctAftWqltToc || 0); + inflAssctAftWqltSsCnt[6] = Number(inflAssctAftWqltSsCnt[6] || 0) + 1; + inflAssctAftWqltSs[6] = Number(inflAssctAftWqltSs[6] || 0) + Number(item.inflAssctAftWqltSs || 0); + inflAssctAftWqltTnCnt[6] = Number(inflAssctAftWqltTnCnt[6] || 0) + 1; + inflAssctAftWqltTn[6] = Number(inflAssctAftWqltTn[6] || 0) + Number(item.inflAssctAftWqltTn || 0); + inflAssctAftWqltTpCnt[6] = Number(inflAssctAftWqltTpCnt[6] || 0) + 1; + inflAssctAftWqltTp[6] = Number(inflAssctAftWqltTp[6] || 0) + Number(item.inflAssctAftWqltTp || 0); + efflWqltBodCnt[6] = Number(efflWqltBodCnt[6] || 0) + 1; + efflWqltBod[6] = Number(efflWqltBod[6] || 0) + Number(item.efflWqltBod || 0); + efflWqltCodCnt[6] = Number(efflWqltCodCnt[6] || 0) + 1; + efflWqltCod[6] = Number(efflWqltCod[6] || 0) + Number(item.efflWqltCod || 0); + efflWqltSsCnt[6] = Number(efflWqltSsCnt[6] || 0) + 1; + efflWqltSs[6] = Number(efflWqltSs[6] || 0) + Number(item.efflWqltSs || 0); + efflWqltTnCnt[6] = Number(efflWqltTnCnt[6] || 0) + 1; + efflWqltTn[6] = Number(efflWqltTn[6] || 0) + Number(item.efflWqltTn || 0); + efflWqltTpCnt[6] = Number(efflWqltTpCnt[6] || 0) + 1; + efflWqltTp[6] = Number(efflWqltTp[6] || 0) + Number(item.efflWqltTp || 0); + }else if(Number(item.infoRnDay) >= 50 && Number(item.infoRnDay) < 60){ + rainDate[7] = Number(rainDate[7] || 0) + 1; + inflAmtCnt[7] = Number(inflAmtCnt[7] || 0) + 1; + inflAmnt[7] = Number(inflAmnt[7] || 0) + Number(item.inflAmnt || 0); + fcltyCpct[7] = 0; + inflAssctAftWqltBodCnt[7] = Number(inflAssctAftWqltBodCnt[7] || 0) + 1; + inflAssctAftWqltBod[7] = Number(inflAssctAftWqltBod[7] || 0) + Number(item.inflAssctAftWqltBod || 0); + inflAssctAftWqltTocCnt[7] = Number(inflAssctAftWqltTocCnt[7] || 0) + 1; + inflAssctAftWqltToc[7] = Number(inflAssctAftWqltToc[7] || 0) + Number(item.inflAssctAftWqltToc || 0); + inflAssctAftWqltSsCnt[7] = Number(inflAssctAftWqltSsCnt[7] || 0) + 1; + inflAssctAftWqltSs[7] = Number(inflAssctAftWqltSs[7] || 0) + Number(item.inflAssctAftWqltSs || 0); + inflAssctAftWqltTnCnt[7] = Number(inflAssctAftWqltTnCnt[7] || 0) + 1; + inflAssctAftWqltTn[7] = Number(inflAssctAftWqltTn[7] || 0) + Number(item.inflAssctAftWqltTn || 0); + inflAssctAftWqltTpCnt[7] = Number(inflAssctAftWqltTpCnt[7] || 0) + 1; + inflAssctAftWqltTp[7] = Number(inflAssctAftWqltTp[7] || 0) + Number(item.inflAssctAftWqltTp || 0); + efflWqltBodCnt[7] = Number(efflWqltBodCnt[7] || 0) + 1; + efflWqltBod[7] = Number(efflWqltBod[7] || 0) + Number(item.efflWqltBod || 0); + efflWqltCodCnt[7] = Number(efflWqltCodCnt[7] || 0) + 1; + efflWqltCod[7] = Number(efflWqltCod[7] || 0) + Number(item.efflWqltCod || 0); + efflWqltSsCnt[7] = Number(efflWqltSsCnt[7] || 0) + 1; + efflWqltSs[7] = Number(efflWqltSs[7] || 0) + Number(item.efflWqltSs || 0); + efflWqltTnCnt[7] = Number(efflWqltTnCnt[7] || 0) + 1; + efflWqltTn[7] = Number(efflWqltTn[7] || 0) + Number(item.efflWqltTn || 0); + efflWqltTpCnt[7] = Number(efflWqltTpCnt[7] || 0) + 1; + efflWqltTp[7] = Number(efflWqltTp[7] || 0) + Number(item.efflWqltTp || 0); + }else if(Number(item.infoRnDay) >= 60){ + rainDate[8] = Number(rainDate[8] || 0) + 1; + inflAmtCnt[8] = Number(inflAmtCnt[8] || 0) + 1; + inflAmnt[8] = Number(inflAmnt[8] || 0) + Number(item.inflAmnt || 0); + fcltyCpct[8] = 0; + inflAssctAftWqltBodCnt[8] = Number(inflAssctAftWqltBodCnt[8] || 0) + 1; + inflAssctAftWqltBod[8] = Number(inflAssctAftWqltBod[8] || 0) + Number(item.inflAssctAftWqltBod || 0); + inflAssctAftWqltTocCnt[8] = Number(inflAssctAftWqltTocCnt[8] || 0) + 1; + inflAssctAftWqltToc[8] = Number(inflAssctAftWqltToc[8] || 0) + Number(item.inflAssctAftWqltToc || 0); + inflAssctAftWqltSsCnt[8] = Number(inflAssctAftWqltSsCnt[8] || 0) + 1; + inflAssctAftWqltSs[8] = Number(inflAssctAftWqltSs[8] || 0) + Number(item.inflAssctAftWqltSs || 0); + inflAssctAftWqltTnCnt[8] = Number(inflAssctAftWqltTnCnt[8] || 0) + 1; + inflAssctAftWqltTn[8] = Number(inflAssctAftWqltTn[8] || 0) + Number(item.inflAssctAftWqltTn || 0); + inflAssctAftWqltTpCnt[8] = Number(inflAssctAftWqltTpCnt[8] || 0) + 1; + inflAssctAftWqltTp[8] = Number(inflAssctAftWqltTp[8] || 0) + Number(item.inflAssctAftWqltTp || 0); + efflWqltBodCnt[8] = Number(efflWqltBodCnt[8] || 0) + 1; + efflWqltBod[8] = Number(efflWqltBod[8] || 0) + Number(item.efflWqltBod || 0); + efflWqltCodCnt[8] = Number(efflWqltCodCnt[8] || 0) + 1; + efflWqltCod[8] = Number(efflWqltCod[8] || 0) + Number(item.efflWqltCod || 0); + efflWqltSsCnt[8] = Number(efflWqltSsCnt[8] || 0) + 1; + efflWqltSs[8] = Number(efflWqltSs[8] || 0) + Number(item.efflWqltSs || 0); + efflWqltTnCnt[8] = Number(efflWqltTnCnt[8] || 0) + 1; + efflWqltTn[8] = Number(efflWqltTn[8] || 0) + Number(item.efflWqltTn || 0); + efflWqltTpCnt[8] = Number(efflWqltTpCnt[8] || 0) + 1; + efflWqltTp[8] = Number(efflWqltTp[8] || 0) + Number(item.efflWqltTp || 0); + } + }); + + // Process the data and create rain management list + if(res.data&&res.data.dsWqltObjs&&res.data.dsWqltObjs.length > 0){ + // 설계 유입수질 데이터 가져오기 - 0값이 있으면 이전 차수에서 가져오기 + const getDesignWaterQualityData = (stepIndex: number, maxPreviousSteps: number = 3) => { + for (let i = 0; i <= maxPreviousSteps && stepIndex - i >= 0; i++) { + const currentStep = res.data.dsWqltObjs[stepIndex - i]; + if (currentStep && + currentStep.dsInflWqltBod > 0 && + currentStep.dsInflWqltCod > 0 && + currentStep.dsInflWqltSs > 0 && + currentStep.dsInflWqltTn > 0 && + currentStep.dsInflWqltTp > 0) { + return { + dsInflWqltBod: currentStep.dsInflWqltBod, + dsInflWqltCod: currentStep.dsInflWqltCod, + dsInflWqltSs: currentStep.dsInflWqltSs, + dsInflWqltTn: currentStep.dsInflWqltTn, + dsInflWqltTp: currentStep.dsInflWqltTp + }; + } + } + // 모든 차수에서 유효한 데이터를 찾지 못한 경우 기본값 반환 + return { + dsInflWqltBod: 0, + dsInflWqltCod: 0, + dsInflWqltSs: 0, + dsInflWqltTn: 0, + dsInflWqltTp: 0 + }; + }; + + const lastStepIndex = res.data.dsWqltObjs.length - 1; + const designData = getDesignWaterQualityData(lastStepIndex); + + dsInflWqltBod[0] = designData.dsInflWqltBod; + dsInflWqltCod[0] = designData.dsInflWqltCod; + dsInflWqltSs[0] = designData.dsInflWqltSs; + dsInflWqltTn[0] = designData.dsInflWqltTn; + dsInflWqltTp[0] = designData.dsInflWqltTp; + } + + rainDate[0] = (Number(rainDate[1]) || 0) + (Number(rainDate[2]) || 0) + (Number(rainDate[3]) || 0) + + (Number(rainDate[4]) || 0) + (Number(rainDate[5]) || 0) + (Number(rainDate[6]) || 0) + + (Number(rainDate[7]) || 0) + (Number(rainDate[8]) || 0); + + // 강수비율 + for(let idx=0; idx<rainDate.length; idx++){ + if(Number(rainDate[idx]) > 0){ + rainRate[0] = '100'; + rainRate[idx] = (Math.round(Number(rainDate[idx])/Number(rainDate[0])*100*100)/100).toString(); + } + } + + // 평균 및 합계 계산 + const calculateAverage = (value: number, count: number) => { + return count > 0 ? Number((value / count).toFixed(1)) : 0; + }; + + // 데이터 있는 항목만 계산 + let dataIsCount = 0; + for(let idx=0; idx<inflAmnt.length; idx++){ + if(Number(inflAmnt[idx]) > 0){ + dataIsCount++; + } + } + + for(let idx=0; idx<inflAmnt.length; idx++){ + inflAmnt[idx] = calculateAverage(Number(inflAmnt[idx]), Number(inflAmtCnt[idx])); + inflAssctAftWqltBod[idx] = calculateAverage(Number(inflAssctAftWqltBod[idx]), Number(inflAssctAftWqltBodCnt[idx])); + inflAssctAftWqltToc[idx] = calculateAverage(Number(inflAssctAftWqltToc[idx]), Number(inflAssctAftWqltTocCnt[idx])); + inflAssctAftWqltSs[idx] = calculateAverage(Number(inflAssctAftWqltSs[idx]), Number(inflAssctAftWqltSsCnt[idx])); + inflAssctAftWqltTn[idx] = calculateAverage(Number(inflAssctAftWqltTn[idx]), Number(inflAssctAftWqltTnCnt[idx])); + inflAssctAftWqltTp[idx] = calculateAverage(Number(inflAssctAftWqltTp[idx]), Number(inflAssctAftWqltTpCnt[idx])); + efflWqltBod[idx] = calculateAverage(Number(efflWqltBod[idx]), Number(efflWqltBodCnt[idx])); + efflWqltCod[idx] = calculateAverage(Number(efflWqltCod[idx]), Number(efflWqltCodCnt[idx])); + efflWqltSs[idx] = calculateAverage(Number(efflWqltSs[idx]), Number(efflWqltSsCnt[idx])); + efflWqltTn[idx] = calculateAverage(Number(efflWqltTn[idx]), Number(efflWqltTnCnt[idx])); + efflWqltTp[idx] = calculateAverage(Number(efflWqltTp[idx]), Number(efflWqltTpCnt[idx])); + } + + // 합계 계산 (index 0) + const calculateTotal = (arr: number[]) => { + return Number((arr.slice(1).reduce((sum, val) => sum + Number(val), 0)).toFixed(1)); + }; + + inflAmnt[0] = calculateAverage(calculateTotal(inflAmnt), dataIsCount); + fcltyCpct[0] = calculateTotal(fcltyCpct); + inflAssctAftWqltBod[0] = Number((calculateTotal(inflAssctAftWqltBod)/8).toFixed(1)); + inflAssctAftWqltToc[0] = Number((calculateTotal(inflAssctAftWqltToc)/8).toFixed(1)); + inflAssctAftWqltSs[0] = Number((calculateTotal(inflAssctAftWqltSs)/8).toFixed(1)); + inflAssctAftWqltTn[0] = Number((calculateTotal(inflAssctAftWqltTn)/8).toFixed(3)); + inflAssctAftWqltTp[0] = Number((calculateTotal(inflAssctAftWqltTp)/8).toFixed(3)); + efflWqltBod[0] = Number((calculateTotal(efflWqltBod)/8).toFixed(1)); + efflWqltCod[0] = Number((calculateTotal(efflWqltCod)/8).toFixed(1)); + efflWqltSs[0] = Number((calculateTotal(efflWqltSs as number[])/8).toFixed(1)); + efflWqltTn[0] = Number((calculateTotal(efflWqltTn as number[])/8).toFixed(3)); + efflWqltTp[0] = Number((calculateTotal(efflWqltTp as number[])/8).toFixed(3)); + + // 최종 리스트 + const filteredData = itemList.map((item, index) => ({ + rainItem: item, + rainRate: rainRate[index] || '0', + rainDay: rainDate[index] ? Number(rainDate[index].toFixed(1)) : '', + inflAmnt: inflAmnt[index] ? Number(inflAmnt[index].toFixed(1)) : '', + fctCpc: inflAmnt[index] ? Number((inflAmnt[index] / fcltyCpcValue).toFixed(1)) : '', + dsInflWqltBod: dsInflWqltBod[index] ? Number(dsInflWqltBod[index].toFixed(1)) : '', + dsInflWqltCod: dsInflWqltCod[index] ? Number(dsInflWqltCod[index].toFixed(1)) : '', + dsInflWqltSs: dsInflWqltSs[index] ? Number(dsInflWqltSs[index].toFixed(1)) : '', + dsInflWqltTn: dsInflWqltTn[index] ? dsInflWqltTn[index].toFixed(3) : '', + dsInflWqltTp: dsInflWqltTp[index] ? dsInflWqltTp[index].toFixed(3) : '', + inflAssctAftWqltBod: inflAssctAftWqltBod[index] ? Number(inflAssctAftWqltBod[index].toFixed(1)) : '', + inflAssctAftWqltToc: inflAssctAftWqltToc[index] ? Number(inflAssctAftWqltToc[index].toFixed(1)) : '', + inflAssctAftWqltSs: inflAssctAftWqltSs[index] ? Number(inflAssctAftWqltSs[index].toFixed(1)) : '', + inflAssctAftWqltTn: inflAssctAftWqltTn[index] ? inflAssctAftWqltTn[index].toFixed(3) : '', + inflAssctAftWqltTp: inflAssctAftWqltTp[index] ? inflAssctAftWqltTp[index].toFixed(3) : '', + efflWqltBod: efflWqltBod[index] ? Number(efflWqltBod[index].toFixed(1)) : '', + efflWqltCod: efflWqltCod[index] ? Number(efflWqltCod[index].toFixed(1)) : '', + efflWqltSs: efflWqltSs[index] ? Number(efflWqltSs[index].toFixed(1)) : '', + efflWqltTn: efflWqltTn[index] ? efflWqltTn[index].toFixed(3) : '', + efflWqltTp: efflWqltTp[index] ? efflWqltTp[index].toFixed(3) : '' + })); + + const excelList : RainManageExcelType[] = []; + if(isExcel){ + filteredData.forEach((item) => { + excelList.push({ + 강우량: item.rainItem, + 강우조건비율: item.rainRate ? Number(Number(item.rainRate).toFixed(1)) : '', + 일수: item.rainDay ? Number(Number(item.rainDay).toFixed(1)) : '', + 유입유량: item.inflAmnt ? Number(Number(item.inflAmnt).toFixed(1)) : '', + 시설용량대비: item.fctCpc ? Number(Number(item.fctCpc).toFixed(1)) : '', + 설계유입수질BOD: item.dsInflWqltBod ? Number(Number(item.dsInflWqltBod).toFixed(1)) : '', + 설계유입수질TOC: item.dsInflWqltCod ? Number(Number(item.dsInflWqltCod).toFixed(1)) : '', + 설계유입수질SS: item.dsInflWqltSs ? Number(Number(item.dsInflWqltSs).toFixed(1)) : '', + 설계유입수질TN: item.dsInflWqltTn ? Number(item.dsInflWqltTn).toFixed(3) : '', + 설계유입수질TP: item.dsInflWqltTp ? Number(item.dsInflWqltTp).toFixed(3) : '', + 유입수질BOD: item.inflAssctAftWqltBod ? Number(Number(item.inflAssctAftWqltBod).toFixed(1)) : '', + 유입수질TOC: item.inflAssctAftWqltToc ? Number(Number(item.inflAssctAftWqltToc).toFixed(1)) : '', + 유입수질SS: item.inflAssctAftWqltSs ? Number(Number(item.inflAssctAftWqltSs).toFixed(1)) : '', + 유입수질TN: item.inflAssctAftWqltTn ? Number(item.inflAssctAftWqltTn).toFixed(3) : '', + 유입수질TP: item.inflAssctAftWqltTp ? Number(item.inflAssctAftWqltTp).toFixed(3) : '', + 방류수질BOD: item.efflWqltBod ? Number(Number(item.efflWqltBod).toFixed(1)) : '', + 방류수질TOC: item.efflWqltCod ? Number(Number(item.efflWqltCod).toFixed(1)) : '', + 방류수질SS: item.efflWqltSs ? Number(Number(item.efflWqltSs).toFixed(1)) : '', + 방류수질TN: item.efflWqltTn ? Number(item.efflWqltTn).toFixed(3) : '', + 방류수질TP: item.efflWqltTp ? Number(item.efflWqltTp).toFixed(3) : '', + }); + }); + } + + set((state: DashBoardType) => ({ + ...state, + RainManage: isExcel ? { + ...state.RainManage, + rainManageList: filteredData as RainManageListProps[], + excelList: excelList, + } : { + ...state.RainManage, + rainManageList: filteredData as RainManageListProps[], + } + })); + }, + + searchDrainageEquipment: async (searchYear: string, fcltyCd: string, isExcel : boolean) => { + await fetchDrainageEquipment(searchYear, fcltyCd); + /* if(res == null || res.data.wqltObjs == null || res.data.wqltObjs.length === 0) { + set((state: DashBoardType) => ({ + ...state.RainManage, + rainManageList: [], + })); + return; + } */ + + /* if(isExcel){ + res.data.wqltObjs.forEach((item) => { + excelList.push({ + 강우량: item.rainItem, + 강우조건비율: item.rainRate || 0, + 일수: item.rainDay || 0, + 유입유량: item.inflAmnt || 0, + 시설용량대비: item.fctCpc || 0, + 설계유입수질BOD: item.dsInflWqltBod || 0, + 설계유입수질TOC: item.dsInflWqltCod || 0, + 설계유입수질SS: item.dsInflWqltSs || 0, + 설계유입수질TN: item.dsInflWqltTn || 0, + 설계유입수질TP: item.dsInflWqltTp || 0, + 유입수질BOD: item.inflAssctAftWqltBod || 0, + 유입수질COD: item.inflAssctAftWqltToc || 0, + 유입수질SS: item.inflAssctAftWqltSs || 0, + 유입수질TN: item.inflAssctAftWqltTn || 0, + 유입수질TP: item.inflAssctAftWqltTp || 0, + 방류수질BOD: item.efflWqltBod || 0, + 방류수질COD: item.efflWqltCod || 0, + 방류수질SS: item.efflWqltSs || 0, + 방류수질TN: item.efflWqltTn || 0, + 방류수질TP: item.efflWqltTp || 0, + }); + }); + } */ + + set((state: DashBoardType) => ({ + ...state, + DrainageEquipment: isExcel ? { + ...state.DrainageEquipment, + drainageEquipmentList: drainageEquipmentList, + drainageEquipmentExcelList: [], + } : { + ...state.DrainageEquipment, + drainageEquipmentList: drainageEquipmentList, + } + })); + } + } +} \ No newline at end of file diff --git a/apps/fo/app/store/facilityPrecipitation/index.tsx b/apps/fo/app/store/facilityPrecipitation/index.tsx new file mode 100644 index 000000000..0c94cf553 --- /dev/null +++ b/apps/fo/app/store/facilityPrecipitation/index.tsx @@ -0,0 +1,307 @@ +import DataForm from "@/app/components/common/DataForm"; +import type { TableUpperProps } from "../dashboard"; +import { getFetch } from "@/app/components/api"; +export type { TableUpperProps }; +/**==================================== + * Store - 타입 + ====================================*/ + +/** + * (1) 메인페이지 + */ +// 시설별 강수현황 +type FacilityPrecipitationProps = { + bscFctCd : string, + sido : string, + gugun : string, + bscFctNm : string, + addr : string, + fctCpc : number, + stnKo : string, + infoRnDay : number, + rainEffectDay : number, + totalYearRain : number, + rvbsn : string, + lgbsn : string, + mdmbsn : string, + rgnNm : string, +} + +/* +* (2) 강수현황 팝업 +*/ +// 강수현황 +export type PrecipitationPropsDetailProps = { + bscFctCd : string, + rainDt : string, + infoRnDay : number, + rainEffectDay : number, + rainDay : number +} + +export interface ExcelType { + 시설코드: string, + 권역:string|'', + 단위유역:string|'', + 중권역:string|'', + 환경청:string|'', + 시도: string, + 시군구: string, + 시설이름: string, + 주소: string, + 시설용량: number, + 관측소정보 : string, + 강우일 : number, + 강우영향일 : number, + 연간총강수량 : number, +} + +/**==================================== + * Store - data + ====================================*/ + +/** + * (1) 메인페이지 + */ +// 검색단 +const LabelArray:string[] = ['구분', '시도', '시군구','용량별', '시설명', '시설상태', '조회기간', '권역', '단위유역', '중권역', '환경청별']; + +// 리스트 헤더 +const upHeadList1:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", row: 0, rowSpan: 2}, + { id: "A", title: "행정구역", row: 0, colSpan: 2 }, + { id: "sido", title: "시도", upName:"upChangeRe", upSequnce:1, row: 1 }, + { id: "gugun", title: "시군구", upName:"upChangeRe",upSequnce:2, row: 1 }, + { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2}, + { id: "addr", title: "주소", row: 0, rowSpan: 2}, + { id: "fctCpc", title: "시설용량(m³/일)", row: 0, rowSpan: 2}, + { id: "stnKo", title: "관측소 정보", row: 0, rowSpan: 2}, + { id: "infoRnDay", title: "강우일\n(일)", row: 0, rowSpan: 2}, + { id: "rainEffectDay", title: "강우영향일\n(일)", row: 0, rowSpan: 2}, + { id: "totalYearRain", title: "연간 총 총강수량\n(mm)", row: 0, rowSpan: 2} +]; + +const upHeadList2:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", row: 0, rowSpan: 2}, + { id: "A", title: "유역", row: 0, colSpan: 3} , + { id: "rvbsn", title: "권역", upName:"upChangeRe", upSequnce:1, row: 1} , + { id: "lgbsn", title: "단위유역", upName:"upChangeRe", upSequnce:2, row: 1}, + { id: "mdmbsn", title: "중권역", upName:"upChangeRe", upSequnce:3, row: 1}, + { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2}, + { id: "addr", title: "주소", row: 0, rowSpan: 2}, + { id: "fctCpc", title: "시설용량(m³/일)", row: 0, rowSpan: 2}, + { id: "stnKo", title: "관측소 정보", row: 0, rowSpan: 2}, + { id: "infoRnDay", title: "강우일\n(일)", row: 0, rowSpan: 2}, + { id: "rainEffectDay", title: "강우영향일\n(일)", row: 0, rowSpan: 2}, + { id: "totalYearRain", title: "연간 총 총강수량\n(mm)", row: 0, rowSpan: 2} +]; + +const upHeadList3:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", row: 0, rowSpan: 2}, + { id: "A", title: "유역", row: 0, colSpan: 3} , + { id: "rvbsn", title: "권역", upName:"upChangeRe1", upSequnce:1, row: 1}, + { id: "lgbsn", title: "단위유역", upName:"upChangeRe1", upSequnce:2, row: 1}, + { id: "mdmbsn", title: "중권역", upName:"upChangeRe1", upSequnce:3, row: 1}, + { id: "rgnNm", title: "환경청", row: 0, rowSpan: 2}, + { id: "B", title: "행정구역", upName:"upChangeRe2", row: 0, colSpan: 2}, + { id: "sido", title: "시도", upName:"upChangeRe2", upSequnce:1, row: 1}, + { id: "gugun", title: "시군구", upName:"upChangeRe2",upSequnce:2, row: 1}, + { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2}, + { id: "addr", title: "주소", row: 0, rowSpan: 2}, + { id: "fctCpc", title: "시설용량(m³/일)", row: 0, rowSpan: 2}, + { id: "stnKo", title: "관측소 정보", row: 0, rowSpan: 2}, + { id: "infoRnDay", title: "강우일\n(일)", row: 0, rowSpan: 2}, + { id: "rainEffectDay", title: "강우영향일\n(일)", row: 0, rowSpan: 2}, + { id: "totalYearRain", title: "연간 총 총강수량\n(mm)", row: 0, rowSpan: 2} +]; + +const facilityPrecipitation:FacilityPrecipitationProps[] = [ +] + +/** + * 강수현황 상세팝업 + */ +// 강수현황 (헤더) +const upHeadListPrecipitationDetail:TableUpperProps[] = [ + { id: "rainDt", title: "날짜"}, + { id: "infoRnDay", title: "강수량(mm/일)"}, + { id: "rainDay", title: "강우일(일)"}, + { id: "rainEffectDay", title: "강우영향일(일)"} +] +// 강수현황 (리스트) +const gridListPrecipitationDetail:PrecipitationPropsDetailProps[] = [ +] + +/**==================================== + * Store - api + ====================================*/ + +const fetchFacilityPrecipitationList = async (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { + const tailStr = '/'+pageNo + '/' + pageSize + '/' + searchYear + (part?'/' + part:'' ) + (nameCd?'/' + nameCd:'' ) + (fcltCpct?'/' + fcltCpct:'' ) + (operationValue?'/' + operationValue:'' ) + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') ; + console.log('tailStr', tailStr); + const url = '/fclt/rain' + tailStr; + const res = await getFetch('fo', url); + const tmpData:PrecipitationPropsDetailProps[] = []; + if(res!= null && res.data.length > 0){ + for(let idx=0; idx<res.data.length; idx++){ + for(let idx2=0; idx2<res.data[idx].rainyDayObjList.length; idx2++){ + const bscFctCd = res.data[idx].rainyDayObjList[idx2].bscFctCd; + const rainDt = res.data[idx].rainyDayObjList[idx2].rainDt; + const infoRnDay = res.data[idx].rainyDayObjList[idx2].infoRnDay; + const rainDay = res.data[idx].rainyDayObjList[idx2].infoRnDay>=3?1:0; + let rainEffectDay = 0; + if(idx2 < res.data[idx].rainyDayObjList.length-2){ + if(rainDay==1){ + rainEffectDay = 1; + } else { + if(idx2 >= 2){ + if(res.data[idx].rainyDayObjList[idx2-1].infoRnDay>=3 || res.data[idx].rainyDayObjList[idx2-2].infoRnDay>=3){ + rainEffectDay = 1; + } + } + } + } else if(idx2 < res.data[idx].rainyDayObjList.length-1){ + if(rainDay==1 || res.data[idx].rainyDayObjList[idx2+1].infoRnDay>=3){ + rainEffectDay = 1; + } + } else { + rainEffectDay = rainDay; + } + + tmpData.push({ + bscFctCd : bscFctCd, + rainDt : rainDt, + infoRnDay : infoRnDay, + rainDay : rainDay, + rainEffectDay : rainEffectDay + }) + } + } + + res.data.map((item: FacilityPrecipitationProps) => { + const filteredList = tmpData.filter((gridItem) => { + return gridItem.bscFctCd === item.bscFctCd; + }); + + item.rainEffectDay = filteredList.reduce((acc, curr) => acc + curr.rainEffectDay, 0); + item.totalYearRain = filteredList.reduce((acc, curr) => acc + curr.infoRnDay, 0); + item.infoRnDay = filteredList.reduce((acc, curr) => acc + curr.rainDay, 0); + }) + } + return { data: res.data, count: res.count, detailData: tmpData }; +} + +/**==================================== + * Store - expaort + ====================================*/ +export type FacilityPrecipitationActions = { + searchFacilityPrecipitationList: (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => void; +} + +const dataFormSetting=(item : FacilityPrecipitationProps)=> { + DataForm({ type: 'number', column: 'fctCpc', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float1', column: 'totalYearRain', item: item as unknown as Record<string, unknown>}); +}; + +export type FacilityPrecipitationType = { + FacilityPrecipitationSearch: { + isInit: boolean; + labelArray:string[]; + }, + + FacilityPrecipitation : { + isInit: boolean; + upHeadList1: TableUpperProps[]; + upHeadList2: TableUpperProps[]; + upHeadList3: TableUpperProps[]; + facilityPrecipitation: FacilityPrecipitationProps[]; + excelList: ExcelType[]; + facilityPrecipitationCount: number; + }, + + PrecipitationDetail : { + isInit : boolean; + upHeadListPrecipitationDetail : TableUpperProps[]; + gridListPrecipitationDetail : PrecipitationPropsDetailProps[]; + } +} + +export const facilityPrecipitationInitState: FacilityPrecipitationType = { + FacilityPrecipitationSearch: { + isInit: false, + labelArray: LabelArray, + }, + + FacilityPrecipitation : { + isInit : false, + upHeadList1 : upHeadList1, + upHeadList2 : upHeadList2, + upHeadList3 : upHeadList3, + facilityPrecipitation : facilityPrecipitation, + excelList : [], + facilityPrecipitationCount : 0 + }, + + PrecipitationDetail : { + isInit : false, + upHeadListPrecipitationDetail : upHeadListPrecipitationDetail, + gridListPrecipitationDetail : gridListPrecipitationDetail + } +} + +export type FacilityPrecipitationStore = FacilityPrecipitationType & FacilityPrecipitationActions; + +export const facilityPrecipitationReducer:(set:(fn: (state: FacilityPrecipitationType) => FacilityPrecipitationType) => void)=>FacilityPrecipitationActions=(set: (fn: (state: FacilityPrecipitationType) => FacilityPrecipitationType) => void) => { + return { + searchFacilityPrecipitationList: async (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { + const res = await fetchFacilityPrecipitationList(pageNo, pageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm); + const data = res.data; + const excelDownList: ExcelType[] = []; + + if(pageSize>5000){ + data.forEach((item: FacilityPrecipitationProps) => { + dataFormSetting(item) + item.fctCpc = item.fctCpc ? parseFloat(item.fctCpc.toString().replace(/,/g, '')) : 0; + item.totalYearRain = item.totalYearRain ? parseFloat(item.totalYearRain.toString().replace(/,/g, '')) : 0; + excelDownList.push({ + 시설코드: item.bscFctCd, + 권역: item.rvbsn, + 단위유역: item.lgbsn, + 중권역: item.mdmbsn, + 환경청: item.rgnNm, + 시도: item.sido, + 시군구: item.gugun, + 시설이름: item.bscFctNm, + 주소: item.addr, + 시설용량: item.fctCpc, + 관측소정보: item.stnKo, + 강우일: item.infoRnDay, + 강우영향일: item.rainEffectDay, + 연간총강수량: item.totalYearRain, + }) + }) + }else{ + data.forEach((item: FacilityPrecipitationProps) => { + dataFormSetting(item) + item.fctCpc = item.fctCpc ? parseFloat(item.fctCpc.toString().replace(/,/g, '')) : 0; + item.totalYearRain = item.totalYearRain ? parseFloat(item.totalYearRain.toString().replace(/,/g, '')) : 0; + }) + } + set((state:FacilityPrecipitationType) => ({ + ...state, + FacilityPrecipitation: pageSize<5000?{ + ...state.FacilityPrecipitation, + facilityPrecipitation: res.data, + facilityPrecipitationCount: res.count, + }:{ + ...state.FacilityPrecipitation, + excelList: excelDownList, + }, + PrecipitationDetail:{ + ...state.PrecipitationDetail, + gridListPrecipitationDetail: res.detailData + } + })) + } + } +} \ No newline at end of file diff --git a/apps/fo/app/store/facilityWaterQlty/index.tsx b/apps/fo/app/store/facilityWaterQlty/index.tsx new file mode 100644 index 000000000..d1bff7723 --- /dev/null +++ b/apps/fo/app/store/facilityWaterQlty/index.tsx @@ -0,0 +1,644 @@ +import { getFetch } from "@/app/components/api"; +import DataForm from "@/app/components/common/DataForm"; +import type { TableUpperProps } from "../dashboard"; +export type { TableUpperProps }; + +/**==================================== + * Store - 타입 + * + * tn, tp는 소수점 3자리까지, 나머지는 소수점 1자리까지 + ====================================*/ + +/** + * (1) 메인페이지 + */ +// 시설수질리스트 타입 +export interface FacilityWaterQltyProps { + bscFctCd: string, + bscFctNm: string, + msrDt: string + sidoNm: string, + sggNm: string, + addr: string, + fctCpc: number, + inflAssctAftWqltBod: string | '', + inflAssctAftWqltToc: string | '', + inflAssctAftWqltSs: string | '', + inflAssctAftWqltTn: string | '', + inflAssctAftWqltTp: string | '', + inflAssctBfrWqltTp: string | '', + efflWqltBod: string | '', + efflWqltCod: string | '', + efflWqltSs: string | '', + efflWqltTn: string | '', + efflWqltTp: string | '', + rgnNm:string|'', + rvbsn:string|'', + lgbsn:string|'', + mdmbsn:string|'', + inflAmnt: number | '', + lclgvrnmntNm: string, + infoRnDay: number | '', + rainEffectDay: number | '', + tpInflWqltTmprtr: number | '', + tpInflWqltPh: string | '', + tpInflWqltBod: string | '', + tpInflWqltCod: string | '', + tpInflWqltSs: string | '', + tpInflWqltTn: string | '', + tpInflWqltTp: string | '', + tpInflWqltEclgyTox: string | '', + tpInflWqltClfgrpcnt: string | '', +} +export interface ExcelType { + 시설코드: string, + 권역:string|'', + 단위유역:string|'', + 중권역:string|'', + 환경청:string|'', + 시도: string, + 시군구: string, + 시설이름: string, + 주소: string, + 용량: number, + 유입BOD: string | '', + 유입TOC: string | '', + 유입SS: string | '', + 유입TN: string | '', + 유입TP: string | '', + 유출BOD: string | '', + 유출TOC: string | '', + 유출SS: string | '', + 유출TN: string | '', + 유출TP: string | '', +} + +/** + * (2) 모달페이지 + */ +// 시설수질리스트 타입 +export type FacilityWaterQltyTmsProps = { + part: string, + toc: number, + ss: number, + tn: number, + tp: number, +} + +// API 응답 데이터 타입 +export interface WaterQualityHistoryResponse { + data: { + wqltObjs: FacilityWaterQltyProps[]; + }; +} + +/**==================================== + * Store - data + ====================================*/ +/** + * (1) 메인페이지 + */ +// 메인 라벨 배열 +const mainLabelArray: string[] = ['구분', '시도', '시군구', '용량별', '시설명', '조회기간', '시설상태', '권역', '단위유역', '중권역', '환경청별']; + +// 시설수질리스트 헤더(행정별) +const upHeadList1: TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", rowSpan: 2, row:0 }, + { id: "C", title: "행정명", colSpan: 2, row: 0 }, + { id: "sidoNm", title: "시도", row: 1 }, + { id: "sggNm", title: "시군구", row: 1 }, + { id: "bscFctNm", title: "시설명", rowSpan: 2, row: 0 }, + { id: "addr", title: "주소", rowSpan: 2, row: 0 }, + { id: "fctCpc", title: "시설용량(m³/일)", align: "right", rowSpan: 2, row: 0 }, + { id: "A", title: "유입", colSpan: 5, row: 0 }, + { id: "B", title: "방류", colSpan: 5, row: 0 }, + { id: "inflAssctAftWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe3", upSequnce: 1, align: "right", row: 1 }, + { id: "inflAssctAftWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row: 1 }, + { id: "inflAssctAftWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row: 1 }, + { id: "inflAssctAftWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe3", upSequnce: 4, align: "right", row: 1 }, + { id: "inflAssctAftWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row: 1 }, + { id: "efflWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe4", upSequnce: 1, align: "right", row: 1 }, + { id: "efflWqltCod", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row: 1 }, + { id: "efflWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row: 1 }, + { id: "efflWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe4", upSequnce: 4, align: "right", row: 1 }, + { id: "efflWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row: 1 }, +]; + +// 시설수질리스트 헤더(권역별) +const upHeadList2: TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", row:0, rowSpan:2 }, + { id: "C", title: "유역", colSpan: 3, row: 0 }, + { id: "rvbsn", title: "권역", upName: "upChangeRe1", upSequnce: 1, row:1 }, + { id: "lgbsn", title: "단위유역", upName: "upChangeRe1", upSequnce: 2, row:1 }, + { id: "mdmbsn", title: "중권역", upName: "upChangeRe1", upSequnce: 3, row:1 }, + { id: "bscFctNm", title: "시설명", row:0, rowSpan:2 }, + { id: "addr", title: "주소", row:0, rowSpan:2 }, + { id: "fctCpc", title: "시설용량(m³/L)", align: "right", row:0, rowSpan:2 }, + { id: "A", title: "유입", colSpan: 5, row: 0 }, + { id: "B", title: "방류", colSpan: 5, row: 0 }, + { id: "inflAssctAftWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe3", upSequnce: 1, align: "right", row:1 }, + { id: "inflAssctAftWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row:1 }, + { id: "inflAssctAftWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row:1 }, + { id: "inflAssctAftWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row:1 }, + { id: "inflAssctAftWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row:1 }, + { id: "efflWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe4", upSequnce: 1, align: "right", row:1 }, + { id: "efflWqltCod", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row:1 }, + { id: "efflWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row:1 }, + { id: "efflWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row:1 }, + { id: "efflWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row:1 }, +]; + +// 시설수질리스트 헤더(환경청별) +const upHeadList3: TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", row:0, rowSpan:2 }, + { id: "C", title: "유역", colSpan: 3, row: 0 }, + { id: "rvbsn", title: "권역", row:1 }, + { id: "lgbsn", title: "단위유역", row:1 }, + { id: "mdmbsn", title: "중권역", row:1 }, + { id: "rgnNm", title: "환경청", row:0, rowSpan:2 }, + { id: "D", title: "행정명", colSpan: 2, row: 0 }, + { id: "sidoNm", title: "시도", upName: "upChangeRe2", row:1 }, + { id: "sggNm", title: "시군구", upName: "upChangeRe2", row:1 }, + { id: "bscFctNm", title: "시설명", row:0, rowSpan:2 }, + { id: "addr", title: "주소", row:0, rowSpan:2 }, + { id: "fctCpc", title: "시설용량(m³/L)", align: "right", row:0, rowSpan:2 }, + { id: "A", title: "유입", colSpan: 5, row: 0 }, + { id: "B", title: "방류", colSpan: 5, row: 0 }, + { id: "inflAssctAftWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe3", upSequnce: 1, align: "right", row:1 }, + { id: "inflAssctAftWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row:1 }, + { id: "inflAssctAftWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row:1 }, + { id: "inflAssctAftWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row:1 }, + { id: "inflAssctAftWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row:1 }, + { id: "efflWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe4", upSequnce: 1, align: "right", row:1 }, + { id: "efflWqltCod", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row:1 }, + { id: "efflWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row:1 }, + { id: "efflWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row:1 }, + { id: "efflWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row:1 }, +]; + +/** + * (2) 모달페이지 + */ +// 처리시설 수질현황 헤더(모달-연간) +const upHeadListModalYear: TableUpperProps[] = [ + { id: "msrDt", title: "날짜" }, + { id: "inflAssctAftWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe1", upSequnce: 1, align: "right" }, + { id: "inflAssctAftWqltToc", title: "TOC(COD)\n(mg/L)", upName: "upChangeRe1", upSequnce: 2, align: "right" }, + { id: "inflAssctAftWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe1", upSequnce: 3, align: "right" }, + { id: "inflAssctAftWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe1", upSequnce: 2, align: "right" }, + { id: "inflAssctBfrWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe1", upSequnce: 3, align: "right" }, + { id: "efflWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe2", upSequnce: 1, align: "right" }, + { id: "efflWqltCod", title: "TOC(COD)\n(mg/L)", upName: "upChangeRe2", upSequnce: 2, align: "right" }, + { id: "efflWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe2", upSequnce: 3, align: "right" }, + { id: "efflWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe2", upSequnce: 2, align: "right" }, + { id: "efflWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe2", upSequnce: 3, align: "right" }, + { id: "infoRnDay", title: "강우량", align: "right" }, +]; + +// 처리시설 수질현황 헤더(모달-수질TMS) +const upHeadListModalTms: TableUpperProps[] = [ + { id: "part", title: "구분" }, + { id: "toc", title: "TOC(mg/L)", upName: "upChangeRe", upSequnce: 1, align: "right" }, + { id: "ss", title: "SS(mg/L)", upName: "upChangeRe", upSequnce: 2, align: "right" }, + { id: "tn", title: "T-N(mg/L)", upName: "upChangeRe", upSequnce: 3, align: "right" }, + { id: "tp", title: "T-P(mg/L)", upName: "upChangeRe", upSequnce: 4, align: "right" }, +]; + +// 처리시설 수질현황 데이터(모달-연간) +const facilityWaterQltyYearList: FacilityWaterQltyProps[] = [ +]; + +// 처리시설 수질현황 데이터(모달-수질TMS) +const facilityWaterQltyTmsList: FacilityWaterQltyTmsProps[] = [ +]; + +// 총인설비 수질현황 헤더 데이터 +const upHeadListModalChongIn: TableUpperProps[] = [ + { id: "msrDt", title: "날짜" }, + { id: "tpInflWqltBod", title: "BOD(mg/L)", upName: "upChangeRe1", upSequnce: 1, align: "right" }, + { id: "tpInflWqltTp", title: "T-P(mg/L)", upName: "upChangeRe1", upSequnce: 2, align: "right" }, + { id: "efflWqltBod", title: "BOD(mg/L)", upName: "upChangeRe2", upSequnce: 1, align: "right" }, + { id: "efflWqltTp", title: "T-P(mg/L)", upName: "upChangeRe2", upSequnce: 2, align: "right" }, +]; + +/**==================================== +* Store - api (데이터 호출) +====================================*/ +// 메인페이지 +// 시설정보 수질 리스트 데이터 호출 +const fetchFacilityWaterQltyList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string|undefined, nameCd?: string|undefined, fcltCpct?: string|undefined, operationValue?: string|undefined, fcltyNm?: string | undefined): Promise<{ data: FacilityWaterQltyProps[], count: number }> => { + try { + const tailStr = partCd ? '/'+ partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : ''; + const url = '/fclt/qlty/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr; + const res = await getFetch('fo', url); + return { data: res.data, count: res.count } + } catch (error) { + console.error('시설정보 수질현황 데이터를 가져오는데 실패했습니다:', error); + return { data: [], count: 0 }; + } +} + +// 시설정보 수질 리스트 데이터 호출(모달-수질TMS) +const fetchFacilityWaterQltyTmsList = async (facilityCd: string|undefined) => { + try { + const res = await getFetch('wr', '/il/getTms/' + facilityCd); + return { data: res.data, count: res.count }; + } catch (error) { + console.error('시설정보 수질현황 TMS 데이터를 가져오는데 실패했습니다:', error); + return { data: [], count: 0 }; + } +}; + +// 시설정보 수질 리스트 데이터 호출(모달-이력) +const fetchFacilityWaterQltyListHist = async (searchYear: string|undefined, facilityCd: string|undefined): Promise<WaterQualityHistoryResponse | null> => { + try {// + const res = await getFetch('fo', '/fclt/qlty/hist/' + searchYear + '/' + facilityCd); + return res; + } catch (error) { + console.error('시설정보 수질현황 이력 데이터를 가져오는데 실패했습니다:', error); + return null; + } +}; + +/**==================================== +* Store - export +====================================*/ +export type FacilityWaterQltyType = { + FacilityWaterQltyMain: { + facilityWaterQltyList: FacilityWaterQltyProps[]; + excelList: ExcelType[]; + facilityWaterQltyCount: number; + isInit: boolean; + mainLabelArray: string[]; + upHeadList1: TableUpperProps[]; + upHeadList2: TableUpperProps[]; + upHeadList3: TableUpperProps[]; + }, + + FacilityWaterQltyModal: { + // 처리시설 수질현황 + upHeadListModalYear: TableUpperProps[]; + facilityWaterQltyYearList: FacilityWaterQltyProps[]; + upHeadListModalTms: TableUpperProps[]; + facilityWaterQltyTmsList: FacilityWaterQltyTmsProps[]; + + // 수질tms + tmsList: FacilityWaterQltyTmsProps[]; + msrmtDate: string; + + // 총인시설 수질현황 + upHeadListModalChongIn: TableUpperProps[]; + } +} + +export const facilityWaterQltyInitState: FacilityWaterQltyType = { + FacilityWaterQltyMain: { + facilityWaterQltyCount: 0, + facilityWaterQltyList: [], + excelList: [], + isInit: false, + mainLabelArray: mainLabelArray, + upHeadList1: upHeadList1, + upHeadList2: upHeadList2, + upHeadList3: upHeadList3, + }, + + FacilityWaterQltyModal: { + // 처리시설 수질현황 + upHeadListModalYear: upHeadListModalYear, + facilityWaterQltyYearList: facilityWaterQltyYearList, + upHeadListModalTms: upHeadListModalTms, + facilityWaterQltyTmsList: facilityWaterQltyTmsList, + + // 수질tms + tmsList: [], + msrmtDate: '', + + // 총인시설 수질현황 + upHeadListModalChongIn: upHeadListModalChongIn, + } +} + +export type FacilityWaterQltyActions = { + /** + * 시설정보 수질현황 리스트 데이터 호출(구분 선택 후 시설명 있을 경우) + * @param pageNo : 페이지 번호 + * @param pageSize : 페이지 크기 + * @param searchYear : 검색 년도 + * @param part : 구분 + * @param nameCd : 시설명 + * @param fcltCpct : 시설용량 + * @param operationValue : 운영상태코드 + * @param fcltyNm : 시설명 + */ + searchFacilityWaterQltyList: (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => Promise<void>; + + /** + * 시설정보 수질현황 이력 데이터 호출 + * @param searchYear : 검색 년도 + * @param facilityCd : 시설코드 + */ + searchFacilityWaterQltyListHist: (searchYear: string, facilityCd: string) => Promise<void>; +} + +/** + * @param item : 시설수질리스트 타입 + * @returns : 없음 + * @description : 시설수질리스트 타입의 데이터를 표현 방식으로 바꿔주는 함수 + * - msrDt : YYYY-MM-DD 형식으로 변환 + * - inflAssctAftWqltBod : 소수점 1자리까지 표현 + * - inflAssctAftWqltTn : 소수점 1자리까지 표현 + * - inflAssctBfrWqltTp : 소수점 1자리까지 표현 + * - efflWqltBod : 소수점 2자리까지 표현 + * - efflWqltTn : 소수점 2자리까지 표현 + * - efflWqltTp : 소수점 2자리까지 표현 + * @author : 박진우 + * @date : 2025-04-24 + */ +const dataFormSetting = (item: FacilityWaterQltyProps) => { + DataForm({ type: 'date', column: 'msrDt', item: item as unknown as Record<string, unknown> }); +} + +export type FacilityWaterQltyStore = FacilityWaterQltyType & FacilityWaterQltyActions; + +export const facilityWaterQltyReducer = (set: (fn: (state: FacilityWaterQltyType) => FacilityWaterQltyType) => void): FacilityWaterQltyActions => { + return { + // 메인페이지 + /** + * 시설정보 수질현황 리스트 데이터 호출(구분 선택 후 시설명 있을 경우) + * @param pageNo : 페이지 번호 + * @param pageSize : 페이지 크기 + * @param searchYear : 검색 년도 + * @param part : 구분 + * @param nameCd : 시설명 + * @param fcltCpct : 시설용량 + * @param operationValue : 운영상태코드 + * @param fcltyNm : 시설명 + */ + searchFacilityWaterQltyList: async (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { + const res = await fetchFacilityWaterQltyList(pageNo, pageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm); + const rtnData = res.data.map(item => { + dataFormSetting(item) + if(item.inflAssctAftWqltTn) { + item.inflAssctAftWqltTn = Number(Math.round(Number(item.inflAssctAftWqltTn) * 1000)/1000).toFixed(3); + } + if(item.efflWqltTn){ + item.efflWqltTn = Number(Math.round(Number(item.efflWqltTn) * 1000)/1000).toFixed(3); + } + if(item.inflAssctAftWqltTp){ + item.inflAssctAftWqltTp = Number(Math.round(Number(item.inflAssctAftWqltTp) * 1000)/1000).toFixed(3); + } + if(item.efflWqltTp){ + item.efflWqltTp = Number(Math.round(Number(item.efflWqltTp) * 1000)/1000).toFixed(3); + } + if(item.inflAssctAftWqltToc){ + item.inflAssctAftWqltToc = Number(Math.round(Number(item.inflAssctAftWqltToc) * 10)/10).toFixed(1); + } + if(item.efflWqltCod){ + item.efflWqltCod = Number(Math.round(Number(item.efflWqltCod) * 10)/10).toFixed(1); + } + if(item.inflAssctAftWqltBod){ + item.inflAssctAftWqltBod = Number(Math.round(Number(item.inflAssctAftWqltBod) * 10)/10).toFixed(1); + } + if(item.efflWqltBod){ + item.efflWqltBod = Number(Math.round(Number(item.efflWqltBod) * 10)/10).toFixed(1); + } + if(item.inflAssctAftWqltSs){ + item.inflAssctAftWqltSs = Number(Math.round(Number(item.inflAssctAftWqltSs) * 10)/10).toFixed(1); + } + if(item.efflWqltSs){ + item.efflWqltSs = Number(Math.round(Number(item.efflWqltSs) * 10)/10).toFixed(1); + } + if(item.inflAssctAftWqltToc){ + item.inflAssctAftWqltToc = Number(Math.round(Number(item.inflAssctAftWqltToc) * 10)/10).toFixed(1); + } + if(item.efflWqltCod){ + item.efflWqltCod = Number(Math.round(Number(item.efflWqltCod) * 10)/10).toFixed(1); + } + return item; + }); + const excelDownList: ExcelType[] = []; + if(pageSize>5000){ + res.data.forEach(item => { + dataFormSetting(item) + item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); + item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; + item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; + excelDownList.push({ + 시설코드: item.bscFctCd, + 권역: item.rvbsn, + 단위유역: item.lgbsn, + 중권역: item.mdmbsn, + 환경청: item.rgnNm, + 시도: item.sidoNm, + 시군구: item.sggNm, + 시설이름: item.bscFctNm, + 주소: item.addr, + 용량: item.fctCpc, + 유입BOD: item.inflAssctAftWqltBod, + 유입TOC: item.inflAssctAftWqltToc, + 유입SS: item.inflAssctAftWqltSs, + 유입TN: item.inflAssctAftWqltTn, + 유입TP: item.inflAssctAftWqltTp, + 유출BOD: item.efflWqltBod, + 유출TOC: item.efflWqltCod, + 유출SS: item.efflWqltSs, + 유출TN: item.efflWqltTn, + 유출TP: item.efflWqltTp, + }); + }); + }else{ + res.data.forEach((item: FacilityWaterQltyProps) => { + dataFormSetting(item) + item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); + item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; + item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; + }); + } + set((state: FacilityWaterQltyType) => ({ + ...state, + FacilityWaterQltyMain: pageSize<5000?{ + ...state.FacilityWaterQltyMain, + facilityWaterQltyList: rtnData, + facilityWaterQltyCount: res.count, + }:{ + ...state.FacilityWaterQltyMain, + excelList: excelDownList, + } + })) + }, + + searchFacilityWaterQltyListHist: async (searchYear: string, facilityCd: string) => { + const res = await fetchFacilityWaterQltyListHist(searchYear, facilityCd); + const res1 = await fetchFacilityWaterQltyTmsList(facilityCd); + + let rtnMsrmtDate = ''; + const rtnTmsList: FacilityWaterQltyTmsProps[] = []; + if(res1.data){ + rtnTmsList.push({ + part: '평균', + toc: res1.data.tocAvgVl, + ss: res1.data.ssAvgVl, + tn: res1.data.tnAvgVl, + tp: res1.data.tpAvgVl, + }); + + rtnTmsList.push({ + part: '최대', + toc: res1.data.tocMaxVl, + ss: res1.data.ssMaxVl, + tn: res1.data.tnMaxVl, + tp: res1.data.tpMaxVl, + }); + + rtnTmsList.push({ + part: '최소', + toc: res1.data.tocMinVl, + ss: res1.data.ssMinVl, + tn: res1.data.tnMinVl, + tp: res1.data.tpMinVl, + }); + + rtnMsrmtDate = res1.data.msrmtDate; + }else{ + rtnTmsList.push({ + part: '평균', + toc: 0, + ss: 0, + tn: 0, + tp: 0, + }); + + rtnTmsList.push({ + part: '최대', + toc: 0, + ss: 0, + tn: 0, + tp: 0, + }); + + rtnTmsList.push({ + part: '최소', + toc: 0, + ss: 0, + tn: 0, + tp: 0, + }); + + rtnMsrmtDate = ''; + } + + if(Array.isArray(res) || !res || !('data' in res) || !res.data || !res.data.wqltObjs || res.data.wqltObjs.length === 0) { + set((state: FacilityWaterQltyType) => ({ + ...state, + FacilityWaterQltyModal: { + ...state.FacilityWaterQltyModal, + facilityWaterQltyYearList: [], + tmsList : rtnTmsList, + msrmtDate : rtnMsrmtDate + } + })) + return; + } + + const tmpData:FacilityWaterQltyProps[] = []; + + // facilityPrecipitation의 rainEffectDay 계산 로직을 적용 + for(let idx = 0; idx < res.data.wqltObjs.length; idx++) { + const item = res.data.wqltObjs[idx]; + if (!item) continue; + + const rainDay = Number(item.infoRnDay) >= 3 ? 1 : 0; + let rainEffectDay = 0; + + if(idx < res.data.wqltObjs.length - 2) { + if(rainDay == 1) { + rainEffectDay = 1; + } else { + if(idx >= 2) { + const prevItem1 = res.data.wqltObjs[idx-1]; + const prevItem2 = res.data.wqltObjs[idx-2]; + if((prevItem1 && Number(prevItem1.infoRnDay) >= 3) || (prevItem2 && Number(prevItem2.infoRnDay) >= 3)) { + rainEffectDay = 1; + } + } + } + } else if(idx < res.data.wqltObjs.length - 1) { + const nextItem = res.data.wqltObjs[idx+1]; + if(rainDay == 1 || (nextItem && Number(nextItem.infoRnDay) >= 3)) { + rainEffectDay = 1; + } + } else { + rainEffectDay = rainDay; + } + + tmpData.push({ + ...item, + rainEffectDay: rainEffectDay, + } as FacilityWaterQltyProps); + } + + const rtnData = tmpData.map((item: FacilityWaterQltyProps) => { + dataFormSetting(item) + if(item.inflAssctAftWqltTn) { + item.inflAssctAftWqltTn = Number(Math.round(Number(item.inflAssctAftWqltTn) * 1000)/1000).toFixed(3); + } + if(item.efflWqltTn){ + item.efflWqltTn = Number(Math.round(Number(item.efflWqltTn) * 1000)/1000).toFixed(3); + } + if(item.inflAssctBfrWqltTp){ + item.inflAssctBfrWqltTp = Number(Math.round(Number(item.inflAssctBfrWqltTp) * 1000)/1000).toFixed(3); + } + if(item.efflWqltTp){ + item.efflWqltTp = Number(Math.round(Number(item.efflWqltTp) * 1000)/1000).toFixed(3); + } + if(item.inflAssctAftWqltToc){ + item.inflAssctAftWqltToc = Number(Math.round(Number(item.inflAssctAftWqltToc) * 10)/10).toFixed(1); + } + if(item.efflWqltCod){ + item.efflWqltCod = Number(Math.round(Number(item.efflWqltCod) * 10)/10).toFixed(1); + } + if(item.inflAssctAftWqltBod){ + item.inflAssctAftWqltBod = Number(Math.round(Number(item.inflAssctAftWqltBod) * 10)/10).toFixed(1); + } + if(item.efflWqltBod){ + item.efflWqltBod = Number(Math.round(Number(item.efflWqltBod) * 10)/10).toFixed(1); + } + if(item.inflAssctAftWqltSs){ + item.inflAssctAftWqltSs = Number(Math.round(Number(item.inflAssctAftWqltSs) * 10)/10).toFixed(1); + } + if(item.efflWqltSs){ + item.efflWqltSs = Number(Math.round(Number(item.efflWqltSs) * 10)/10).toFixed(1); + } + if(item.inflAssctAftWqltToc){ + item.inflAssctAftWqltToc = Number(Math.round(Number(item.inflAssctAftWqltToc) * 10)/10).toFixed(1); + } + if(item.efflWqltCod){ + item.efflWqltCod = Number(Math.round(Number(item.efflWqltCod) * 10)/10).toFixed(1); + } + + if(item.tpInflWqltBod){ + item.tpInflWqltBod = item.tpInflWqltBod?Number(Math.round(Number(item.tpInflWqltBod) * 10)/10).toFixed(1):Number(item.tpInflWqltBod)===0?'0.0':''; + }else{ + item.tpInflWqltBod = ''; + } + + if(item.tpInflWqltTp){ + item.tpInflWqltTp = item.tpInflWqltTp?Number(Math.round(Number(item.tpInflWqltTp) * 1000)/1000).toFixed(3): Number(item.tpInflWqltTp)===0?'0.000':''; + }else{ + item.tpInflWqltTp = ''; + } + return item; + }) + set((state: FacilityWaterQltyType) => ({ + ...state, + FacilityWaterQltyModal: { + ...state.FacilityWaterQltyModal, + facilityWaterQltyYearList: rtnData, + tmsList : rtnTmsList, + msrmtDate : rtnMsrmtDate + } + })) + }, + } +} \ No newline at end of file diff --git a/apps/fo/app/store/flowRate/index.tsx b/apps/fo/app/store/flowRate/index.tsx new file mode 100644 index 000000000..2ef192c0b --- /dev/null +++ b/apps/fo/app/store/flowRate/index.tsx @@ -0,0 +1,355 @@ +import { getFetch } from "@/app/components/api"; +import type { TableUpperProps } from "../dashboard"; +import DataForm from "@/app/components/common/DataForm"; + +/**==================================== + * Store - 타입 + ====================================*/ + +/** + * (1) 메인페이지 + */ +const FlowRateSearchLabelArray:string[] = ['구분', '시도', '시군구', '용량별', '시설명', '조회기간', '시설상태', '권역', '단위유역', '중권역', '환경청별']; + +export type flowRateListProps = { + bscFctCd : string, + sidoNm : string, + sggNm : string, + bscFctNm : string, + daddr : string, + fctCpc : number, + lclgvrnmntNm : string, + totInflAmnt : number | '', + inflAmnt : number | '', + sumFlow : number | '', + returnAmnt : number | '', + efflAmnt : number | '', + rgnNm : string, + rvbsn : string, + lgbsn : string, + mdmbsn : string, + infoRnDay : number | '', +} + +export interface ExcelType { + 시설코드: string, + 권역:string|'', + 단위유역:string|'', + 중권역:string|'', + 시도: string, + 시군구: string, + 시설이름: string, + 주소: string, + 용량: number, + 총유입량: number | '', + 하수유입량: number | '', + 연계처리량: number | '', + 총인반류수량: number | '', + 방류량: number | '', + 환경청:string|'', + +} + +/** + * (2) 모달 + */ +export interface FlowRateModalInterface { + msrDt : string, + totInflAmnt : number | '', + inflAmnt : number | '', + sumFlow : number | '', + returnAmnt : number | '', + efflAmnt : number | '', +} +export type FlowRateModalProps = { + msrDt : string, + totInflAmnt : number, + inflAmnt : number, + sumFlow : number, + returnAmnt : number, + efflAmnt : number, + infoRnDay : number | '', + rainEffectDay : number | '', +} + +/**==================================== + * Store - data + ====================================*/ + + /** + * (1) 메인페이지 + */ +// 리스트 (행정별) +const upHeadList1:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", row:0, rowSpan:2}, + { id: "A", title: "행정명", row: 0 ,colSpan: 2 }, + { id: "sidoNm", title: "시도", upName:"upChangeRe", row:1 }, + { id: "sggNm", title: "시군구", upName:"upChangeRe", row:1 }, + { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2}, + { id: "daddr", title: "주소", row: 0, rowSpan: 2}, + { id: "fctCpc", title: "시설용량\n(m³/일)", align:"right", row: 0, rowSpan: 2}, + { id: "totInflAmnt", title: "총 유입입량\n(m³/일)", align:"right", row: 0, rowSpan: 2}, + { id: "inflAmnt", title: "하수유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2}, + { id: "sumFlow", title: '연계처리량\n(m³/일)', align:"right", row: 0, rowSpan: 2}, + { id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align:"right", row: 0, rowSpan: 2}, + { id: "efflAmnt", title: '방류량\n(m³/일)', align:"right", row: 0, rowSpan: 2} +]; + +// 리스트 (권역별) +const upHeadList2:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", row:0, rowSpan:2}, + { id: "A", title: "유역", row: 0, colSpan: 3}, + { id: "rvbsn", title: "권역", upName:"upChangeRe", row:1 }, + { id: "lgbsn", title: "단위유역", upName:"upChangeRe", row:1 }, + { id: "mdmbsn", title: "중권역", upName:"upChangeRe", row:1 }, + { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2}, + { id: "daddr", title: "주소", row: 0, rowSpan: 2}, + { id: "fctCpc", title: "시설용량\n(m³/일)", align:"right", row: 0, rowSpan: 2}, + { id: "totInflAmnt", title: "총 유입입량\n(m³/일)", align:"right", row: 0, rowSpan: 2}, + { id: "inflAmnt", title: "하수유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2}, + { id: "sumFlow", title: '연계처리량\n(m³/일)', align:"right", row: 0, rowSpan: 2}, + { id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align:"right", row: 0, rowSpan: 2}, + { id: "efflAmnt", title: '방류량\n(m³/일)', align:"right", row: 0, rowSpan: 2} +]; + +// 리스트 (환경청별별) +const upHeadList3:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", row:0, rowSpan:2 }, + { id: "A", title: "유역", row: 0, colSpan: 3 }, + { id: "rvbsn", title: "권역", upName:"upChangeRe1", row:1 }, + { id: "lgbsn", title: "단위유역", upName:"upChangeRe1", row:1 }, + { id: "mdmbsn", title: "중권역", upName:"upChangeRe1", row:1 }, + { id: "rgnNm", title: "환경청", row:0, rowSpan:2 }, + { id: "B", title: "행정명", row: 0 ,colSpan: 2 }, + { id: "ctpvNm", title: "시도", upName:"upChangeRe2", row:1 }, + { id: "sggNm", title: "시군구", upName:"upChangeRe2", row:1 }, + { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2 }, + { id: "daddr", title: "주소", row: 0, rowSpan: 2 }, + { id: "fctCpc", title: "시설용량\n(m³/일)", align:"right", row: 0, rowSpan: 2 }, + { id: "totInflAmnt", title: "총 유입입량\n(m³/일)", align:"right", row: 0, rowSpan: 2 }, + { id: "inflAmnt", title: "하수유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2 }, + { id: "sumFlow", title: '연계처리량\n(m³/일)', align:"right", row: 0, rowSpan: 2 }, + { id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align:"right", row: 0, rowSpan: 2 }, + { id: "efflAmnt", title: '방류량\n(m³/일)', align:"right", row: 0, rowSpan: 2 } +]; + +const flowRateList:flowRateListProps[] = [ +] + +/** + * (2) 모달 + */ + +const upHeadListFlowRateModal:TableUpperProps[] = [ + { id: "msrDt", title: "날짜"}, + { id: "totInflAmnt", title: "총 유입량(m³/일)", align:"right"}, + { id: "inflAmnt", title: "하수유입량(m³/일)", align:"right"}, + { id: "sumFlow", title: "연계처리량(m³/일)", align:"right"}, + { id: "returnAmnt", title: "총인 반류수량(m³/일)", align:"right"}, + { id: "efflAmnt", title: "방류량(m³/일)", align:"right"} +] + +const modalFlowRateListYear:FlowRateModalProps[] = [ +] + +/**==================================== + * Store - API + ====================================*/ +const fetchFlowRateList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { + try { + const tailStr = partCd ? '/'+ partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : ''; const url = '/fclt/flow/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr; + const res = await getFetch('fo', url); + console.log(url); + return { data: res.data, count: res.count } + } catch (error) { + console.error('시설정보 유량현황 데이터를 가져오는데 실패했습니다:', error); + return { data: [], count: 0 }; + } +} + +const fetchFlowRateModalList = async (bscFctCd: string, searchYear: string) => { + try { + const url = '/fclt/flow/' + bscFctCd + '/' + searchYear; + const res = await getFetch('fo', url); + + // msrDt 오름차순으로 정렬 + const sortedData = res.data.sort((a: FlowRateModalInterface, b: FlowRateModalInterface) => { + return new Date(a.msrDt).getTime() - new Date(b.msrDt).getTime(); + }); + + return { data: sortedData } + } catch (error) { + console.error('시설정보 유량현황 모달 데이터를 가져오는데 실패했습니다:', error); + return { data: [] } + } +} + + +/**==================================== + * Store - expaort + ====================================*/ + +export type FlowRateSearchActions = { + searchFlowRateList: (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => void; + + searchFlowRateModalList : (bscFctCd: string, searchYear: string) => void; +} + +export type FlowRateSearchType = { + FlowRateSearch: { + isInit: boolean; + flowRateSearchLabelArray:string[]; + }, + + FlowRateList : { + isInit : boolean; + upHeadList1: TableUpperProps[]; + upHeadList2: TableUpperProps[]; + upHeadList3: TableUpperProps[]; + flowRateList:flowRateListProps[]; + flowRateCount: number; + excelList: ExcelType[]; + }, + + FlowRateModal : { + isInit : boolean; + modalFlowRateListYear : FlowRateModalProps[]; + upHeadListFlowRateModalYear : TableUpperProps[]; + } +} + +export type FlowRateSearchStore = FlowRateSearchType & FlowRateSearchActions; + +const dataFormSetting=(item : flowRateListProps | FlowRateModalProps)=> { + DataForm({ type: 'date', column: 'msrDt', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float1', column: 'totInflAmnt', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float1', column: 'inflAmnt', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float1', column: 'sumFlow', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float1', column: 'efflWqltBod', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float1', column: 'returnAmnt', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float1', column: 'efflAmnt', item: item as unknown as Record<string, unknown>}); +} + +export const flowRateSearchInitState:FlowRateSearchType = { + FlowRateSearch: { + isInit: false, + flowRateSearchLabelArray: FlowRateSearchLabelArray, + }, + FlowRateList : { + isInit : false, + upHeadList1 : upHeadList1, + upHeadList2 : upHeadList2, + upHeadList3 : upHeadList3, + flowRateList : flowRateList, + flowRateCount : 0, + excelList: [] + }, + FlowRateModal : { + isInit : false, + upHeadListFlowRateModalYear : upHeadListFlowRateModal, + modalFlowRateListYear : modalFlowRateListYear, + } +} + +export const flowRateSearchReducer:(set:(fn: (state: FlowRateSearchType) => FlowRateSearchType) => void)=>FlowRateSearchActions=(set: (fn: (state: FlowRateSearchType) => FlowRateSearchType) => void) => { + return { + searchFlowRateList: async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { + const res = await fetchFlowRateList(pageNo, pageSize, searchYear, partCd, nameCd, fcltCpct, operationValue, fcltyNm); + const data = res.data; + const excelDownList: ExcelType[] = []; + + const rtnData = data.map((item: flowRateListProps) => { + item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); + item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; + item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; + item.totInflAmnt = Number(item.inflAmnt || 0) + Number(item.sumFlow || 0) + Number(item.returnAmnt || 0) + dataFormSetting(item); + return item; + }); + + if(pageSize>5000){ + rtnData.forEach((item: flowRateListProps) => { + excelDownList.push({ + 시설코드: item.bscFctCd, + 권역: item.rvbsn, + 단위유역: item.lgbsn, + 중권역: item.mdmbsn, + 환경청: item.rgnNm, + 시도: item.sidoNm, + 시군구: item.sggNm, + 시설이름: item.bscFctNm, + 주소: item.daddr, + 용량: item.fctCpc, + 총유입량: item.totInflAmnt, + 하수유입량: item.inflAmnt, + 연계처리량: item.sumFlow, + 총인반류수량: item.returnAmnt, + 방류량: item.efflAmnt, + }); + }); + } + + console.log('excelDownList' , excelDownList); + set((state: FlowRateSearchType) => ({ + ...state, + FlowRateList: pageSize<5000?{ + ...state.FlowRateList, + flowRateList: rtnData, + flowRateCount: res.count, + }:{ + ...state.FlowRateList, + excelList: excelDownList, + } + })) + }, + searchFlowRateModalList: async (bscFctCd: string, searchYear: string) => { + const res = await fetchFlowRateModalList(bscFctCd, searchYear); + const data = res.data; + + const tmpData:FlowRateModalProps[] = []; + // facilityPrecipitation의 rainEffectDay 계산 로직을 적용 + for(let idx = 0; idx < data.length; idx++) { + const item = data[idx]; + const rainDay = Number(item.infoRnDay) >= 3 ? 1 : 0; + let rainEffectDay = 0; + + if(idx < data.length - 2) { + if(rainDay == 1) { + rainEffectDay = 1; + } else { + if(idx >= 2) { + if(Number(data[idx-1].infoRnDay) >= 3 || Number(data[idx-2].infoRnDay) >= 3) { + rainEffectDay = 1; + } + } + } + } else if(idx < data.length - 1) { + if(rainDay == 1 || Number(data[idx+1].infoRnDay) >= 3) { + rainEffectDay = 1; + } + } else { + rainEffectDay = rainDay; + } + + tmpData.push({ + ...item, + rainEffectDay: rainEffectDay, + }); + } + + const rtnData = tmpData.map((item: FlowRateModalProps) => { + item.totInflAmnt = Number(item.inflAmnt || 0) + Number(item.sumFlow || 0) + Number(item.returnAmnt || 0) + dataFormSetting(item); + return item; + }); + + set((state: FlowRateSearchType) => ({ + ...state, + FlowRateModal: { + ...state.FlowRateModal, + modalFlowRateListYear: rtnData || [], + } + })) + } + } +} \ No newline at end of file diff --git a/apps/fo/app/store/index.tsx b/apps/fo/app/store/index.tsx new file mode 100644 index 000000000..bd684542b --- /dev/null +++ b/apps/fo/app/store/index.tsx @@ -0,0 +1,45 @@ +'use client' + +import { type ReactNode, createContext, useContext, useRef } from 'react' +import { useStore } from 'zustand' +import { type FoStore, StoreZus } from './store' + + +export type StoreApi = ReturnType<typeof StoreZus> + +export const StoreContext = createContext<StoreApi | undefined>( + undefined, +) + +export interface StoreProviderProps { + children: ReactNode +} + +export const StoreProvider = ({ + children, +}: StoreProviderProps) => { + const storeRef = useRef<StoreApi>() + + if (!storeRef.current) { + const store = StoreZus() + storeRef.current = store + } + + return ( + <StoreContext.Provider value={storeRef.current}> + {children} + </StoreContext.Provider> + ) +} + +export const useFoStore = <T,>( + selector: (store: FoStore) => T, +): T => { + const storeContext = useContext(StoreContext) + + if (!storeContext) { + throw new Error(`useStore must be used within StoreProvider`) + } + + return useStore(storeContext, selector) +} \ No newline at end of file diff --git a/apps/fo/app/store/planSewage/index.tsx b/apps/fo/app/store/planSewage/index.tsx new file mode 100644 index 000000000..e9153305a --- /dev/null +++ b/apps/fo/app/store/planSewage/index.tsx @@ -0,0 +1,226 @@ +import DataForm from "@/app/components/common/DataForm"; +import type { TableUpperProps } from "../dashboard"; +import { getFetch } from "@/app/components/api"; +export type { TableUpperProps }; +/**==================================== + * Store - 타입 + ====================================*/ + +/** + * (1) 메인페이지 + */ +// 시설별 강수현황 +type PlanSewageProps = { + bscFctCd : string, + sido : string, + gugun : string, + bscFctNm : string, + daddr : string, + fctCpc : number, + spareCapacity : number, + variableLoadPercent : number, + classifiedSewerPercent : number, + rgnNm : string, + rvbsn : string, + lgbsn : string, + mdmbsn : string, + sprtProcZoneAr : number, + procZoneSm : number, + avgInflAmnt : number, + avgInflAmntSunny : number, + maxInflAmntSunny : number, +} + +/**==================================== + * Store - data + ====================================*/ + +/** + * (1) 메인페이지 + */ +// 검색단 +const LabelArray:string[] = ['구분', '시도', '시군구','용량별', '시설명', '조회기간', '시설상태', '권역', '단위유역', '중권역', '환경청별']; + +// 리스트 헤더 +const upHeadList1:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", row:0, rowSpan:2 }, + { id: "A", title: "행정구역", upSequnce:1, row:0, colSpan:2 }, + { id: "sido", title: "시도", upName:"upChangeRe", upSequnce:1, row:1 }, + { id: "gugun", title: "시군구", upName:"upChangeRe",upSequnce:2, row:1 }, + { id: "bscFctNm", title: "시설명", row:0, rowSpan:2 }, + { id: "daddr", title: "주소", row:0, rowSpan:2 }, + { id: "fctCpc", title: "시설용량(m³/일)", row:0, rowSpan:2, align:'right' }, + { id: "spareCapacity", title: "여유용량(m³/일)", row:0, rowSpan:2, align:'right' }, + { id: "variableLoadPercent", title: "변동부하율(%)", row:0, rowSpan:2, align:'right' }, + { id: "classifiedSewerPercent", title: "분류식화율(%)", row:0, rowSpan:2, align:'right' }, +]; + +const upHeadList2:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", row:0, rowSpan:2 }, + { id: "A", title: "유역", upName:"upChangeRe", upSequnce:1, row:0, colSpan:3 }, + { id: "rvbsn", title: "권역", upName:"upChangeRe", upSequnce:1, row:1}, + { id: "lgbsn", title: "단위유역", upName:"upChangeRe", upSequnce:2, row:1}, + { id: "mdmbsn", title: "중권역", upName:"upChangeRe", upSequnce:3, row:1}, + { id: "bscFctNm", title: "시설명", row:0, rowSpan:2 }, + { id: "daddr", title: "주소", row:0, rowSpan:2 }, + { id: "fctCpc", title: "시설용량(m³/일)", row:0, rowSpan:2, align:'right' }, + { id: "spareCapacity", title: "여유용량(m³/일)", row:0, rowSpan:2, align:'right' }, + { id: "variableLoadPercent", title: "변동부하율(%)", row:0, rowSpan:2, align:'right' }, + { id: "classifiedSewerPercent", title: "분류식화율(%)", row:0, rowSpan:2, align:'right' }, +]; + +const upHeadList3:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", row:0, rowSpan:2 }, + { id: "A", title: "유역", upName:"upChangeRe", upSequnce:1, row:0, colSpan:3 }, + { id: "rvbsn", title: "권역", upName:"upChangeRe1", upSequnce:1, row:1}, + { id: "lgbsn", title: "단위유역", upName:"upChangeRe1", upSequnce:2, row:1}, + { id: "mdmbsn", title: "중권역", upName:"upChangeRe1", upSequnce:3, row:1}, + { id: "rgnNm", title: "환경청", row:0, rowSpan:2 }, + { id: "B", title: "행정구역", upName:"upChangeRe", upSequnce:1, row:0, colSpan:2 }, + { id: "sido", title: "시도", upName:"upChangeRe2", upSequnce:1, row:1 }, + { id: "gugun", title: "시군구", upName:"upChangeRe2",upSequnce:2, row:1 }, + { id: "bscFctNm", title: "시설명", row:0, rowSpan:2 }, + { id: "daddr", title: "주소", row:0, rowSpan:2 }, + { id: "fctCpc", title: "시설용량(m³/일)", row:0, rowSpan:2, align:'right' }, + { id: "spareCapacity", title: "여유용량(m³/일)", row:0, rowSpan:2, align:'right' }, + { id: "variableLoadPercent", title: "변동부하율(%)", row:0, rowSpan:2, align:'right' }, + { id: "classifiedSewerPercent", title: "분류식화율(%)", row:0, rowSpan:2, align:'right' }, +]; + +const planSewageList:PlanSewageProps[] = [ +] + +/**==================================== + * Store - api + ====================================*/ + const fetchPlanSewageList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { + const tailStr = partCd ? '/'+ partCd + '/' + (nameCd || '0') + '/' + (fcltCpct || '0') + '/' + (operationValue || '0') +'/0'+ (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : ''; + const url = '/prcsFclt/info/plan/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr; + console.log(url); + const res = await getFetch('fo', url); + return { data: res.data, count: res.count } + } + +/**==================================== + * Store - expaort + ====================================*/ +export type ExcelType = { + 시설코드: string; + 권역:string|'', + 단위유역:string|'', + 중권역:string|'', + 환경청:string|'', + 시도: string; + 시군구: string; + 시설이름: string; + 주소: string; + 시설용량: number; + 여유용량: number; + 변동부하율 : number; + 분류식화율 : number; +} + +const dataFormSetting=(item : PlanSewageProps)=> { + DataForm({ type: 'float1', column: 'fctCpc', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float1', column: 'spareCapacity', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float1', column: 'variableLoadPercent', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float1', column: 'classifiedSewerPercent', item: item as unknown as Record<string, unknown>}); +}; + +export type PlanSewageActions = { + searchPlanSewageList: (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => void; +} + +export type PlanSewageType = { + PlanSewageSearch: { + isInit: boolean; + labelArray:string[]; + }, + + PlanSewage : { + isInit: boolean; + upHeadList1: TableUpperProps[]; + upHeadList2: TableUpperProps[]; + upHeadList3: TableUpperProps[]; + planSewageList: PlanSewageProps[]; + planSewageCount: number; + excelList: ExcelType[]; + }, +} + +export const planSewageInitState: PlanSewageType = { + PlanSewageSearch: { + isInit: false, + labelArray: LabelArray, + }, + + PlanSewage : { + isInit : false, + upHeadList1 : upHeadList1, + upHeadList2 : upHeadList2, + upHeadList3 : upHeadList3, + planSewageList : planSewageList, + planSewageCount : 0, + excelList : [] + }, +} + +export type PlanSewageStore = PlanSewageType & PlanSewageActions; + +export const planSewageReducer:(set:(fn: (state: PlanSewageType) => PlanSewageType) => void)=>PlanSewageActions=(set: (fn: (state: PlanSewageType) => PlanSewageType) => void) => { + return { + searchPlanSewageList: async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { + const res = await fetchPlanSewageList(pageNo, pageSize, searchYear, partCd, nameCd, fcltCpct, operationValue, fcltyNm); + const excelDownList: ExcelType[] = []; + console.log('res' , res.data); + /** + * 결과데이터 계산 + * (1) 여유용량 = 시설용량 - 건기시 평균유량 + * (2) 변동부하율 = 건기시 일최대 유량/일평균유량(기준 최근 3개년) + * (3) 분류식화율 = 분류식지역 면적(㎢)/처리구역 면적합계(㎢) ×100 + */ + const resultData = res.data.map((item:PlanSewageProps) => { + item.spareCapacity = Number(item.fctCpc) - Number(item.avgInflAmntSunny); + item.variableLoadPercent = item.maxInflAmntSunny && item.maxInflAmntSunny!==0 ? Number(item.maxInflAmntSunny) / Number(item.avgInflAmntSunny) : 0; + item.classifiedSewerPercent = item.sprtProcZoneAr && item.sprtProcZoneAr!==0 ? Number(item.sprtProcZoneAr) / Number(item.procZoneSm) * 100 : 0; + return item; + }); + + resultData.forEach((item:PlanSewageProps) => { + dataFormSetting(item) + }) + + if(pageSize>5000){ + resultData.forEach((item:PlanSewageProps) => { + excelDownList.push({ + 시설코드: item.bscFctCd, + 권역: item.lgbsn, + 단위유역: item.rvbsn, + 중권역: item.mdmbsn, + 환경청: item.rgnNm, + 시설이름: item.bscFctNm, + 시도: item.sido, + 시군구: item.gugun, + 주소: item.daddr, + 시설용량: item.fctCpc, + 여유용량: item.spareCapacity, + 변동부하율: item.variableLoadPercent, + 분류식화율: item.classifiedSewerPercent, + }) + }) + } + + set((state:PlanSewageType) => ({ + ...state, + PlanSewage: pageSize<5000?{ + ...state.PlanSewage, + planSewageList: resultData, + planSewageCount: res.count, + }:{ + ...state.PlanSewage, + excelList: excelDownList, + } + })) + } + } +} \ No newline at end of file diff --git a/apps/fo/app/store/processArea/index.tsx b/apps/fo/app/store/processArea/index.tsx new file mode 100644 index 000000000..a43777b1c --- /dev/null +++ b/apps/fo/app/store/processArea/index.tsx @@ -0,0 +1,507 @@ +import { getFetchAreaList, postFetch } from "@/app/components/api"; +import type { TableUpperProps } from "../dashboard"; +import DataForm from "@/app/components/common/DataForm"; +export type { TableUpperProps }; +/**==================================== + * Store - 타입 + ====================================*/ + +/** + * (1) 메인페이지 + */ +// 처리구역 리스트 +export type ProcessAreaProps = { + swtrmtFcltCd : string, + sido : string, + gugun : string, + swtrmtFcltNm : string, + location : string, + fctCpc : number | '', + ruse : boolean, + yrDt4 : string, + yr : string, + yrDc1 : string, + yrDc2 : string, + yrDc3 : string, + yrDc4 : string, + /** + * 증설계획 + */ + // 기승인(당초4단계), 현재, 변경1~4 + planSwageQntSumDt4 : number | '', + planSwageQntSum : number | '', + planSwageQntSumDc1 : number | '', + planSwageQntSumDc2 : number | '', + planSwageQntSumDc3 : number | '', + planSwageQntSumDc4 : number | '', + /** + * 처리인구 + */ + // 기승인(당초4단계), 변경1~4 + swtrmtPpltnCntDt4 : number | '', + swtrmtPpltnCnt : number | '', + swtrmtPpltnCntDc1 : number | '', + swtrmtPpltnCntDc2 : number | '', + swtrmtPpltnCntDc3 : number | '', + swtrmtPpltnCntDc4 : number | '', + /** + * 처리구역면적 + */ + // 기승인(당초4단계), 변경1~4 + swtrmtZoneAreaDt4 : number | '', + swtrmtZoneArea : number | '', + swtrmtZoneAreaDc1 : number | '', + swtrmtZoneAreaDc2 : number | '', + swtrmtZoneAreaDc3 : number | '', + swtrmtZoneAreaDc4 : number | '', + // 처리구역 + trtDstr : string | '', +} + +export interface ExcelType { + 시설코드: string, + 시설명: string, + 주소: string, + 시설용량: number | '', + 증설계획기존: number | '', + 증설계획현재: number | '', + 증설계획1단계: number | '', + 증설계획2단계: number | '', + 증설계획3단계: number | '', + 증설계획4단계: number | '', + 처리인구기존: number | '', + 처리인구현재: number | '', + 처리인구1단계: number | '', + 처리인구2단계: number | '', + 처리인구3단계: number | '', + 처리인구4단계: number | '', + 처리구역기존: number | '', + 처리구역현재: number | '', + 처리구역1단계: number | '', + 처리구역2단계: number | '', + 처리구역3단계: number | '', + 처리구역4단계: number | '', + 처리구역: string | '' +} + +// (2) 처리구역 팝업 +// 시설증설 계획 +export type FcltyImproveInfoProps = { + planSwageQntSumDt4 : number | '', + planSwageQntSum : number | '', + planSwageQntSumDc1 : number | '', + planSwageQntSumDc2 : number | '', + planSwageQntSumDc3 : number | '', + planSwageQntSumDc4 : number | '', +} + +// 처리인구 계획 +export type ProcessPopulationProps = { + swtrmtPpltnCntDt4 : number | '', + swtrmtPpltnCnt : number | '', + swtrmtPpltnCntDc1 : number | '', + swtrmtPpltnCntDc2 : number | '', + swtrmtPpltnCntDc3 : number | '', + swtrmtPpltnCntDc4 : number | '', +} +// 처리구역 계획 +export type ProcessAreaPlanProps = { + swtrmtZoneAreaDt4 : number | '', + swtrmtZoneArea : number | '', + swtrmtZoneAreaDc1 : number | '', + swtrmtZoneAreaDc2 : number | '', + swtrmtZoneAreaDc3 : number | '', + swtrmtZoneAreaDc4 : number | '', + trtDstr : string, +} + +/**==================================== + * Store - data + ====================================*/ + +/** + * (1) 메인페이지 + */ +// 검색단 +const ProcessFacilityLabelArray:string[] = ['구분', '시도', '시군구','용량별', '시설명', '시설상태', '연도별', '권역', '단위유역', '중권역', '환경청별']; + +// 리스트 헤더(행정별) +const upHeadList1:TableUpperProps[] = [ + { id: "swtrmtFcltCd", title: "시설코드", rowSpan:3, row:0}, + { id: "A", title: "행정구역", colSpan:2, rowSpan:2, row:0}, + { id: "sido", title: "시도", upName:"upChangeRe", row:2 }, + { id: "sigungo", title: "시군구", upName:"upChangeRe", row:2 }, + { id: "swtrmtFcltNm", title: "시설명", rowSpan:3, row:0}, + { id: "location", title: "주소", rowSpan:3, row:0, }, + { id: "fctCpc", title: "시설용량(m³/일)", align:"right", rowSpan:3, row:0}, + { id: "B", title: "시설계획", colSpan:19, row:0}, + { id: "C", title: "증설계획(m³/일)", colSpan:6, row:1}, + { id: "planSwageQntSumDt4", title: "기승인\n4단계", row:2}, + { id: "planSwageQntSum", title: "현재", row:2}, + { id: "planSwageQntSumDc1", title: "1단계", row:2}, + { id: "planSwageQntSumDc2", title: "2단계", row:2}, + { id: "planSwageQntSumDc3", title: "3단계", row:2}, + { id: "planSwageQntSumDc4", title: "4단계", row:2}, + { id: "D", title: "처리인구(인)", colSpan:6, row:1}, + { id: "swtrmtPpltnCntDt4", title: "기승인\n4단계", row:2}, + { id: "swtrmtPpltnCnt", title: "현재", row:2}, + { id: "swtrmtPpltnCntDc1", title: "1단계", row:2}, + { id: "swtrmtPpltnCntDc2", title: "2단계", row:2}, + { id: "swtrmtPpltnCntDc3", title: "3단계", row:2}, + { id: "swtrmtPpltnCntDc4", title: "4단계", row:2}, + { id: "E", title: "처리구역(km²)", colSpan:7, row:1}, + { id: "swtrmtZoneAreaDt4", title: "기승인\n4단계", row:2}, + { id: "swtrmtZoneArea", title: "현재", row:2}, + { id: "swtrmtZoneAreaDc1", title: "1단계", row:2}, + { id: "swtrmtZoneAreaDc2", title: "2단계", row:2}, + { id: "swtrmtZoneAreaDc3", title: "3단계", row:2}, + { id: "swtrmtZoneAreaDc4", title: "4단계", row:2}, + { id: "trtDstr", title: "처리구역", row:2} +]; + +const processAreaList:ProcessAreaProps[] = [ +] + +/** + * 처리구역정보 상세팝업 + */ +// 시설증설 계획 (헤더) +const upHeadListFcltyImproveInfo:TableUpperProps[] = [ + { id: "planSwageQntSumDt4", title: "기승인\n4단계(m³/일)", rowSpan:2, row:0}, + { id: "A", title: "증설계획(m³/일)", colSpan:5, row:0}, + { id: "planSwageQntSum", title: "현재", row:1}, + { id: "planSwageQntSumDc1", title: "1단계", row:1}, + { id: "planSwageQntSumDc2", title: "2단계", row:1}, + { id: "planSwageQntSumDc3", title: "3단계", row:1}, + { id: "planSwageQntSumDc4", title: "4단계", row:1}, +]; + +// 시설증설 계획 (리스트) +const gridListFcltyImproveInfo:FcltyImproveInfoProps[] = [ +]; + +// 처리인구 계획 (헤더) +const upHeadListProcessPopulation:TableUpperProps[] = [ + { id: "swtrmtPpltnCntDt4", title: "기승인\n4단계(인)", rowSpan:2, row:0}, + { id: "A", title: "처리인구(인)", colSpan:5, row:0}, + { id: "swtrmtPpltnCnt", title: "현재", row:1}, + { id: "swtrmtPpltnCntDc1", title: "1단계", row:1}, + { id: "swtrmtPpltnCntDc2", title: "2단계", row:1}, + { id: "swtrmtPpltnCntDc3", title: "3단계", row:1}, + { id: "swtrmtPpltnCntDc4", title: "4단계", row:1}, +]; + +// 처리인구 계획 (리스트) +const gridListProcessPopulation:ProcessPopulationProps[] = [ +]; + +// 처리구역 계획 (헤더) +const upHeadListProcessAreaPlan:TableUpperProps[] = [ + { id: "swtrmtZoneAreaDt4", title: "기승인\n4단계(km²)", rowSpan:2, row:0}, + { id: "A", title: "처리면적(km²)", colSpan:6, row:0}, + { id: "swtrmtZoneArea", title: "현재", row:1}, + { id: "swtrmtZoneAreaDc1", title: "1단계", row:1}, + { id: "swtrmtZoneAreaDc2", title: "2단계", row:1}, + { id: "swtrmtZoneAreaDc3", title: "3단계", row:1}, + { id: "swtrmtZoneAreaDc4", title: "4단계", row:1}, + { id: "trtDstr", title: "처리구역", row:1} +]; + +// 시설증설 계획 (리스트) +const gridListProcessAreaPlan:ProcessAreaPlanProps[] = [ +]; + +/**==================================== + * Store - API +=====================================*/ +// 시설 상세 정보 조회 API +const fetchFacilityDetailInfo = async (swtrmtFcltCd: string) => { + try { + const tailUrl = '/1/5/A/0/0/0/SW'; + const res = await postFetch('fo', '/prcsFclt/ruseInfo'+tailUrl, [swtrmtFcltCd]); + return { data:res.data, count:res.count }; + } catch (error) { + console.error('시설정보 데이터를 가져오는데 실패했습니다:', error); + return {data: [], count: 0}; + } +}; + +// 시설정보 리스트 데이터 호출(구분 선택 후 시설명 있을 경우) +const fetchProcessAreaList = async (pageNo : number, pageSize : number, ctpvNm : string | undefined, sggNm : string | undefined, targetYear : string | undefined ): Promise<{data:ProcessAreaProps[], count:number}> => { + try { + targetYear = targetYear ? targetYear : "2024"; + const baseUrl = 'https://apigateway.rsonesoft.com/dc-service/api/v1/nowDmgMtncGnsvy'; + const queryParams = new URLSearchParams(); + + if (ctpvNm && ctpvNm !== '전체') queryParams.append('ctpvNm', ctpvNm); + if (sggNm && sggNm !== '전체') queryParams.append('sggNm', sggNm); + if (targetYear) queryParams.append('targetYear',targetYear); + + const queryString = queryParams.toString(); + const url = queryString ? `${baseUrl}?${queryString}` : baseUrl; + const res = await getFetchAreaList(url); + + if(res && res.length > 0){ + const enrichedData = await Promise.all( + res.map(async (item: ProcessAreaProps) => { + upHeadList1.forEach((head:TableUpperProps) => { + if (head.id === 'planSwageQntSum' || head.id === 'swtrmtPpltnCnt' || head.id === 'swtrmtZoneArea') { + head.title = '현재\n(' + item.yr + '년)'; + } else if(head.id === 'planSwageQntSumDc1' || head.id === 'swtrmtPpltnCntDc1' || head.id === 'swtrmtZoneAreaDc1') { + head.title = '1단계\n(' + item.yrDc1 + '년)'; + } else if(head.id === 'planSwageQntSumDc2' || head.id === 'swtrmtPpltnCntDc2' || head.id === 'swtrmtZoneAreaDc2') { + head.title = '2단계\n(' + item.yrDc2 + '년)'; + } else if(head.id === 'planSwageQntSumDc3' || head.id === 'swtrmtPpltnCntDc3' || head.id === 'swtrmtZoneAreaDc3') { + head.title = '3단계\n(' + item.yrDc3 + '년)'; + } else if(head.id === 'planSwageQntSumDc4' || head.id === 'swtrmtPpltnCntDc4' || head.id === 'swtrmtZoneAreaDc4') { + head.title = '4단계\n(' + item.yrDc4 + '년)'; + } else if(head.id === 'planSwageQntSumDt4' || head.id === 'swtrmtPpltnCntDt4' || head.id === 'swtrmtZoneAreaDt4') { + head.title = '기승인\n4단계(' + item.yrDt4 + '년)'; + } + }); + const res = await fetchFacilityDetailInfo(item.swtrmtFcltCd); + const detailInfo = res.data.filter((item:ProcessAreaProps) => item.ruse === true); + return { + ...item, + sido: detailInfo.length > 0 ? detailInfo[0].sido||'' : '', + sigungo: detailInfo.length > 0 ? detailInfo[0].gugun||'' : '', + location: detailInfo.length > 0 ? detailInfo[0].addr||'' : '', + fctCpc: detailInfo.length > 0 ? detailInfo[0].fctCpc||'' : 0, + trtDstr: detailInfo.length > 0 ? detailInfo[0].trtDstr||'' : '', + }; + }) + ); + const startIndex = (pageNo - 1) * pageSize; + const endIndex = startIndex + pageSize; + const paginatedData = enrichedData.slice(startIndex, endIndex); + return {data: paginatedData, count: enrichedData.length}; + }else{ + return {data: [], count: 0}; + } + } catch (error) { + console.error('시설계획정보를 가져오는데 실패했습니다:', error); + return {data: [], count: 0}; + } +}; + +/**==================================== + * Store - expaort +=====================================*/ +export type ProcessAreaActions = { + searchProcessAreaList : (pageNo: number, pageSize: number, ctpvNm?:string, sggNm?:string, targetYear?:string) => void; + initModalData : (swtrmtFcltCd:string) => void; +} + +export type ProcessAreaType = { + ProcessAreaSearch: { + isInit: boolean; + processFacilityLabelArray:string[]; + }, + + ProcessArea : { + isInit: boolean; + upHeadList1: TableUpperProps[]; + processAreaList: ProcessAreaProps[]; + processAreaCount: number; + excelList: ExcelType[]; + }, + + ProcessAreaDetail : { + isInit: boolean; + upHeadListFcltyImproveInfo: TableUpperProps[]; + gridListFcltyImproveInfo: FcltyImproveInfoProps[]; // Changed from facilityAreaProps to ProcessAreaProps + upHeadListProcessPopulation: TableUpperProps[]; + gridListProcessPopulation: ProcessPopulationProps[]; // Changed from facilityAreaProps to ProcessAreaProps + upHeadListProcessAreaPlan: TableUpperProps[]; + gridListProcessAreaPlan: ProcessAreaPlanProps[]; // Changed from facilityAreaProps to ProcessAreaProps + }, +} + +export const processAreaInitState: ProcessAreaType = { + ProcessAreaSearch: { + isInit: false, + processFacilityLabelArray: ProcessFacilityLabelArray, + }, + + ProcessArea : { + isInit : false, + upHeadList1 : upHeadList1, + processAreaList : processAreaList, + processAreaCount : 0, + excelList : [] + }, + + ProcessAreaDetail : { + isInit : false, + upHeadListFcltyImproveInfo : upHeadListFcltyImproveInfo, + gridListFcltyImproveInfo : gridListFcltyImproveInfo, + upHeadListProcessPopulation : upHeadListProcessPopulation, + gridListProcessPopulation : gridListProcessPopulation, + upHeadListProcessAreaPlan : upHeadListProcessAreaPlan, + gridListProcessAreaPlan : gridListProcessAreaPlan, + }, +} + +// 상태 설정 함수 타입 정의 +type SetStateFunction = (state: ProcessAreaType | ((state: ProcessAreaType) => ProcessAreaType)) => void; + +export type ProcessAreaStore = ProcessAreaType & ProcessAreaActions; + +export const processAreaReducer:(set:SetStateFunction)=>ProcessAreaActions=(set: SetStateFunction) => { + return { + /** + * 시설정보 리스트 데이터 호출 + * @param pageNo : 페이지 번호 + * @param pageSize : 페이지 크기 + */ + searchProcessAreaList: async ( pageNo:number, pageSize:number, ctpvNm?:string, sggNm?:string, targetYear?:string) => { + const res = await fetchProcessAreaList(pageNo, pageSize, ctpvNm, sggNm, targetYear); + res.data.forEach((item:ProcessAreaProps) => { + DataForm({ type: 'float1', column: 'fctCpc', item:item as unknown as Record<string, unknown>}); + }) + const excelDownList: ExcelType[] = []; + if(pageSize>5000){ + res.data.forEach(item => { + item.fctCpc = item.fctCpc ? parseFloat(item.fctCpc.toString().replace(/,/g, '')) : ''; + excelDownList.push({ + 시설코드: item.swtrmtFcltCd, + 시설명: item.swtrmtFcltNm, + 주소: item.location, + 시설용량: item.fctCpc, + 증설계획기존: item.planSwageQntSumDt4, + 증설계획현재: item.planSwageQntSum, + 증설계획1단계: item.planSwageQntSumDc1, + 증설계획2단계: item.planSwageQntSumDc2, + 증설계획3단계: item.planSwageQntSumDc3, + 증설계획4단계: item.planSwageQntSumDc4, + 처리인구기존: item.swtrmtPpltnCntDt4, + 처리인구현재: item.swtrmtPpltnCnt, + 처리인구1단계: item.swtrmtPpltnCntDc1, + 처리인구2단계: item.swtrmtPpltnCntDc2, + 처리인구3단계: item.swtrmtPpltnCntDc3, + 처리인구4단계: item.swtrmtPpltnCntDc4, + 처리구역기존: item.swtrmtZoneAreaDt4, + 처리구역현재: item.swtrmtZoneArea, + 처리구역1단계: item.swtrmtZoneAreaDc1, + 처리구역2단계: item.swtrmtZoneAreaDc2, + 처리구역3단계: item.swtrmtZoneAreaDc3, + 처리구역4단계: item.swtrmtZoneAreaDc4, + 처리구역: item.trtDstr + }); + }); + }else{ + res.data.forEach(item => { + item.fctCpc = item.fctCpc ? parseFloat(item.fctCpc.toString().replace(/,/g, '')) : ''; + }) + } + set((state:ProcessAreaType) => ({ + ...state, + ProcessArea: pageSize<5000?{ + ...state.ProcessArea, + processAreaList: res.data, + processAreaCount: res.count, + }:{ + ...state.ProcessArea, + excelList: excelDownList, + }, + })) + }, + + initModalData: async (swtrmtFcltCd:string) => { + set((state: ProcessAreaType) => { + const rtnData = state.ProcessArea.processAreaList.find((item: ProcessAreaProps) => item.swtrmtFcltCd === swtrmtFcltCd); + if (rtnData) { + upHeadListFcltyImproveInfo.forEach((head:TableUpperProps) => { + if(head.id === 'planSwageQntSum' || head.id === 'swtrmtPpltnCnt' || head.id === 'swtrmtZoneArea') { + head.title = '현재\n(' + rtnData.yr + '년)'; + } else if(head.id === 'planSwageQntSumDc1' || head.id === 'swtrmtPpltnCntDc1' || head.id === 'swtrmtZoneAreaDc1') { + head.title = '1단계\n(' + rtnData.yrDc1 + '년)'; + } else if(head.id === 'planSwageQntSumDc2' || head.id === 'swtrmtPpltnCntDc2' || head.id === 'swtrmtZoneAreaDc2') { + head.title = '2단계\n(' + rtnData.yrDc2 + '년)'; + } else if(head.id === 'planSwageQntSumDc3' || head.id === 'swtrmtPpltnCntDc3' || head.id === 'swtrmtZoneAreaDc3') { + head.title = '3단계\n(' + rtnData.yrDc3 + '년)'; + } else if(head.id === 'planSwageQntSumDc4' || head.id === 'swtrmtPpltnCntDc4' || head.id === 'swtrmtZoneAreaDc4') { + head.title = '4단계\n(' + rtnData.yrDc4 + '년)'; + } else if(head.id === 'planSwageQntSumDt4' || head.id === 'swtrmtPpltnCntDt4' || head.id === 'swtrmtZoneAreaDt4') { + head.title = '기승인\n4단계(' + rtnData.yrDt4 + '년)'; + } + }); + + upHeadListProcessAreaPlan.forEach((head:TableUpperProps) => { + if(head.id === 'planSwageQntSum' || head.id === 'swtrmtPpltnCnt' || head.id === 'swtrmtZoneArea') { + head.title = '현재\n(' + rtnData.yr + '년)'; + } else if(head.id === 'planSwageQntSumDc1' || head.id === 'swtrmtPpltnCntDc1' || head.id === 'swtrmtZoneAreaDc1') { + head.title = '1단계\n(' + rtnData.yrDc1 + '년)'; + } else if(head.id === 'planSwageQntSumDc2' || head.id === 'swtrmtPpltnCntDc2' || head.id === 'swtrmtZoneAreaDc2') { + head.title = '2단계\n(' + rtnData.yrDc2 + '년)'; + } else if(head.id === 'planSwageQntSumDc3' || head.id === 'swtrmtPpltnCntDc3' || head.id === 'swtrmtZoneAreaDc3') { + head.title = '3단계\n(' + rtnData.yrDc3 + '년)'; + } else if(head.id === 'planSwageQntSumDc4' || head.id === 'swtrmtPpltnCntDc4' || head.id === 'swtrmtZoneAreaDc4') { + head.title = '4단계\n(' + rtnData.yrDc4 + '년)'; + } else if(head.id === 'planSwageQntSumDt4' || head.id === 'swtrmtPpltnCntDt4' || head.id === 'swtrmtZoneAreaDt4') { + head.title = '기승인\n4단계(' + rtnData.yrDt4 + '년)'; + } + }); + + upHeadListProcessPopulation.forEach((head:TableUpperProps) => { + if(head.id === 'planSwageQntSum' || head.id === 'swtrmtPpltnCnt' || head.id === 'swtrmtZoneArea') { + head.title = '현재\n(' + rtnData.yr + '년)'; + } else if(head.id === 'planSwageQntSumDc1' || head.id === 'swtrmtPpltnCntDc1' || head.id === 'swtrmtZoneAreaDc1') { + head.title = '1단계\n(' + rtnData.yrDc1 + '년)'; + } else if(head.id === 'planSwageQntSumDc2' || head.id === 'swtrmtPpltnCntDc2' || head.id === 'swtrmtZoneAreaDc2') { + head.title = '2단계\n(' + rtnData.yrDc2 + '년)'; + } else if(head.id === 'planSwageQntSumDc3' || head.id === 'swtrmtPpltnCntDc3' || head.id === 'swtrmtZoneAreaDc3') { + head.title = '3단계\n(' + rtnData.yrDc3 + '년)'; + } else if(head.id === 'planSwageQntSumDc4' || head.id === 'swtrmtPpltnCntDc4' || head.id === 'swtrmtZoneAreaDc4') { + head.title = '4단계\n(' + rtnData.yrDc4 + '년)'; + } else if(head.id === 'planSwageQntSumDt4' || head.id === 'swtrmtPpltnCntDt4' || head.id === 'swtrmtZoneAreaDt4') { + head.title = '기승인\n4단계(' + rtnData.yrDt4 + '년)'; + } + }); + + // 시설증설 계획 데이터 생성 + const fcltyImproveInfo: FcltyImproveInfoProps = { + planSwageQntSumDt4: rtnData.planSwageQntSumDt4, + planSwageQntSum: rtnData.planSwageQntSum, + planSwageQntSumDc1: rtnData.planSwageQntSumDc1, + planSwageQntSumDc2: rtnData.planSwageQntSumDc2, + planSwageQntSumDc3: rtnData.planSwageQntSumDc3, + planSwageQntSumDc4: rtnData.planSwageQntSumDc4 + }; + + // 처리인구 계획 데이터 생성 + const processPopulation: ProcessPopulationProps = { + swtrmtPpltnCntDt4: rtnData.swtrmtPpltnCntDt4, + swtrmtPpltnCnt: rtnData.swtrmtPpltnCnt, + swtrmtPpltnCntDc1: rtnData.swtrmtPpltnCntDc1, + swtrmtPpltnCntDc2: rtnData.swtrmtPpltnCntDc2, + swtrmtPpltnCntDc3: rtnData.swtrmtPpltnCntDc3, + swtrmtPpltnCntDc4: rtnData.swtrmtPpltnCntDc4 + }; + + // 처리구역 계획 데이터 생성 + const processAreaPlan: ProcessAreaPlanProps = { + swtrmtZoneAreaDt4: rtnData.swtrmtZoneAreaDt4, + swtrmtZoneArea: rtnData.swtrmtZoneArea, + swtrmtZoneAreaDc1: rtnData.swtrmtZoneAreaDc1, + swtrmtZoneAreaDc2: rtnData.swtrmtZoneAreaDc2, + swtrmtZoneAreaDc3: rtnData.swtrmtZoneAreaDc3, + swtrmtZoneAreaDc4: rtnData.swtrmtZoneAreaDc4, + trtDstr: rtnData.trtDstr + }; + + return { + ...state, + ProcessAreaDetail: { + ...state.ProcessAreaDetail, + gridListFcltyImproveInfo: [fcltyImproveInfo], + gridListProcessPopulation: [processPopulation], + gridListProcessAreaPlan: [processAreaPlan] + } + }; + } + return state; + }); + } + } +} \ No newline at end of file diff --git a/apps/fo/app/store/processFacility/index.tsx b/apps/fo/app/store/processFacility/index.tsx new file mode 100644 index 000000000..a8c04930d --- /dev/null +++ b/apps/fo/app/store/processFacility/index.tsx @@ -0,0 +1,832 @@ +import { getFetch } from "@/app/components/api"; +import DataForm from "@/app/components/common/DataForm"; +import type { TableUpperProps } from "../dashboard"; +export type { TableUpperProps }; + +/**==================================== + * Store - 타입 + ====================================*/ + +/** + * (1) 메인페이지 + */ +// 처리시설 리스트 +export type facilityListProps = { + bscFctCd : string, + bscFctNm : string, + bscFctClsNm : string, + sido : string, + gugun : string, + daddr : string, + fctCpc : number | string | '', + plInflWqltBod : number | string | '', + dsInflWqltBod : number | string | '', + trtFrfNm : string, + rnDt : string, + cmplDt : string, + trstOprEtpNm : string, + rvbsn : string, + mdmbsn : string, + lgbsn : string, + rgnNm : string, + mnstr : string, + efflWtrrgn : string, + efflWqltStndrdNm : string +} + +export interface ExcelType { + 시설코드: string, + 권역:string|'', + 단위유역:string|'', + 중권역:string|'', + 환경청:string|'', + 시도: string, + 시군구: string, + 시설이름: string, + 주소: string, + 시설용량: number | '', + 계획유입수질: number | '', + 설계유입수질: number | '', + 공법: string, + 가동개시일: string, + 준공일: string, + 관리대행업자: string, +} + +// (2) 처리시설 팝업 +// 시설 기본정보 +export type BasicInfoProps = { + bscFctNm : string, + fctCpc : number | '', + sido : string, + gugun : string, + startDay : string, + addr : string, + cmplDt : string, + trtFrfNm : string, + trstOprEtpNm : string, +} + +// 시설 계획정보 +export type PlanInfoProps = { + plInflWqltBod? : string, + plInflWqltToc? : string, + plInflWqltCod? : string, + plInflWqltSs? : string, + plInflWqltTn? : string, + plInflWqltTp? : string, + dsInflWqltBod? : string, + dsInflWqltToc? : string, + dsInflWqltCod? : string, + dsInflWqltSs? : string, + dsInflWqltTn? : string, + dsInflWqltTp? : string, + sitArea? : string | number, + trtDstrArea? : string | number, + swrTrtPopl? : string | number +} + +// 시설 계획정보 +export type LegalWaterQltyProps = { + totClfgrpcnt : number, + bod : number, + cod : number, + ss : number, + tn : number, + tp : number +} + +// 시설 수역 및 구역정보 +export type fcltyAreaInfoProps = { + rvbsn : string, + efflWtrrgn : string, + lgbsn : string, + efflWqltStndrdNm : string, + rgnNm : string, +} + +// 시설 이력관리 +export type fcltyHistInfoProps = { + extnsSeqno : string, + extnsNm : string, + bzStrtYrMnth : string, + bzEdYrMnth : string, + eqpPrmsDt : string, + cmplDt : string, + trlrnCmplDt : string, + rnDt : string, + sitArea : number, + trtDstrArea : number, + swrTrtPopl : number +} + +// 시설 수질정보 +export type fcltyWaterQltyInfoProps = { + extnsSeqno : string, + plInflWqltBod : string, + plInflWqltToc : string, + plInflWqltCod : string, + plInflWqltSs : string, + plInflWqltTn : string, + plInflWqltTp : string, + dsInflWqltBod : string, + dsInflWqltToc : string, + dsInflWqltCod : string, + dsInflWqltSs : string, + dsInflWqltTn : string, + dsInflWqltTp : string, + plEfflWqltBod : string, + plEfflWqltToc : string, + plEfflWqltCod : string, + plEfflWqltSs : string, + plEfflWqltTn : string, + plEfflWqltTp : string, + bod : number, + cod : number, + ss : number, + tn : number, + tp : number, + totClfgrpcnt : number, +} + +/**==================================== + * Store - data + ====================================*/ + +/** + * (1) 메인페이지 + */ +// 검색단 +const ProcessFacilityLabelArray:string[] = ['구분', '시도', '시군구','용량별', '시설명', '시설상태', '시설구분', '권역', '단위유역', '중권역', '환경청별']; + +// 리스트 헤더 +const upHeadList1:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드"}, + { id: "sido", title: "시도", upName:"upChangeRe", upSequnce:1 }, + { id: "gugun", title: "시군구", upName:"upChangeRe",upSequnce:2 }, + { id: "bscFctNm", title: "시설명"}, + { id: "daddr", title: "주소"}, + { id: "fctCpc", title: "시설용량\n(m³/일)", align: 'right'}, + { id: "plInflWqltBod", title: "계획유입수질\n(mg/L)", align:"right"}, + { id: "dsInflWqltBod", title: "설계유입수질\n(mg/L)", align:"right"}, + { id: "trtFrfNm", title: '공법'}, + { id: "rnDt", title: '가동개시일'}, + { id: "cmplDt", title: '준공일' }, + { id: "trstOprEtpNm", title: '관리대행업자'} +]; + +// 처리시설 리스트 (유역) +const upHeadList2:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드"}, + { id: "rvbsn", title: "권역", upName:"upChangeRe", upSequnce:1}, + { id: "lgbsn", title: "단위유역", upName:"upChangeRe", upSequnce:2}, + { id: "mdmbsn", title: "중권역", upName:"upChangeRe", upSequnce:3}, + { id: "bscFctNm", title: "시설명"}, + { id: "daddr", title: "주소"}, + { id: "fctCpc", title: "시설용량\n(m³/일)", align: 'right'}, + { id: "plInflWqltBod", title: "계획유입수질\n(mg/L)", align:'right'}, + { id: "dsInflWqltBod", title: "설계유입수질\n(mg/L)", align:'right'}, + { id: "trtFrfNm", title: '공법'}, + { id: "rnDt", title: '가동개시일'}, + { id: "cmplDt", title: '준공일' }, + { id: "trstOprEtpNm", title: '관리대행업자'} +]; + +// 처리시설 리스트 (환경청청) +const upHeadList3:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드"}, + { id: "rvbsn", title: "권역", upName:"upChangeRe1", upSequnce:1}, + { id: "lgbsn", title: "단위유역", upName:"upChangeRe1", upSequnce:2}, + { id: "mdmbsn", title: "중권역", upName:"upChangeRe1", upSequnce:3}, + { id: "rgnNm", title: "환경청"}, + { id: "sido", title: "시도", upName:"upChangeRe2", upSequnce:1 }, + { id: "gugun", title: "시군구", upName:"upChangeRe2",upSequnce:2 }, + { id: "bscFctNm", title: "시설명"}, + { id: "daddr", title: "주소"}, + { id: "fctCpc", title: "시설용량\n(m³/일)", align: 'right'}, + { id: "plInflWqltBod", title: "계획유입수질\n(mg/L)", align:'right'}, + { id: "dsInflWqltBod", title: "설계유입수질\n(mg/L)", align:'right'}, + { id: "trtFrfNm", title: '공법'}, + { id: "rnDt", title: '가동개시일'}, + { id: "cmplDt", title: '준공일' }, + { id: "trstOprEtpNm", title: '관리대행업자'} +]; + +const processFacilityList:facilityListProps[] = [ +] + +/** + * 처리시설 상세팝업 + */ +// 시설 기본정보 (헤더) +const upHeadListBasicInfo:TableUpperProps[] = [ + { id: "bscFctNm", title: "시설명" }, + { id: "fctCpc", title: "시설용량n(m³/일)", align: 'right'}, + { id: "sido", title: "시도"}, + { id: "gugun", title: "시군구"}, + { id: "rnDt", title: "가동개시일"}, + { id: "daddr", title: "주소"}, + { id: "cmplDt", title: "준공일"}, + { id: "trtFrfNm", title: "공법"}, + { id: "trstOprEtpNm", title: "관리대행업자"}, +]; + +// 시설 기본정보 (리스트) +const gridListBasicInfo:BasicInfoProps[] = [ + { + bscFctNm : "난지", + fctCpc : 860000, + sido : "서울특별시", + gugun : "", + startDay : "1987-06-30", + addr : "경기도 고양시 덕양구 대덕로 426 (현천동)", + cmplDt : "2013-04-30", + trtFrfNm : "MLE, A2O", + trstOprEtpNm : "자체", + } +]; + +// 시설 법적방류수질 (헤더) +const upHeadListLegalWaterQlty:TableUpperProps[] = [ + { id: "bod", title: "BOD(mg/L)", align: 'right'}, + { id: "cod", title: "TOC(COD)(mg/L)", align: 'right'}, + { id: "ss", title: "SS(mg/L)", align: 'right'}, + { id: "tn", title: "T-N(mg/L)", align: 'right'}, + { id: "tp", title: "T-P(mg/L) ", align: 'right'}, + { id: "totClfgrpcnt", title: "대장균군(개/100ml)"}, +] + +// 시설 법적방류수질 (리스트) +let gridListLegalWaterQlty:LegalWaterQltyProps[] = [ +] + +// 시설 계획정보 (헤더) +const upHeadListPlanInfo:TableUpperProps[] = [ + { id: "plInflWqltBod", title: "BOD", upName:"upChangeRe1", upSequnce:1, align: 'right' }, + { id: "plInflWqltToc", title: "TOC", upName:"upChangeRe1", upSequnce:2, align: 'right' }, + { id: "plInflWqltCod", title: "COD", upName:"upChangeRe1", upSequnce:3, align: 'right' }, + { id: "plInflWqltSs", title: "SS", upName:"upChangeRe1", upSequnce:4, align: 'right' }, + { id: "plInflWqltTn", title: "T-N", upName:"upChangeRe1", upSequnce:5, align: 'right' }, + { id: "plInflWqltTp", title: "T-P", upName:"upChangeRe1", upSequnce:6, align: 'right' }, + { id: "dsInflWqltBod", title: "BOD", upName:"upChangeRe2", upSequnce:1, align: 'right' }, + { id: "dsInflWqltToc", title: "TOC", upName:"upChangeRe2", upSequnce:2, align: 'right' }, + { id: "dsInflWqltCod", title: "COD", upName:"upChangeRe2", upSequnce:3, align: 'right' }, + { id: "dsInflWqltSs", title: "SS", upName:"upChangeRe2", upSequnce:4, align: 'right' }, + { id: "dsInflWqltTn", title: "T-N", upName:"upChangeRe2", upSequnce:5, align: 'right' }, + { id: "dsInflWqltTp", title: "T-P", upName:"upChangeRe2", upSequnce:6, align: 'right' }, + { id: "sitArea", title: "부지면적\n(m²)", align: 'right'}, + { id: "trtDstrArea", title: "처리구역면적\n(ha)", align: 'right'}, + { id: "swrTrtPopl", title: "하수처리인구\n(인)", align: 'right'}, +]; + +// 시설 계획정보 (리스트) +const gridListPlanInfo:PlanInfoProps[] = [ + { + plInflWqltBod : "179.0", + plInflWqltToc : "90.0", + plInflWqltCod : "0.0", + plInflWqltSs : "132.0", + plInflWqltTn : "38.000", + plInflWqltTp : "4.300", + dsInflWqltBod : "178.0", + dsInflWqltToc : "91.0", + dsInflWqltCod : "0.0", + dsInflWqltSs : "131.0", + dsInflWqltTn : "40.200", + dsInflWqltTp : "4.500", + sitArea : "928,574", + trtDstrArea : "7,994.0", + swrTrtPopl : "1,573,277", + } +]; + +// 시설 수역 및 구역정보 (헤더) +const upHeadListFcltyAreaInfo:TableUpperProps[] = [ + { id: "rvbsn", title: "하천명" }, + { id: "efflWtrrgn", title: "방류수역"}, + { id: "lgbsn", title: "단위유역"}, + { id: "efflWqltStndrdNm", title: "지역구분"}, + { id: "rgnNm", title: "관할 유역(지방) 환경청"} +]; + +// 시설 수역 및 구역정보 (리스트) +const gridListFcltyAreaInfo:fcltyAreaInfoProps[] = [ + { + rvbsn : "한강", + efflWtrrgn : "한강수계", + lgbsn : "한강본류", + efflWqltStndrdNm : "500톤 이상\n(Ⅲ지역)", + rgnNm : "한강유역환경청" + } +]; + +// 시설 이력관리 (헤더) +const upHeadListFcltyHistInfo:TableUpperProps[] = [ + { id: "extnsSeqno", title: "차수", align: 'center' }, + { id: "extnsNm", title: "구분"}, + { id: "bzStrtYrMnth", title: "사업기간", upName:"upChangeRe1", upSequnce:1}, + { id: "bzEdYrMnth", title: "사업기간", upName:"upChangeRe1", upSequnce:2}, + { id: "eqpPrmsDt", title: "설치인가일"}, + { id: "cmplDt", title: "준공일"}, + { id: "trlrnCmplDt", title: "시운전완료일"}, + { id: "rnDt", title: "가동개시일"}, +]; + +// 시설 이력관리 (리스트) +const gridListFcltyHistInfo:fcltyHistInfoProps[] = [ + { + extnsSeqno : "최초", + extnsNm : "최초", + bzStrtYrMnth : "1984.12.01", + bzEdYrMnth : "1987.06.01", + eqpPrmsDt : "1985.09.13", + cmplDt : "1987.06.30", + trlrnCmplDt : "1987.06.30", + rnDt : "1987.06.30", + sitArea : 0, + trtDstrArea : 0, + swrTrtPopl : 0, + } +]; + +// 시설 수질정보 (헤더) +const upHeadListFcltyWaterQltyInfo:TableUpperProps[] = [ + { id: "extnsSeqno", title: "차수" }, + { id: "plInflWqltBod", title: "BOD", upName:"upChangeRe1", upSequnce:1, align: 'right' }, + { id: "plInflWqltToc", title: "TOC", upName:"upChangeRe1", upSequnce:2, align: 'right' }, + { id: "plInflWqltCod", title: "COD", upName:"upChangeRe1", upSequnce:3, align: 'right' }, + { id: "plInflWqltSs", title: "SS", upName:"upChangeRe1", upSequnce:4, align: 'right' }, + { id: "plInflWqltTn", title: "T-N", upName:"upChangeRe1", upSequnce:5, align: 'right' }, + { id: "plInflWqltTp", title: "T-P", upName:"upChangeRe1", upSequnce:6, align: 'right' }, + { id: "dsInflWqltBod", title: "BOD", upName:"upChangeRe2", upSequnce:1, align: 'right' }, + { id: "dsInflWqltToc", title: "TOC", upName:"upChangeRe2", upSequnce:2, align: 'right' }, + { id: "dsInflWqltCod", title: "COD", upName:"upChangeRe2", upSequnce:3, align: 'right' }, + { id: "dsInflWqltSs", title: "SS", upName:"upChangeRe2", upSequnce:4, align: 'right' }, + { id: "dsInflWqltTn", title: "T-N", upName:"upChangeRe2", upSequnce:5, align: 'right' }, + { id: "dsInflWqltTp", title: "T-P", upName:"upChangeRe2", upSequnce:6, align: 'right' }, + { id: "plEfflWqltBod", title: "BOD", upName:"upChangeRe3", upSequnce:1, align: 'right' }, + { id: "plEfflWqltToc", title: "TOC", upName:"upChangeRe3", upSequnce:2, align: 'right' }, + { id: "plEfflWqltCod", title: "COD", upName:"upChangeRe3", upSequnce:3, align: 'right' }, + { id: "plEfflWqltSs", title: "SS", upName:"upChangeRe3", upSequnce:4, align: 'right' }, + { id: "plEfflWqltTn", title: "T-N", upName:"upChangeRe3", upSequnce:5, align: 'right' }, + { id: "plEfflWqltTp", title: "T-P", upName:"upChangeRe3", upSequnce:6, align: 'right' }, +]; + +// 시설 수질정보 (리스트) +const gridListFcltyWaterQltyInfo:fcltyWaterQltyInfoProps[] = [ + { + extnsSeqno: "최초", + plInflWqltBod: "111.0", + plInflWqltToc: "(0.0)", + plInflWqltCod: "(0.0)", + plInflWqltSs: "122.0", + plInflWqltTn: "0.000", + plInflWqltTp: "0.000", + dsInflWqltBod: "111.0", + dsInflWqltToc: "(0.0)", + dsInflWqltCod: "(0.0)", + dsInflWqltSs: "122.0", + dsInflWqltTn: "0.000", + dsInflWqltTp: "0.000", + plEfflWqltBod: "20.0", + plEfflWqltCod: "(0.0)", + plEfflWqltToc: "(0.0)", + plEfflWqltSs: "12.0", + plEfflWqltTn: "0.000", + plEfflWqltTp: "0.000", + bod: 0, + cod: 0, + ss: 0, + tn: 0, + tp: 0, + totClfgrpcnt: 0 + } +]; + +/**==================================== + * Store - api (데이터 호출) + ====================================*/ + +// 시설정보 리스트 데이터 호출(구분 선택 후 시설명 있을 경우) +const fetchFacilityList = async (pageNo:number, pageSize:number, partValue?:string, nameCd?:string, fcltCpct?:string, oprtngSttsCd?:string, facilityPartValue?:string, facilityName?:string ): Promise<{data:facilityListProps[], count:number}> => { + try { + const tailStr = partValue ? '/'+ (partValue==='G' ? 'A' : partValue) + '/' + nameCd + '/' + fcltCpct + '/' + oprtngSttsCd + '/' + facilityPartValue + (facilityName && facilityName !== '' ? '/' + facilityName : '') : ''; + const url = '/prcsFclt/info/history/'+pageNo+'/'+pageSize+tailStr; + //const res = await getFetch('fo', '/prcsFclt/info/'+pageNo+'/'+pageSize+tailUrl); + const res = await getFetch('fo', url); + return res; + } catch (error) { + console.error('시설정보 데이터를 가져오는데 실패했습니다:', error); + return {data: [], count: 0}; + } +}; + +// 시설정보 리스트 데이터 호출 (대시보드용) +const fetchFacilityListSearching = async (pageNo:number, pageSize:number, partValue?:string, nameCd?:string, fcltCpct?:string, oprtngSttsCd?:string, facilityPartValue?:string, facilityName?:string ): Promise<{data:facilityListProps[], count:number}> => { + try { + const tailStr = partValue ? '/'+ (partValue==='G' ? 'A' : partValue) + '/' + nameCd + '/' + fcltCpct + '/' + oprtngSttsCd + '/' + facilityPartValue + (facilityName && facilityName !== '' ? '/' + facilityName : '') : ''; + const url = '/prcsFclt/searching/'+pageNo+'/'+pageSize+tailStr; + //const res = await getFetch('fo', '/prcsFclt/info/'+pageNo+'/'+pageSize+tailUrl); + const res = await getFetch('fo', url); + return res; + } catch (error) { + console.error('시설정보 데이터를 가져오는데 실패했습니다:', error); + return {data: [], count: 0}; + } +}; + +// 모달 +// 시설정보 이력정보 데이터 호출 +const fetchFacilityHistInfo = async (facilityCd:string ): Promise<fcltyHistInfoProps[]> => { + try { + const res = await getFetch('fo', '/prcsFclt/hist/'+facilityCd); + const data = res.data; + DataForm({ type: 'date', column: 'trlrnCmplDt', item: data as unknown as Record<string, unknown> }); + DataForm({ type: 'date', column: 'eqpPrmsDt', item: data as unknown as Record<string, unknown> }); + DataForm({ type: 'date', column: 'cmplDt', item: data as unknown as Record<string, unknown> }); + DataForm({ type: 'date', column: 'rnDt', item: data as unknown as Record<string, unknown> }); + DataForm({ type: 'number', column: 'sitArea', item: data as unknown as Record<string, unknown> }); + DataForm({ type: 'number', column: 'trtDstrArea', item: data as unknown as Record<string, unknown> }); + DataForm({ type: 'number', column: 'swrTrtPopl', item: data as unknown as Record<string, unknown> }); + return data; + } catch (error) { + console.error('시설정보 이력정보 데이터를 가져오는데 실패했습니다:', error); + return []; + } +}; + +// 시설정보 수질정보 데이터 호출 +const fetchFacilityWaterQltyInfo = async (facilityCd:string ): Promise<fcltyWaterQltyInfoProps[]> => { + try { + const res = await getFetch('fo', '/prcsFclt/info/history/'+facilityCd); + const data = res.data; + return data; + } catch (error) { + console.error('시설정보 수질정보 데이터를 가져오는데 실패했습니다:', error); + return []; + } +}; + +/**==================================== + * Store - expaort + ====================================*/ +export type ProcessFacilityActions = { + /** + * 시설정보 리스트 데이터 호출(구분 선택 후 시설명 있을 경우) + * @param pageNo : 페이지 번호 + * @param pageSize : 페이지 크기 + * @param partValue : 구분값(행정명, 대유역, 환경청) + * @param nameCd : 행정코드(시도명, 시군구명, 단위유역) + * @param fcltCpct : 시설용량 + * @param oprtngSttsCd : 운영 상태 코드 + * @param facilityName : 시설명 + */ + searchProcessFacility : (pageNo:number, pageSize:number, partValue?:string, nameCd?:string, fcltCpct?:string, oprtngSttsCd?:string, facilityPartValue?:string, facilityName?:string) => void; + + /** + * 시설정보 이력정보 데이터 호출 + * @param facilityCd : 시설코드 + */ + searchProcessFacilityHist : (facilityCd:string) => void; + + /** + * 시설정보 수질정보 데이터 호출 + * @param facilityCd : 시설코드 + */ + searchProcessFacilityWaterQlty : (facilityCd:string) => void; + + /** + * 시설정보 리스트 데이터 호출 (대시보드용) + * @param pageNo : 페이지 번호 + * @param pageSize : 페이지 크기 + */ + searchProcessFacilitySearching : (pageNo:number, pageSize:number, partValue?:string, nameCd?:string, fcltCpct?:string, oprtngSttsCd?:string, facilityPartValue?:string, facilityName?:string) => void; +} + +export type ProcessFacilityType = { + ProcessFacility: { + isInit: boolean; + processFacilityLabelArray:string[]; + }, + + ProcessFacilityList : { + isInit: boolean; + upHeadList1:TableUpperProps[]; + upHeadList2:TableUpperProps[]; + upHeadList3:TableUpperProps[]; + processFacilityList:facilityListProps[]; + processFacilityCount:number; + excelList : ExcelType[]; + }, + + ProcessFacilityDetail : { + isInit : boolean; + upHeadListBasicInfo : TableUpperProps[]; + gridListBasicInfo : BasicInfoProps[]; + upHeadListPlanInfo : TableUpperProps[]; + gridListPlanInfo : PlanInfoProps[]; + upHeadListFcltyAreaInfo : TableUpperProps[]; + gridListFcltyAreaInfo : fcltyAreaInfoProps[]; + + upHeadListFcltyHistInfo : TableUpperProps[]; + gridListFcltyHistInfo : fcltyHistInfoProps[]; + upHeadListFcltyWaterQltyInfo : TableUpperProps[]; + gridListFcltyWaterQltyInfo : fcltyWaterQltyInfoProps[]; + + upHeadListLegalWaterQlty : TableUpperProps[]; + gridListLegalWaterQlty : LegalWaterQltyProps[]; + }, +} + +export const processFacilityInitState:ProcessFacilityType = { + ProcessFacility: { + isInit: false, + processFacilityLabelArray: ProcessFacilityLabelArray, + }, + + ProcessFacilityList : { + isInit : false, + upHeadList1 : upHeadList1, + upHeadList2 : upHeadList2, + upHeadList3 : upHeadList3, + processFacilityList : processFacilityList, + processFacilityCount:1, + excelList : [] + }, + + ProcessFacilityDetail : { + isInit : false, + upHeadListBasicInfo : upHeadListBasicInfo, + gridListBasicInfo : gridListBasicInfo, + upHeadListPlanInfo : upHeadListPlanInfo, + gridListPlanInfo : gridListPlanInfo, + upHeadListFcltyAreaInfo : upHeadListFcltyAreaInfo, + gridListFcltyAreaInfo : gridListFcltyAreaInfo, + + upHeadListFcltyHistInfo : upHeadListFcltyHistInfo, + gridListFcltyHistInfo : gridListFcltyHistInfo, + upHeadListFcltyWaterQltyInfo : upHeadListFcltyWaterQltyInfo, + gridListFcltyWaterQltyInfo : gridListFcltyWaterQltyInfo, + + upHeadListLegalWaterQlty : upHeadListLegalWaterQlty, + gridListLegalWaterQlty : gridListLegalWaterQlty, + } +} + +// 상태 설정 함수 타입 정의 +type SetStateFunction = (state: ProcessFacilityType | ((state: ProcessFacilityType) => ProcessFacilityType)) => void; + +export type ProcessFacilityStore = ProcessFacilityType & ProcessFacilityActions; + +export const processFacilityReducer:(set:SetStateFunction)=>ProcessFacilityActions=(set: SetStateFunction) => { + return{ + // 메인페이지 + + /** + * 시설정보 리스트 데이터 호출 + * @param pageNo : 페이지 번호 + * @param pageSize : 페이지 크기 + */ + searchProcessFacility: async (pageNo:number, pageSize:number, partValue?:string, nameCd?:string, fcltCpct?:string, oprtngSttsCd?:string, facilityPartValue?:string, facilityName?:string) => { + const res = await fetchFacilityList(pageNo, pageSize, partValue, nameCd, fcltCpct, oprtngSttsCd, facilityPartValue, facilityName); + res.data.forEach((item:facilityListProps) => { + DataForm({ type: 'date', column: 'cmplDt', item:item as unknown as Record<string, unknown>}); + DataForm({ type: 'date', column: 'rnDt', item:item as unknown as Record<string, unknown>}); + DataForm({ type: 'float1', column: 'fctCpc', item:item as unknown as Record<string, unknown>}); + }) + + res.data.forEach(item => { + item.plInflWqltBod = item.plInflWqltBod ? Number(item.plInflWqltBod).toFixed(1) : ''; + item.dsInflWqltBod = item.dsInflWqltBod ? Number(item.dsInflWqltBod).toFixed(1) : ''; + }) + + const excelDownList: ExcelType[] = []; + + if(pageSize>5000){ + res.data.forEach(item => { + item.fctCpc = item.fctCpc ? parseFloat(item.fctCpc.toString().replace(/,/g, '')) : ''; + excelDownList.push({ + 시설코드: item.bscFctCd, + 권역: item.rvbsn, + 단위유역: item.lgbsn, + 중권역: item.mdmbsn, + 환경청: item.rgnNm, + 시도: item.sido, + 시군구: item.gugun, + 시설이름: item.bscFctNm, + 주소: item.daddr, + 시설용량: item.fctCpc ? Number(item.fctCpc) : '', + 계획유입수질: item.plInflWqltBod ? Number(item.plInflWqltBod) : '', + 설계유입수질: item.dsInflWqltBod ? Number(item.dsInflWqltBod) : '', + 공법: item.trtFrfNm, + 가동개시일: item.rnDt, + 준공일: item.cmplDt, + 관리대행업자: item.mnstr, + }) + }) + }else{ + res.data.forEach(item => { + item.fctCpc = item.fctCpc ? parseFloat(item.fctCpc.toString().replace(/,/g, '')) : ''; + }) + } + set((state:ProcessFacilityType) => ({ + ...state, + ProcessFacilityList: pageSize<5000?{ + ...state.ProcessFacilityList, + processFacilityList: res.data, + processFacilityCount: res.count, + }:{ + ...state.ProcessFacilityList, + excelList: excelDownList, + }, + })) + }, + + /** + * 시설정보 리스트 데이터 호출 + * @param pageNo : 페이지 번호 + * @param pageSize : 페이지 크기 + */ + searchProcessFacilitySearching: async (pageNo:number, pageSize:number, partValue?:string, nameCd?:string, fcltCpct?:string, oprtngSttsCd?:string, facilityPartValue?:string, facilityName?:string) => { + const res = await fetchFacilityListSearching(pageNo, pageSize, partValue, nameCd, fcltCpct, oprtngSttsCd, facilityPartValue, facilityName); + /* res.data.forEach((item:facilityListProps) => { + DataForm({ type: 'date', column: 'cmplDt', item:item as unknown as Record<string, unknown>}); + DataForm({ type: 'date', column: 'rnDt', item:item as unknown as Record<string, unknown>}); + }) + + res.data.forEach(item => { + item.plInflWqltBod = item.plInflWqltBod ? Number(item.plInflWqltBod).toFixed(1) : ''; + item.dsInflWqltBod = item.dsInflWqltBod ? Number(item.dsInflWqltBod).toFixed(1) : ''; + }) */ + console.log(res.data); + set((state:ProcessFacilityType) => ({ + ...state, + ProcessFacilityList: { + ...state.ProcessFacilityList, + processFacilityList: res.data, + processFacilityCount: res.count, + }, + })) + }, + + + // 모달 이력정보 + /** + * 시설정보 이력정보 데이터 호출 + * @param facilityCd : 시설코드 + */ + searchProcessFacilityHist: async (facilityCd:string) => { + const promiseSet = await Promise.all([fetchFacilityHistInfo(facilityCd)]); + const [facilityHistInfo] = promiseSet; + // extnsSeqno를 기준으로 오름차순 정렬 + const sortedHistInfo = [...facilityHistInfo].sort((a, b) => { + // 숫자로 변환하여 비교 + const numA = Number(a.extnsSeqno); + const numB = Number(b.extnsSeqno); + if (!isNaN(numA) && !isNaN(numB)) { + return numA - numB; + } + // 숫자 변환이 실패하면 문자열로 비교 + return String(a.extnsSeqno).localeCompare(String(b.extnsSeqno)); + }); + + sortedHistInfo.forEach(item => { + if(item.extnsSeqno == '0'){ + item.extnsSeqno = '최초'; + item.extnsNm = '신설'; + } + }); + + // yyyy-MM-dd로 변환 + sortedHistInfo.forEach(item => { + item.eqpPrmsDt = item.eqpPrmsDt ? item.eqpPrmsDt.substring(0,4) + '-' + item.eqpPrmsDt.substring(4,6) + '-' + item.eqpPrmsDt.substring(6,8) : ''; + item.trlrnCmplDt = item.trlrnCmplDt ? item.trlrnCmplDt.substring(0,4) + '-' + item.trlrnCmplDt.substring(4,6) + '-' + item.trlrnCmplDt.substring(6,8) : ''; + item.cmplDt = item.cmplDt ? item.cmplDt.substring(0,4) + '-' + item.cmplDt.substring(4,6) + '-' + item.cmplDt.substring(6,8) : ''; + item.rnDt = item.rnDt ? item.rnDt.substring(0,4) + '-' + item.rnDt.substring(4,6) + '-' + item.rnDt.substring(6,8) : ''; + }); + + // 마지막 이력 데이터의 값을 gridListPlanInfo에 업데이트 + if (sortedHistInfo.length > 0) { + const lastHistInfo = sortedHistInfo[sortedHistInfo.length - 1]; + set((state: ProcessFacilityType) => ({ + ...state, + ProcessFacilityDetail: { + ...state.ProcessFacilityDetail, + gridListFcltyHistInfo: sortedHistInfo, + gridListPlanInfo: [{ + ...state.ProcessFacilityDetail.gridListPlanInfo[0], + swrTrtPopl: lastHistInfo?.swrTrtPopl ?? state.ProcessFacilityDetail.gridListPlanInfo[0]?.swrTrtPopl, + trtDstrArea: lastHistInfo?.trtDstrArea ?? state.ProcessFacilityDetail.gridListPlanInfo[0]?.trtDstrArea, + sitArea: lastHistInfo?.sitArea ?? state.ProcessFacilityDetail.gridListPlanInfo[0]?.sitArea + }] + } + })); + } else { + set((state: ProcessFacilityType) => ({ + ...state, + ProcessFacilityDetail: { + ...state.ProcessFacilityDetail, + gridListFcltyHistInfo: sortedHistInfo, + gridListPlanInfo: [{ + ...state.ProcessFacilityDetail.gridListPlanInfo[0], + swrTrtPopl: '', + trtDstrArea: '', + sitArea: '' + }] + } + })); + } + }, + + // 모달 수질정보 + /** + * 시설정보 수질정보 데이터 호출 + * @param facilityCd : 시설코드 + */ + searchProcessFacilityWaterQlty: async (facilityCd:string) => { + const promiseSet = await Promise.all([fetchFacilityWaterQltyInfo(facilityCd)]); + const [facilityWaterQltyInfo] = promiseSet; + // extnsSeqno를 기준으로 오름차순 정렬 + const sortedWaterQltyInfo = [...facilityWaterQltyInfo].sort((a, b) => { + // 숫자로 변환하여 비교 + const numA = Number(a.extnsSeqno); + const numB = Number(b.extnsSeqno); + if (!isNaN(numA) && !isNaN(numB)) { + return numA - numB; + } + // 숫자 변환이 실패하면 문자열로 비교 + return String(a.extnsSeqno).localeCompare(String(b.extnsSeqno)); + }); + + sortedWaterQltyInfo.forEach(item => { + if(item.extnsSeqno == '0'){ + item.extnsSeqno = '최초'; + } + }); + + // 법적수질정보 초기화 및 push + gridListLegalWaterQlty = []; + + gridListLegalWaterQlty.push({ + bod: facilityWaterQltyInfo[0]?.bod ?? 0, + cod: Number(facilityWaterQltyInfo[0]?.cod ?? 0), + ss: Number(facilityWaterQltyInfo[0]?.ss ?? 0), + tn: Number(facilityWaterQltyInfo[0]?.tn ?? 0), + tp: Number(facilityWaterQltyInfo[0]?.tp ?? 0), + totClfgrpcnt : Number(facilityWaterQltyInfo[0]?.totClfgrpcnt ?? 0), + }); + + // 마지막 수질 데이터의 값을 gridListPlanInfo에 업데이트 + if (sortedWaterQltyInfo.length > 0) { + const lastWaterQltyInfo = sortedWaterQltyInfo[sortedWaterQltyInfo.length - 1]; + set((state: ProcessFacilityType) => ({ + ...state, + ProcessFacilityDetail: { + ...state.ProcessFacilityDetail, + gridListFcltyWaterQltyInfo: sortedWaterQltyInfo, + gridListLegalWaterQlty: gridListLegalWaterQlty, + gridListPlanInfo: [{ + ...state.ProcessFacilityDetail.gridListPlanInfo[0], + dsInflWqltBod: lastWaterQltyInfo?.dsInflWqltBod === 'NULL' || lastWaterQltyInfo?.dsInflWqltBod === undefined ? '' : lastWaterQltyInfo.dsInflWqltBod, + dsInflWqltToc: lastWaterQltyInfo?.dsInflWqltToc === 'NULL' || lastWaterQltyInfo?.dsInflWqltToc === undefined ? '' : lastWaterQltyInfo.dsInflWqltToc, + dsInflWqltCod: lastWaterQltyInfo?.dsInflWqltCod === 'NULL' || lastWaterQltyInfo?.dsInflWqltCod === undefined ? '' : lastWaterQltyInfo.dsInflWqltCod, + dsInflWqltSs: lastWaterQltyInfo?.dsInflWqltSs === 'NULL' || lastWaterQltyInfo?.dsInflWqltSs === undefined ? '' : lastWaterQltyInfo.dsInflWqltSs, + dsInflWqltTn: lastWaterQltyInfo?.dsInflWqltTn === 'NULL' || lastWaterQltyInfo?.dsInflWqltTn === undefined ? '' : lastWaterQltyInfo.dsInflWqltTn, + dsInflWqltTp: lastWaterQltyInfo?.dsInflWqltTp === 'NULL' || lastWaterQltyInfo?.dsInflWqltTp === undefined ? '' : lastWaterQltyInfo.dsInflWqltTp, + plInflWqltBod: lastWaterQltyInfo?.plInflWqltBod === 'NULL' || lastWaterQltyInfo?.plInflWqltBod === undefined ? '' : lastWaterQltyInfo.plInflWqltBod, + plInflWqltToc: lastWaterQltyInfo?.plInflWqltToc === 'NULL' || lastWaterQltyInfo?.plInflWqltToc === undefined ? '' : lastWaterQltyInfo.plInflWqltToc, + plInflWqltCod: lastWaterQltyInfo?.plInflWqltCod === 'NULL' || lastWaterQltyInfo?.plInflWqltCod === undefined ? '' : lastWaterQltyInfo.plInflWqltCod, + plInflWqltSs: lastWaterQltyInfo?.plInflWqltSs === 'NULL' || lastWaterQltyInfo?.plInflWqltSs === undefined ? '' : lastWaterQltyInfo.plInflWqltSs, + plInflWqltTn: lastWaterQltyInfo?.plInflWqltTn === 'NULL' || lastWaterQltyInfo?.plInflWqltTn === undefined ? '' : lastWaterQltyInfo.plInflWqltTn, + plInflWqltTp: lastWaterQltyInfo?.plInflWqltTp === 'NULL' || lastWaterQltyInfo?.plInflWqltTp === undefined ? '' : lastWaterQltyInfo.plInflWqltTp + }] + } + })); + } else { + set((state: ProcessFacilityType) => ({ + ...state, + ProcessFacilityDetail: { + ...state.ProcessFacilityDetail, + gridListFcltyWaterQltyInfo: sortedWaterQltyInfo, + gridListLegalWaterQlty: gridListLegalWaterQlty, + gridListPlanInfo: [{ + ...state.ProcessFacilityDetail.gridListPlanInfo[0], + dsInflWqltBod: '', + dsInflWqltToc: '', + dsInflWqltCod: '', + dsInflWqltSs: '', + dsInflWqltTn: '', + dsInflWqltTp: '', + plEfflWqltBod: '', + plEfflWqltToc: '', + plEfflWqltCod: '', + plEfflWqltSs: '', + plEfflWqltTn: '', + plEfflWqltTp: '' + }] + } + })); + } + } + } +} \ No newline at end of file diff --git a/apps/fo/app/store/publicReuseFaciltyInsert/index.tsx b/apps/fo/app/store/publicReuseFaciltyInsert/index.tsx new file mode 100644 index 000000000..645cae5dc --- /dev/null +++ b/apps/fo/app/store/publicReuseFaciltyInsert/index.tsx @@ -0,0 +1,97 @@ +export type TableUpperProps = { + id: string; + title: string; + upName?: string; + upSequnce?: number; +} +type PublicReuseFacility = { + sido: string, + sigungo: string, + facilityName: string, + location: string, + locationgubun: string, + facilityCapacity: string, + yn?: string, + authoDay?: string, + area?: string, + reuse?: string, + register?: string +} +const upHeadList:TableUpperProps[] = [ + { id: "sido", title: "시도"}, + { id: "sigungo", title: "시군구"}, + { id: "facilityName", title: "시설명"}, + { id: "location", title: "위치"}, + { id: "locationgubun", title: "지역구분"}, + { id: "facilityCapacity", title: "시설용량"}, + { id: "yn", title: '여부', upName:'upChangeRe' , upSequnce:1 }, + { id: "authoDay", title: '허가일',upName:'upChangeRe', upSequnce:2 }, + { id: "area", title: '면적' ,upName:'upChangeRe',upSequnce:3 }]; + +const publicReuseFacilityUper:PublicReuseFacility[] = [ + { + sido: "서울", + sigungo: "강남구", + facilityName: "난지", + location: "경기도 고양시 덕양구 대차로 4가", + locationgubun: "500", + facilityCapacity: "800,000", + reuse: "Y", + register: "Y" + }, + { + sido: "서울", + sigungo: "강남구", + facilityName: "난지", + location: "경기도 고양시 덕양구 대차로 4가", + locationgubun: "500", + facilityCapacity: "800,000", + reuse: "Y", + register: "Y" + }, + { + sido: "서울", + sigungo: "강남구", + facilityName: "난지", + location: "경기도 고양시 덕양구 대차로 4가", + locationgubun: "500", + facilityCapacity: "800,000", + yn: "Y", + authoDay: "2012", + area:"123" + }, +] + +export type tableState = { + isInit: boolean; + upHeadList: TableUpperProps[]; + publicReuseFacilityUper: PublicReuseFacility[]; +} +type tableActions = { + decrementList: () => void +} + +export type tableType = tableState & tableActions; + +export const tableStateExport:tableState= { + isInit:false, + upHeadList: upHeadList, + publicReuseFacilityUper: publicReuseFacilityUper, +} + +// 상태 설정 함수 타입 정의 +type SetStateFunction = (state: tableState | ((state: tableState) => tableState)) => void; + +export const tableActionsExport:(set:SetStateFunction)=>tableActions=(set: SetStateFunction) => { + + return { + decrementList:()=>set( + (state:tableState) => { + return { + ...state, + publicReuseFacilityUper: + state.publicReuseFacilityUper.slice(0, state.publicReuseFacilityUper.length - 1) + }} + ) + } +} diff --git a/apps/fo/app/store/rdi/index.tsx b/apps/fo/app/store/rdi/index.tsx new file mode 100644 index 000000000..e7acb2231 --- /dev/null +++ b/apps/fo/app/store/rdi/index.tsx @@ -0,0 +1,274 @@ +import DataForm from "@/app/components/common/DataForm"; +import type { TableUpperProps } from "../dashboard"; +import { getFetch } from "@/app/components/api"; +export type { TableUpperProps }; +/**==================================== + * Store - 타입 + ====================================*/ + +/** + * (1) 메인페이지 + */ +// 시설별 강수현황 +export type RdiProps = { + bscFctCd : string, + sido : string, + sigungo : string, + bscFctNm : string, + lclgvrnmntNm : string, + daddr : string, + fctCpc : number, + summerMinBodValue : number, + inflAmnt : number, + winterAvgBodLowRainfall : number, + rdiiValue : number, + infoRnDay : number, + rgnNm : string, + rvbsn : string, + lgbsn : string, + mdmbsn : string, +} + +export interface RdiInterface { + bscFctCd : string, + sido : string, + sigungo : string, + bscFctNm : string, + lclgvrnmntNm : string, + daddr : string, + fctCpc : number, + summerMinBodValue : number, + inflAmnt : number, + winterAvgBodLowRainfall : number, + rdiiValue : number, + infoRnDay : number, + rgnNm : string, + rvbsn : string, + lgbsn : string, + mdmbsn : string, +} + +// 모달 +export interface RdiInputModalProps { + msrDt : string, + realSewageInput : number | '', + sewageOccur : number | '', + underWaterInput : number | '', +} + +/**==================================== + * Store - data + ====================================*/ + +/** + * (1) 메인페이지 + */ +// 검색단 +const LabelArray:string[] = ['구분', '시도', '시군구','용량별', '시설명', '조회기간', '시설상태', '권역', '단위유역', '중권역', '환경청별']; + +export interface ExcelType { + 시설코드: string, + 권역:string|'', + 단위유역:string|'', + 중권역:string|'', + 환경청:string|'', + 시도: string, + 시군구: string, + 시설명: string, + 주소: string, + 시설용량: number, + 하절기강우일최저유입BOD: number | '', + 하절기최저유입BOD유입유량: number | '', + 동절기청천시유입BOD: number | '', + RDII추정 : number | '', + RDII추정시일강수량 : number | '', +} + +// 리스트 헤더 +const upHeadList1:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", row:0, rowSpan:2 }, + { id: "A", title: "행정구역", row:0, colSpan:2 }, + { id: "sido", title: "시도", upName:"upChangeRe", upSequnce:1, row:1 }, + { id: "sigungo", title: "시군구", upName:"upChangeRe",upSequnce:2, row:1 }, + { id: "bscFctNm", title: "시설명", row:0, rowSpan:2 }, + { id: "daddr", title: "주소", row:0, rowSpan:2 }, + { id: "fctCpc", title: "시설용량\n(m³/일)", align:"right", row:0, rowSpan:2 }, + { id: "B", title: "하절기 운영현황(6~8월)", row:0, colSpan:2 }, + { id: "summerMinBodValue", title: "3mm 이상 강우일 중 최저 유입BOD\n(mg/L)", align:"right", row:1 }, + { id: "inflAmnt", title: "하절기최저유입BOD유입유량\n(m³/일)", row:1 }, + { id: "C", title: "동절기 운영현황(1~2월)", row:0 }, + { id: "winterAvgBodLowRainfall", title: "청천시 유입BOD\n(mg/L)", row:1 }, + { id: "rdiiValue", title: "RDII추정", row:0, rowSpan:2 }, + { id: "infoRnDay", title: "RDII추정시일강수량\n(mm)", row:0, rowSpan:2 }, +]; + +const upHeadList2:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", row:0, rowSpan:2 }, + { id: "A", title: "유역", row:0, colSpan:3 }, + { id: "rvbsn", title: "권역", upName:"upChangeRe", upSequnce:1, row:1 }, + { id: "lgbsn", title: "단위유역", upName:"upChangeRe", upSequnce:2, row:1 }, + { id: "mdmbsn", title: "중권역", upName:"upChangeRe", upSequnce:3, row:1 }, + { id: "bscFctNm", title: "시설명", row:0, rowSpan:2 }, + { id: "daddr", title: "주소", row:0, rowSpan:2 }, + { id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2 }, + { id: "B", title: "하절기 운영현황(6~8월)", row:0, colSpan:2 }, + { id: "summerMinBodValue", title: "하절기강우일최저유입BOD", align:"right", row:1 }, + { id: "inflAmnt", title: "하절기최저유입BOD유입유량", row:1 }, + { id: "D", title: "동절기 운영현황(1~2월)", row:0 }, + { id: "winterAvgBodLowRainfall", title: "동절기청천시유입BOD", row:1 }, + { id: "rdiiValue", title: "RDII추정", row:0, rowSpan:2 }, + { id: "infoRnDay", title: "RDII추정시일강수량", row:0, rowSpan:2 }, +]; + +const upHeadList3:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", row:0, rowSpan:2 }, + { id: "A", title: "유역", row:0, colSpan:3 }, + { id: "rvbsn", title: "권역", upName:"upChangeRe1", upSequnce:1, row:1 }, + { id: "lgbsn", title: "단위유역", upName:"upChangeRe1", upSequnce:2, row:1 }, + { id: "mdmbsn", title: "중권역", upName:"upChangeRe1", upSequnce:3, row:1 }, + { id: "rgnNm", title: "환경청", row:0, rowSpan:2 }, + { id: "B", title: "행정구역", row:0, colSpan:2 }, + { id: "sido", title: "시도", upName:"upChangeRe2", upSequnce:1, row:1 }, + { id: "sigungo", title: "시군구", upName:"upChangeRe2",upSequnce:2, row:1 }, + { id: "bscFctNm", title: "시설명", row:0, rowSpan:2 }, + { id: "daddr", title: "주소", row:0, rowSpan:2 }, + { id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2 }, + { id: "C", title: "하절기 운영현황(6~8월)", row:0, colSpan:2 }, + { id: "summerMinBodValue", title: "하절기강우일최저유입BOD", align:"right", row:1 }, + { id: "inflAmnt", title: "하절기최저유입BOD유입유량", row:1 }, + { id: "D", title: "동절기 운영현황(1~2월)", row:0 }, + { id: "winterAvgBodLowRainfall", title: "동절기청천시유입BOD", row:1 }, + { id: "rdiiValue", title: "RDII추정", row:0, rowSpan:2 }, + { id: "infoRnDay", title: "RDII추정시일강수량", row:0, rowSpan:2 }, +]; + +const rdiList:RdiProps[] = [ +] + +/**==================================== + * Store - API + ====================================*/ + +const fetchRdiList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { + try{ + const tailStr = partCd ? '/'+ partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : ''; + const url = '/rdii/list/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr; + console.log(url); + const res = await getFetch('fo', url); + return { data: res.data, count: res.count } + }catch(error){ + console.log(error); + return { data: rdiList, count: 0 }; + } +} + +/**==================================== + * Store - expaort + ====================================*/ +export type RdiActions = { + searchRdiList: (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => void; +} + +export type RdiType = { + RdiSearch: { + isInit: boolean; + labelArray:string[]; + }, + + Rdi : { + isInit: boolean; + upHeadList1: TableUpperProps[]; + upHeadList2: TableUpperProps[]; + upHeadList3: TableUpperProps[]; + rdiList: RdiProps[]; // Changed from facilityAreaProps to ProcessAreaProps + rdiCount: number; + excelList: ExcelType[]; + }, +} + +export const rdiInitState: RdiType = { + RdiSearch: { + isInit: false, + labelArray: LabelArray, + }, + + Rdi : { + isInit : false, + upHeadList1 : upHeadList1, + upHeadList2 : upHeadList2, + upHeadList3 : upHeadList3, + rdiList : rdiList, + rdiCount : 2, + excelList : [] + } +} + +const dataFormSetting=(item : RdiProps)=> { + DataForm({ type: 'float1', column: 'fctCpc', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float1', column: 'summerMinBodValue', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float1', column: 'winterAvgBodLowRainfall', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'rdiiValue', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'infoRnDay', item: item as unknown as Record<string, unknown>}); +} + +// Add type definitions for state setter function +type SetStateFunction = (state: RdiType | ((state: RdiType) => RdiType)) => void; + +export type RdiStore = RdiType & RdiActions; + +export const rdiReducer:(set:SetStateFunction)=>RdiActions=(set: SetStateFunction) => { + console.log("tableActionsExport"); + return { + searchRdiList: async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { + const res = await fetchRdiList(pageNo, pageSize, searchYear, partCd, nameCd, fcltCpct, operationValue, fcltyNm); + const data = res.data; + const excelDownList: ExcelType[] = []; + + const rtnData = data.map((item: RdiProps) => { + return { + ...item, + sido: item.lclgvrnmntNm.split(' ')[0]?.toString() || '', + sigungo: item.lclgvrnmntNm.split(' ')[1]?.toString() || '', + inflAmnt: item.inflAmnt?item.inflAmnt.toFixed(1) : '' + } + }) + + rtnData.forEach((item: RdiProps) => { + dataFormSetting(item) + }) + + if(pageSize>5000){ + rtnData.forEach((item: RdiProps) => { + excelDownList.push({ + 시설코드: item.bscFctCd, + 권역: item.rvbsn, + 단위유역: item.lgbsn, + 중권역: item.mdmbsn, + 환경청: item.rgnNm, + 시설명: item.bscFctNm, + 시도: item.sido, + 시군구: item.sigungo, + 주소: item.daddr, + 시설용량: item.fctCpc, + 하절기강우일최저유입BOD: item.summerMinBodValue, + 하절기최저유입BOD유입유량: item.inflAmnt, + 동절기청천시유입BOD: item.winterAvgBodLowRainfall, + RDII추정 : item.rdiiValue, + RDII추정시일강수량 : item.infoRnDay, + }); + }); + } + set((state: RdiType) => ({ + ...state, + Rdi: pageSize<5000?{ + ...state.Rdi, + rdiList: rtnData, + rdiCount: res.count, + }:{ + ...state.Rdi, + excelList: excelDownList, + } + })) + }, + } +} \ No newline at end of file diff --git a/apps/fo/app/store/sewageOccur/index.tsx b/apps/fo/app/store/sewageOccur/index.tsx new file mode 100644 index 000000000..93de7ca94 --- /dev/null +++ b/apps/fo/app/store/sewageOccur/index.tsx @@ -0,0 +1,464 @@ +import DataForm from "@/app/components/common/DataForm"; +import type { TableUpperProps } from "../dashboard"; +import { getFetch } from "@/app/components/api"; +export type { TableUpperProps }; +/**==================================== + * Store - 타입 + ====================================*/ + +/** + * (1) 메인페이지 + */ +// 시설별 강수현황 +export type SewageOccurProps = { + bscFctCd : string, + sidoNm : string, + sggNm : string, + lclgvrnmntNm : string, + bscFctNm : string, + daddr : string, + fctCpc : number, + waterUsage : number, + swageChangePercent : number, + estimationSewage : number, + sewageInputYear : number, + sewageInputChungchun : number, + rgnNm : string, + rvbsn : string, + lgbsn : string, + mdmbsn : string, + msrDt : string, +} + +export type SewageOccurDetailProps = { + msrDt : string, + waterUsage : number, + swageChangePercent : number, + estimationSewage : number, +} + +/**==================================== + * Store - data + ====================================*/ + +/** + * (1) 메인페이지 + */ +// 검색단 +const LabelArray:string[] = ['구분', '시도', '시군구','용량별', '시설명', '조회기간', '시설상태', '권역', '단위유역', '중권역', '환경청별']; + +export interface ExcelType { + 시설코드: string, + 권역:string|'', + 단위유역:string|'', + 중권역:string|'', + 환경청:string|'', + 시도: string, + 시군구: string, + 시설명: string, + 주소: string, + 시설용량: number, + 물사용량: number | '', + 오수전환율: number | '', + 오수발생량추정: number | '', + 연간하수유입량: number | '', + 청천시하수유입량: number | '', +} + +// 리스트 헤더 +const upHeadList1:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", row:0, rowSpan:2 }, + { id: "A", title: "행정구역", row:0, colSpan:2 }, + { id: "sidoNm", title: "시도", upName:"upChangeRe", upSequnce:1, row:1 }, + { id: "sggNm", title: "시군구", upName:"upChangeRe",upSequnce:2, row:1 }, + { id: "bscFctNm", title: "시설명", row:0, rowSpan:2 }, + { id: "daddr", title: "주소", row:0, rowSpan:2 }, + { id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2 }, + { id: "waterUsage", title: "물사용량(m³/일)", align:"right", row:0, rowSpan:2 }, + { id: "swageChangePercent", title: "오수전환율\n(%)", align:"right", row:0, rowSpan:2 }, + { id: "estimationSewage", title: "오수발생량 추정\n(m³/일)", align:"right", row:0, rowSpan:2 }, + { id: "sewageInputYear", title: "연간 하수유입량\n(m³/일)", align:"right", row:0, rowSpan:2 }, + { id: "sewageInputChungchun", title: "청천시 하수유입량\n(m³/일)", align:"right", row:0, rowSpan:2 }, +]; + +const upHeadList2:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", row:0, rowSpan:2 }, + { id: "A", title: "유역", row:0, colSpan:3 }, + { id: "rvbsn", title: "권역", upName:"upChangeRe", upSequnce:1, row:1 }, + { id: "lgbsn", title: "단위유역", upName:"upChangeRe", upSequnce:2, row:1 }, + { id: "mdmbsn", title: "중권역", upName:"upChangeRe", upSequnce:3, row:1 }, + { id: "bscFctNm", title: "시설명", row:0, rowSpan:2 }, + { id: "daddr", title: "주소", row:0, rowSpan:2 }, + { id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2 }, + { id: "waterUsage", title: "물사용량(m³/일)", align:"right", row:0, rowSpan:2 }, + { id: "swageChangePercent", title: "오수전환율", align:"right", row:0, rowSpan:2 }, + { id: "estimationSewage", title: "오수발생량 추정\n(m³/일)", align:"right", row:0, rowSpan:2 }, + { id: "sewageInputYear", title: "연간 하수유입량\n(m³/일)", align:"right", row:0, rowSpan:2 }, + { id: "sewageInputChungchun", title: "청천시 하수유입량\n(m³/일)", align:"right", row:0, rowSpan:2 }, +]; + +const upHeadList3:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", row:0, rowSpan:2 }, + { id: "A", title: "유역", row:0, colSpan:3 }, + { id: "rvbsn", title: "권역", upName:"upChangeRe1", upSequnce:1, row:1 }, + { id: "lgbsn", title: "단위유역", upName:"upChangeRe1", upSequnce:2, row:1 }, + { id: "mdmbsn", title: "중권역", upName:"upChangeRe1", upSequnce:3, row:1 }, + { id: "rgnNm", title: "환경청", row:0, rowSpan:2 }, + { id: "B", title: "행정구역", row:0, colSpan:2 }, + { id: "sidoNm", title: "시도", upName:"upChangeRe2", upSequnce:1, row:1 }, + { id: "sggNm", title: "시군구", upName:"upChangeRe2",upSequnce:2, row:1 }, + { id: "bscFctNm", title: "시설명", row:0, rowSpan:2 }, + { id: "daddr", title: "주소", row:0, rowSpan:2 }, + { id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2 }, + { id: "waterUsage", title: "물사용량(m³/일)", align:"right", row:0, rowSpan:2 }, + { id: "swageChangePercent", title: "오수전환율", align:"right", row:0, rowSpan:2 }, + { id: "estimationSewage", title: "오수발생량 추정\n(m³/일)", align:"right", row:0, rowSpan:2 }, + { id: "sewageInputYear", title: "연간 하수유입량\n(m³/일)", align:"right", row:0, rowSpan:2 }, + { id: "sewageInputChungchun", title: "청천시 하수유입량\n(m³/일)", align:"right", row:0, rowSpan:2 }, +]; + +const upHeadListSewageOccurDetail:TableUpperProps[] = [ + { id: "msrDt", title: "년월" }, + { id: "waterUsage", title: "물사용량(m³/일)" }, + { id: "swageChangePercent", title: "오수전환율" }, + { id: "estimationSewage", title: "오수발생량 추정(m³/일)", row:0, rowSpan:2 }, +]; + +const sewageOccurList:SewageOccurProps[] = [ +] + +const tempSewageOccurList:SewageOccurDetailProps[] = [ + { + msrDt: '2024-01', + waterUsage: 100, + swageChangePercent: 80, + estimationSewage: 60, + }, + { + msrDt: '2024-02', + waterUsage: 106, + swageChangePercent: 80, + estimationSewage: 80, + }, + { + msrDt: '2024-03', + waterUsage: 100, + swageChangePercent: 80, + estimationSewage: 80, + }, + { + msrDt: '2024-04', + waterUsage: 100, + swageChangePercent: 80, + estimationSewage: 80, + }, + { + msrDt: '2024-05', + waterUsage: 100, + swageChangePercent: 10, + estimationSewage: 80, + }, + { + msrDt: '2024-06', + waterUsage: 100, + swageChangePercent: 80, + estimationSewage: 80, + }, + { + msrDt: '2024-07', + waterUsage: 100, + swageChangePercent: 580, + estimationSewage: 80, + }, + { + msrDt: '2024-08', + waterUsage: 100, + swageChangePercent: 80, + estimationSewage: 80, + }, + { + msrDt: '2024-09', + waterUsage: 100, + swageChangePercent: 80, + estimationSewage: 80, + }, + { + msrDt: '2024-10', + waterUsage: 100, + swageChangePercent: 80, + estimationSewage: 80, + }, + { + msrDt: '2024-11', + waterUsage: 100, + swageChangePercent: 80, + estimationSewage: 80, + }, + { + msrDt: '2024-12', + waterUsage: 100, + swageChangePercent: 80, + estimationSewage: 80, + }, + { + msrDt: '2025-01', + waterUsage: 100, + swageChangePercent: 80, + estimationSewage: 80, + }, + { + msrDt: '2025-02', + waterUsage: 100, + swageChangePercent: 80, + estimationSewage: 80, + }, + { + msrDt: '2025-03', + waterUsage: 100, + swageChangePercent: 80, + estimationSewage: 80, + }, + { + msrDt: '2025-04', + waterUsage: 100, + swageChangePercent: 80, + estimationSewage: 80, + }, + { + msrDt: '2025-05', + waterUsage: 100, + swageChangePercent: 80, + estimationSewage: 80, + }, + { + msrDt: '2025-06', + waterUsage: 100, + swageChangePercent: 80, + estimationSewage: 80, + }, + { + msrDt: '2025-07', + waterUsage: 100, + swageChangePercent: 80, + estimationSewage: 80, + }, + { + msrDt: '2025-08', + waterUsage: 100, + swageChangePercent: 0.8, + estimationSewage: 80, + }, + { + msrDt: '2025-09', + waterUsage: 100, + swageChangePercent: 80, + estimationSewage: 80, + }, + { + msrDt: '2025-10', + waterUsage: 100, + swageChangePercent: 80, + estimationSewage: 80, + }, + { + msrDt: '2025-11', + waterUsage: 100, + swageChangePercent: 80, + estimationSewage: 80, + }, + { + msrDt: '2025-12', + waterUsage: 100, + swageChangePercent: 80, + estimationSewage: 80, + }, +] + +/**==================================== + * Store - API + ====================================*/ + +const fetchSewageOccurList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { + // 20250701임시시 + console.log("partCd", partCd); + console.log("nameCd", nameCd); + console.log("fcltCpct", fcltCpct); + console.log("operationValue", operationValue); + console.log("fcltyNm", fcltyNm); + console.log("searchYear", searchYear); + const tailStr = partCd ? '/'+ partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : ''; + const url = '/fclt/flow/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr; + const res = await getFetch('fo', url); + console.log("res", res.data); + return { data: res.data, count: res.count } + + /* + const tailStr = partCd ? '/'+ partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : ''; + const url = '/fclt/qlty/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr; + const res = await getFetch('fo', url); + return { data: res.data, count: res.count } */ +} + +/**==================================== + * Store - expaort + ====================================*/ +export type SewageOccurActions = { + searchSewageOccurList: (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => void; +} + +export type SewageOccurType = { + SewageOccurSearch: { + isInit: boolean; + labelArray:string[]; + }, + + SewageOccur : { + isInit: boolean; + upHeadList1: TableUpperProps[]; + upHeadList2: TableUpperProps[]; + upHeadList3: TableUpperProps[]; + sewageOccurList: SewageOccurProps[]; // Changed from facilityAreaProps to ProcessAreaProps + sewageOccurCount: number; + excelList: ExcelType[]; + }, + + SewageOccurDetail : { + isInit: boolean; + upHeadListSewageOccurDetail: TableUpperProps[]; + gridListSewageOccurDetail: SewageOccurDetailProps[]; + } +} + +export const sewageOccurInitState: SewageOccurType = { + SewageOccurSearch: { + isInit: false, + labelArray: LabelArray, + }, + + SewageOccur : { + isInit : false, + upHeadList1 : upHeadList1, + upHeadList2 : upHeadList2, + upHeadList3 : upHeadList3, + sewageOccurList : sewageOccurList, + sewageOccurCount : 2, + excelList : [] + }, + + SewageOccurDetail : { + isInit: false, + upHeadListSewageOccurDetail: upHeadListSewageOccurDetail, + gridListSewageOccurDetail: tempSewageOccurList, + } +} + +const dataFormSetting=(item : SewageOccurProps)=> { + DataForm({ type: 'float1', column: 'fctCpc', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float1', column: 'waterUsage', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'estimationSewage', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'sewageInputYear', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'sewageInputChungchun', item: item as unknown as Record<string, unknown>}); +} + +export type SewageOccurStore = SewageOccurType & SewageOccurActions; + +// Add type definitions for API responses +type FlowDataItem = { + inflAmnt: string | number; + infoRnDay: string | number; + bscFctCd: string; + msrDt: string; +} + +type FlowResponse = { + data: FlowDataItem[]; + count: number; +} + +type SetStateFunction = (state: SewageOccurType | ((state: SewageOccurType) => SewageOccurType)) => void; + +export const sewageOccurReducer:(set:SetStateFunction)=>SewageOccurActions=(set: SetStateFunction) => { + return { + searchSewageOccurList: async (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { + const res = await fetchSewageOccurList(pageNo, pageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm); + const data = res.data; + + // Promise.all을 사용하여 모든 비동기 작업이 완료될 때까지 기다림 + const calData = await Promise.all(data.map(async (item: SewageOccurProps) => { + item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; + item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; + item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); + item.waterUsage = item.fctCpc * 0.6; + item.swageChangePercent = 80; + item.estimationSewage = item.waterUsage * (item.swageChangePercent/100); + + const bscFctCd = item.bscFctCd; + const url2 = '/fclt/flow/' + bscFctCd + '/' + searchYear; + const res2 = await getFetch('fo', url2) as FlowResponse; + const sumFlow = res2.data.reduce((acc: number, curr: FlowDataItem) => Number(acc) + Number(curr.inflAmnt), 0); + + let sumChungcunDay = 0; + let chungcunSumFlow = 0; + + res2.data.forEach((item: FlowDataItem) => { + if(Number(item.infoRnDay) ===0){ + chungcunSumFlow += Number(item.inflAmnt); + sumChungcunDay += 1; + }else{ + console.log(item.bscFctCd +' day : ' +' '+item.msrDt); + } + }); + + item.sewageInputYear = sumFlow/res2.count; + item.sewageInputChungchun = chungcunSumFlow===0?0:(chungcunSumFlow / sumChungcunDay); + return item; + })); + + console.log('calData : ', calData); + + const excelDownList: ExcelType[] = []; + if(pageSize>5000){ + calData.forEach(item => { + dataFormSetting(item) + item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); + /* item.ctpvNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; + item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; */ + excelDownList.push({ + 시설코드: item.bscFctCd, + 권역: item.rvbsn, + 단위유역: item.lgbsn, + 중권역: item.mdmbsn, + 환경청: item.rgnNm, + 시도: item.sidoNm, + 시군구: item.sggNm, + 시설명: item.bscFctNm, + 주소: item.daddr, + 시설용량: item.fctCpc, + 물사용량: item.waterUsage, + 오수전환율: item.swageChangePercent, + 오수발생량추정: item.estimationSewage, + 연간하수유입량: item.sewageInputYear, + 청천시하수유입량: item.sewageInputChungchun, + }); + }); + }else{ + calData.forEach((item: SewageOccurProps) => { + dataFormSetting(item) + /* item.sidoNmNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; + item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; */ + }); + } + set((state: SewageOccurType) => ({ + ...state, + SewageOccur: pageSize<5000?{ + ...state.SewageOccur, + sewageOccurList: calData, + sewageOccurCount: res.count, + }:{ + ...state.SewageOccur, + excelList: excelDownList, + } + })) + }, + } +} \ No newline at end of file diff --git a/apps/fo/app/store/store.tsx b/apps/fo/app/store/store.tsx new file mode 100644 index 000000000..f17801d1f --- /dev/null +++ b/apps/fo/app/store/store.tsx @@ -0,0 +1,78 @@ +import { createStore } from 'zustand/vanilla'; +import { CommonReducer, commonState, type CommonStore, type CommonType } from './common'; +import { dashBoardReducer, dashBoardInitState, type DashBoardStore, type DashBoardType } from './dashboard'; +import { + facilityPrecipitationInitState, + facilityPrecipitationReducer, + type FacilityPrecipitationStore, type FacilityPrecipitationType +} from './facilityPrecipitation'; +import { planSewageInitState, planSewageReducer, type PlanSewageStore, type PlanSewageType } from './planSewage'; +import { flowRateSearchInitState, flowRateSearchReducer, type FlowRateSearchStore, type FlowRateSearchType } from './flowRate'; +import { + processAreaInitState, + processAreaReducer, + type ProcessAreaStore, type ProcessAreaType +} from './processArea'; +import { + processFacilityInitState, + processFacilityReducer, + type ProcessFacilityStore, type ProcessFacilityType +} from './processFacility'; +import { + facilityWaterQltyInitState, + facilityWaterQltyReducer, + type FacilityWaterQltyStore, type FacilityWaterQltyType +} from './facilityWaterQlty'; +import { + sewageOccurInitState, + sewageOccurReducer, + type SewageOccurStore, type SewageOccurType +} from './sewageOccur'; +import { + underWaterInitState, + underWaterReducer, + type UnderWaterStore, type UnderWaterType +} from './underWaterInput'; +import { + rdiInitState, + rdiReducer, + type RdiStore, type RdiType +} from './rdi'; +import { tableActionsExport, tableStateExport, type tableState, type tableType } from './publicReuseFaciltyInsert/index'; +export type FoStore = CommonStore & tableType & DashBoardStore & ProcessFacilityStore & ProcessAreaStore & FlowRateSearchStore & FacilityPrecipitationStore & FacilityWaterQltyStore & PlanSewageStore & SewageOccurStore & UnderWaterStore & RdiStore; +export type FoState = CommonType & tableState & ProcessFacilityType & ProcessAreaType & FacilityPrecipitationType & FlowRateSearchType & DashBoardType & FacilityWaterQltyType & PlanSewageType & SewageOccurType & UnderWaterType & RdiType; + +export const StoreZus = + (initState: FoState = { ...commonState, + ...tableStateExport + , ...processFacilityInitState + , ...processAreaInitState + , ...facilityPrecipitationInitState + , ...dashBoardInitState + , ...flowRateSearchInitState + , ...facilityWaterQltyInitState + , ...planSewageInitState + , ...sewageOccurInitState + , ...underWaterInitState + , ...rdiInitState + } + ) => { + return createStore<FoStore>()((set) => { + return { + ...initState, + ...CommonReducer(set), + ...tableActionsExport(set), + ...dashBoardReducer(set), + ...processFacilityReducer(set), + ...processAreaReducer(set), + ...facilityPrecipitationReducer(set), + ...flowRateSearchReducer(set), + ...facilityWaterQltyReducer(set), + ...planSewageReducer(set), + ...sewageOccurReducer(set), + ...underWaterReducer(set), + ...rdiReducer(set), + } + }) +} +//store 등록하는 부분 \ No newline at end of file diff --git a/apps/fo/app/store/underWaterInput/index.tsx b/apps/fo/app/store/underWaterInput/index.tsx new file mode 100644 index 000000000..ea6f4575b --- /dev/null +++ b/apps/fo/app/store/underWaterInput/index.tsx @@ -0,0 +1,397 @@ +import DataForm from "@/app/components/common/DataForm"; +import type { TableUpperProps } from "../dashboard"; +import { getFetch } from "@/app/components/api"; +export type { TableUpperProps }; +/**==================================== + * Store - 타입 + ====================================*/ + +/** + * (1) 메인페이지 + */ +// 시설별 강수현황 +export type UnderWaterProps = { + bscFctCd : string, + lclgvrnmntNm : string, + sidoNm : string, + sggNm : string, + bscFctNm : string, + daddr : string, + fctCpc : number, + underWaterInputYear : number, + underWaterInputSummer : number, + underWaterInputWinter : number, + infoRnDay : number, + rgnNm : string, + rvbsn : string, + lgbsn : string, + mdmbsn : string, +} +export interface UnderWaterInterface { + bscFctCd : string, + sidoNm : string, + sggNm : string, + bscFctNm : string, + daddr : string, + fctCpc : number, + underWaterInputYear : number, + underWaterInputSummer : number, + underWaterInputWinter : number, + infoRnDay : number, + rgnNm : string, + rvbsn : string, + lgbsn : string, + mdmbsn : string, +} + +// 모달 +export interface UnderWaterInputModalProps { + msrDt : string, + realSewageInput : number | '', + sewageOccur : number | '', + underWaterInput : number | '', +} + +/**==================================== + * Store - data + ====================================*/ + +/** + * (1) 메인페이지 + */ +// 검색단 +const LabelArray:string[] = ['구분', '시도', '시군구','용량별', '시설명', '조회기간', '시설상태', '권역', '단위유역', '중권역', '환경청별']; + +export interface ExcelType { + 시설코드: string, + 권역:string|'', + 단위유역:string|'', + 중권역:string|'', + 환경청:string|'', + 시도: string, + 시군구: string, + 시설명: string, + 주소: string, + 시설용량: number, + 연간지하수유입량: number | '', + 하절기지하수유입량: number | '', + 동절기지하수유입량: number | '', +} + +// 리스트 헤더 +const upHeadList1:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", row:0, rowSpan:2 }, + { id: "A", title: "행정구역", row:0, colSpan:2 }, + { id: "sidoNm", title: "시도", upName:"upChangeRe", upSequnce:1, row:1 }, + { id: "sggNm", title: "시군구", upName:"upChangeRe",upSequnce:2, row:1 }, + { id: "bscFctNm", title: "시설명", row:0, rowSpan:2 }, + { id: "daddr", title: "주소", row:0, rowSpan:2 }, + { id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2 }, + { id: "C", title: "지하수 유입량 추정", align:"right", row:0, colSpan:3 }, + { id: "underWaterInputYear", title: "연간\n(m³/일)", align:"right", row:1 }, + { id: "underWaterInputSummer", title: "하절기\n(m³/일)", align:"right", row:1 }, + { id: "underWaterInputWinter", title: "동절기\n(m³/일)", align:"right", row:1 }, +]; + +const upHeadList2:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", row:0, rowSpan:2 }, + { id: "A", title: "유역", row:0, colSpan:3 }, + { id: "rvbsn", title: "권역", upName:"upChangeRe", upSequnce:1, row:1 }, + { id: "lgbsn", title: "단위유역", upName:"upChangeRe", upSequnce:2, row:1 }, + { id: "mdmbsn", title: "중권역", upName:"upChangeRe", upSequnce:3, row:1 }, + { id: "bscFctNm", title: "시설명", row:0, rowSpan:2 }, + { id: "daddr", title: "주소", row:0, rowSpan:2 }, + { id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2 }, + { id: "C", title: "지하수 유입량 추정", align:"right", row:0, colSpan:3 }, + { id: "underWaterInputYear", title: "연간\n(m³/일)", align:"right", row:1 }, + { id: "underWaterInputSummer", title: "하절기\n(m³/일)", align:"right", row:1 }, + { id: "underWaterInputWinter", title: "동절기\n(m³/일)", align:"right", row:1 }, +]; + +const upHeadList3:TableUpperProps[] = [ + { id: "bscFctCd", title: "시설코드", row:0, rowSpan:2 }, + { id: "A", title: "유역", row:0, colSpan:3 }, + { id: "rvbsn", title: "권역", upName:"upChangeRe1", upSequnce:1, row:1 }, + { id: "lgbsn", title: "단위유역", upName:"upChangeRe1", upSequnce:2, row:1 }, + { id: "mdmbsn", title: "중권역", upName:"upChangeRe1", upSequnce:3, row:1 }, + { id: "rgnNm", title: "환경청", row:0, rowSpan:2 }, + { id: "B", title: "행정구역", row:0, colSpan:2 }, + { id: "sidoNm", title: "시도", upName:"upChangeRe2", upSequnce:1, row:1 }, + { id: "sggNm", title: "시군구", upName:"upChangeRe2",upSequnce:2, row:1 }, + { id: "bscFctNm", title: "시설명", row:0, rowSpan:2 }, + { id: "daddr", title: "주소", row:0, rowSpan:2 }, + { id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2 }, + { id: "C", title: "지하수 유입량 추정", align:"right", row:0, colSpan:3 }, + { id: "underWaterInputYear", title: "연간\n(m³/일)", align:"right", row:1 }, + { id: "underWaterInputSummer", title: "하절기\n(m³/일)", align:"right", row:1 }, + { id: "underWaterInputWinter", title: "동절기\n(m³/일)", align:"right", row:1 }, +]; + +// 모달 +const upHeadListUnderWaterDetail:TableUpperProps[] = [ + { id: "msrDt", title: "날짜" }, + { id: "realSewageInput", title: "실제 하수유입량\n(m³/일)" }, + { id: "sewageOccur", title: "오수발생량\n(m³/일)" }, + { id: "underWaterInput", title: "지하수 유입량\n(m³/일)" }, +]; + +const underWaterList:UnderWaterProps[] = [ +] + +const underWaterDetailList:UnderWaterInputModalProps[] = [ + { + msrDt : "2024-01", + realSewageInput : 178007, + sewageOccur : 10.5, + underWaterInput : 80.6, + }, + { + msrDt : "2024-02", + realSewageInput : 123007, + sewageOccur : 10.7, + underWaterInput : 80.6, + }, + { + msrDt : "2024-03", + realSewageInput : 213007, + sewageOccur : 10.1, + underWaterInput : 80.6, + }, + { + msrDt : "2024-04", + realSewageInput : 83007, + sewageOccur : 9.57, + underWaterInput : 80.6, + }, + { + msrDt : "2024-05", + realSewageInput : 15007, + sewageOccur : 3.57, + underWaterInput : 80.6, + }, + { + msrDt : "2024-06", + realSewageInput : 123007, + sewageOccur : '', + underWaterInput : 80.6, + }, + { + msrDt : "2024-07", + realSewageInput : 101007, + sewageOccur : 1, + underWaterInput : 80.6, + }, + { + msrDt : "2024-08", + realSewageInput : 103807, + sewageOccur : 10.57, + underWaterInput : '', + }, + { + msrDt : "2024-09", + realSewageInput : 9007, + sewageOccur : 10.57, + underWaterInput : 80.6, + }, + { + msrDt : "2024-10", + realSewageInput : 163007, + sewageOccur : 10.57, + underWaterInput : 80.6, + }, + { + msrDt : "2024-11", + realSewageInput : 123007, + sewageOccur : 10.57, + underWaterInput : 80.6, + }, + { + msrDt : "2024-12", + realSewageInput : 1007, + sewageOccur : 10.57, + underWaterInput : 80.6, + }, +] +/**==================================== + * Store - API + ====================================*/ + +// API response types +interface FlowDataItem { + inflAmnt: number; + infoRnDay: number; + msrDt: string; +} + +interface ApiResponse { + data: FlowDataItem[]; + count: number; +} + +const fetchUnderWaterList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { + const tailStr = partCd ? '/'+ partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : ''; + const url = '/fclt/flow/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr; + const res = await getFetch('fo', url); + return { data: res.data, count: res.count } + /* + const tailStr = partCd ? '/'+ partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : ''; + const url = '/fclt/qlty/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr; + const res = await getFetch('fo', url); + return { data: res.data, count: res.count } */ + + //return { data: underWaterList, count: 2 }; +} + +/**==================================== + * Store - expaort + ====================================*/ +export type UnderWaterActions = { + searchUnderWaterList: (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => void; +} + +export type UnderWaterType = { + UnderWaterSearch: { + isInit: boolean; + labelArray:string[]; + }, + + UnderWater : { + isInit: boolean; + upHeadList1: TableUpperProps[]; + upHeadList2: TableUpperProps[]; + upHeadList3: TableUpperProps[]; + underWaterList: UnderWaterProps[]; // Changed from facilityAreaProps to ProcessAreaProps + underWaterCount: number; + excelList: ExcelType[]; + }, + + UnderWaterDetail : { + isInit: boolean; + upHeadListUnderWaterDetail: TableUpperProps[]; + gridListUnderWaterDetail: UnderWaterInputModalProps[]; + } +} + +export const underWaterInitState: UnderWaterType = { + UnderWaterSearch: { + isInit: false, + labelArray: LabelArray, + }, + + UnderWater : { + isInit : false, + upHeadList1 : upHeadList1, + upHeadList2 : upHeadList2, + upHeadList3 : upHeadList3, + underWaterList : underWaterList, + underWaterCount : 4, + excelList : [] + }, + + UnderWaterDetail : { + isInit: false, + upHeadListUnderWaterDetail: upHeadListUnderWaterDetail, + gridListUnderWaterDetail: underWaterDetailList, + } +} + +const dataFormSetting=(item : UnderWaterProps)=> { + DataForm({ type: 'float1', column: 'fctCpc', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float1', column: 'underWaterInputYear', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'underWaterInputSummer', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float2', column: 'underWaterInputWinter', item: item as unknown as Record<string, unknown>}); +} + +export type UnderWaterStore = UnderWaterType & UnderWaterActions; + +export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterType) => void)=>UnderWaterActions=(set: (fn: (state: UnderWaterType) => UnderWaterType) => void) => { + return { + searchUnderWaterList: async (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { + const res = await fetchUnderWaterList(pageNo, pageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm); + const data = res.data; + const calData = await Promise.all(data.map(async (item: UnderWaterProps) => { + item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; + item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; + item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); + + const bscFctCd = item.bscFctCd; + const url2 = '/fclt/flow/' + bscFctCd + '/' + searchYear; + const res2 = await getFetch('fo', url2) as ApiResponse; + + let sumChungcunDay = 0; + let chungcunSumFlow = 0; + + let sumSummerChungcunDay = 0; + let sumSummerChungcunFlow = 0; + + let sumWinterChungcunDay = 0; + let sumWinterChungcunFlow = 0; + + res2.data.forEach((flowItem: FlowDataItem) => { + // 청천시 + if(Number(flowItem.infoRnDay) ===0){ + sumChungcunDay += 1; + chungcunSumFlow += Number(flowItem.inflAmnt); + + if(flowItem.msrDt.substring(4,6) ==='06' || flowItem.msrDt.substring(4,6) ==='07' || flowItem.msrDt.substring(4,6) ==='08'){ + sumSummerChungcunDay += 1; + sumSummerChungcunFlow += Number(flowItem.inflAmnt); + }else if(flowItem.msrDt.includes('01') || flowItem.msrDt.includes('02')){ + sumWinterChungcunDay += 1; + sumWinterChungcunFlow += Number(flowItem.inflAmnt); + } + } + }); + item.underWaterInputYear = Number(chungcunSumFlow==0?0:Math.round((chungcunSumFlow / sumChungcunDay) * 10) / 10) - Number(item.fctCpc * 0.6 * 0.8); + item.underWaterInputSummer = Number(sumSummerChungcunFlow==0?0:Math.round((sumSummerChungcunFlow / sumSummerChungcunDay) * 10) / 10) - Number(item.fctCpc * 0.6 * 0.8); + item.underWaterInputWinter = Number(sumWinterChungcunFlow==0?0:Math.round((sumWinterChungcunFlow / sumWinterChungcunDay) * 10) / 10) - Number(item.fctCpc * 0.6 * 0.8); + + return item; + })); + + const excelDownList: ExcelType[] = []; + if(pageSize>5000){ + calData.forEach(item => { + dataFormSetting(item) + item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); + /* item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; + item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; */ + excelDownList.push({ + 시설코드: item.bscFctCd, + 권역: item.rvbsn, + 단위유역: item.lgbsn, + 중권역: item.mdmbsn, + 환경청: item.rgnNm, + 시도: item.sidoNm, + 시군구: item.sggNm, + 시설명: item.bscFctNm, + 주소: item.daddr, + 시설용량: item.fctCpc, + 연간지하수유입량: item.underWaterInputYear, + 하절기지하수유입량: item.underWaterInputSummer, + 동절기지하수유입량: item.underWaterInputWinter, + + }); + }); + }else{ + data.forEach((item: UnderWaterProps) => { + dataFormSetting(item) + item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); + /* item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; + item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; */ + }); + } + set((state: UnderWaterType) => ({ + ...state, + UnderWater: pageSize<5000?{ + ...state.UnderWater, + underWaterList: calData, + underWaterCount: res.count, + }:{ + ...state.UnderWater, + excelList: excelDownList, + } + })) + }, + } +} \ No newline at end of file diff --git a/apps/fo/components.json b/apps/fo/components.json new file mode 100644 index 000000000..dea737b85 --- /dev/null +++ b/apps/fo/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} \ No newline at end of file diff --git a/apps/fo/eslint.config.mjs b/apps/fo/eslint.config.mjs new file mode 100644 index 000000000..c85fb67c4 --- /dev/null +++ b/apps/fo/eslint.config.mjs @@ -0,0 +1,16 @@ +import { dirname } from "path"; +import { fileURLToPath } from "url"; +import { FlatCompat } from "@eslint/eslintrc"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const compat = new FlatCompat({ + baseDirectory: __dirname, +}); + +const eslintConfig = [ + ...compat.extends("next/core-web-vitals", "next/typescript"), +]; + +export default eslintConfig; diff --git a/apps/fo/middleware.ts b/apps/fo/middleware.ts new file mode 100644 index 000000000..c3e2a5bec --- /dev/null +++ b/apps/fo/middleware.ts @@ -0,0 +1,115 @@ +import { NextRequest, NextResponse } from "next/server"; + +const AUTH_USER_ID = process.env.NEXT_PUBLIC_AUTH_USER_ID || "token-id"; +const CLAIM_NAME = process.env.NEXT_PUBLIC_CLAIM_NAME || "Authorization"; +const SERVER_API_URL = process.env.NEXT_PUBLIC_SERVER_API_URL || ""; +const GEOSERVER_URL = process.env.NEXT_PUBLIC_GEOSERVER_URL || ""; +const LX_GEOSERVER_URL = process.env.NEXT_PUBLIC_LX_GEOSERVER_URL || ""; +const SEWERAGE_API_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || ""; + +export function middleware(req: NextRequest) { + console.log("Middleware 진입:", req.nextUrl.pathname); + const pathname = req.nextUrl.pathname; + const searchParams = req.nextUrl.searchParams; + + if (pathname.startsWith("/server")) { + const queryParams = searchParams.toString(); + const newUrl = `${SERVER_API_URL}${pathname.replace("/server", "")}${ + queryParams ? `?${queryParams}` : "" + }`; + console.log(`[Middleware] Rewriting from '/server' path to: ${newUrl}`); + return NextResponse.rewrite(new URL(newUrl)); + } + + if (pathname.startsWith("/geoserver")) { + let queryParams = searchParams.toString(); + const typename = searchParams.get("TYPENAME"); + + let newUrl = `${GEOSERVER_URL}${pathname.replace("/geoserver", "")}${queryParams ? `?${queryParams}` : ""}`; + + if ( + typename == "hasudo:tb_il_swage_prcs_fclt" //하수처리시설 + || typename == "hasudo:tb_ms_swage_prcs_zone" //하수처리구역 + || typename == "hasudo:tb_ms_sbmrg_dngr_map" //침수위험지도 + || typename == "hasudo:tb_ms_flood_dngr_map" //도시침수지도 + ) { + newUrl = `${GEOSERVER_URL}${pathname.replace("/geoserver", "")}${queryParams ? `?${queryParams}` : ""}`; + } + else if ( + typename == "hasudo:tb_ms_swage_ppl" //관로 + || typename == "hasudo:tb_ms_swage_mhl" //맨홀 + || typename == "hasudo:tb_ms_swage_pmstn" //펌프장 + || typename == "hasudo:tb_ms_stofcbr" //우수토실 + ) { + newUrl = `${LX_GEOSERVER_URL}${pathname.replace("/geoserver", "")}${queryParams ? `?${queryParams}` : ""}`; + } + else if ( + typename == "hasudo:om_dt_untrt_swg_rain" //중점우수토실 + || typename == "hasudo:om_wqlt_station" //관측소 + || typename == "hasudo:tb_wr_bdst_ruse_fclt" //재이용시설 + || typename == "hasudo:tb_wr_rnwtr_utztn_fclt" //빗물이용시설 + || typename == "hasudo:tb_wr_rswtr_fclt" //중수도시설 + || typename == "hasudo:tb_wr_htdfl_fclt" //온배수시설 + || typename == "hasudo:tb_wr_ruse_fclt_dmd_co" //수요처 + || typename == "hasudo:tb_wr_tmpr_dmd_co" //잠재수요처 + ){ + const url = req.nextUrl.clone(); + url.searchParams.set('TYPENAME', typename.replace("hasudo:","")); + queryParams = url.searchParams.toString(); + newUrl = `${SEWERAGE_API_URL}/v1/map/geometry${queryParams ? `?${queryParams}` : ""}`; + } + + console.log(`[Middleware] Rewriting from '/geoserver' path to: ${newUrl}`); + return NextResponse.rewrite(new URL(newUrl)); + } + + if (pathname.startsWith("/sewerage-service/api/v1/map/geometry")) { + const queryParams = searchParams.toString(); + const newUrl = `${SEWERAGE_API_URL}${pathname.replace("/sewerage-service/api", "")}${ + queryParams ? `?${queryParams}` : "" + }`; + console.log(`[Middleware] Rewriting from '/geoserver' path to: ${newUrl}`); + return NextResponse.rewrite(new URL(newUrl)); + } + + if (pathname.startsWith("/attach-service") || pathname.startsWith("/cms-service")) { + const requestHeaders = new Headers(req.headers); + const token = req.cookies.get(CLAIM_NAME)?.value; + const userId = req.cookies.get(AUTH_USER_ID)?.value; + const newUrl = `${SERVER_API_URL}${pathname}`; + + if (token) requestHeaders.set(CLAIM_NAME, token); + if (userId) requestHeaders.set(AUTH_USER_ID, userId); + + console.log( + `[Middleware] Rewriting from '/attach-service' path to: ${newUrl}`, + ); + return NextResponse.rewrite(new URL(newUrl), { + headers: requestHeaders, + }); + } + + if (pathname.startsWith("/user-service")) { + const requestHeaders = new Headers(req.headers); + const newUrl = `${SERVER_API_URL}${pathname}`; + + console.log( + `[Middleware] Rewriting from '/user-service' path to: ${newUrl}`, + ); + return NextResponse.rewrite(new URL(newUrl), { + headers: requestHeaders, + }); + } + + return NextResponse.next(); +} + +export const config = { + matcher: [ + "/server/:path*", + "/geoserver/:path*", + "/attach-service/:path*", + "/user-service/:path*", + "/cms-service/:path*", + ], +}; diff --git a/apps/fo/next.config.ts b/apps/fo/next.config.ts new file mode 100644 index 000000000..d157358c9 --- /dev/null +++ b/apps/fo/next.config.ts @@ -0,0 +1,33 @@ +import type { NextConfig } from "next"; + +const subDomain = + process.env.NEXT_PUBLIC_SUB_DOMAIN || "http://localhost:13001"; + +const nextConfig: NextConfig = { + async rewrites() { + return { + beforeFiles: [ + { + source: "/_next/static/:path*", + destination: `${subDomain}/_next/static/:path*`, + has: [ + { + type: "header", + key: "referer", + value: "(.*)/pst(.*)", + }, + ], + }, + ], + afterFiles: [ + { + source: "/pst/:path*", + destination: `${subDomain}/pst/:path*`, + }, + ], + fallback: [], + }; + }, +}; + +export default nextConfig; diff --git a/apps/fo/package.json b/apps/fo/package.json new file mode 100644 index 000000000..447e7d7a7 --- /dev/null +++ b/apps/fo/package.json @@ -0,0 +1,29 @@ +{ + "name": "fo", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "@common/business_components": "workspace:*", + "@common/components": "workspace:*", + "@tailwindcss/vite": "^4.0.10", + "html2canvas": "^1.4.1", + "next": "15.1.7", + "select": "^1.1.2", + "webpack": "^5.98.0", + "zustand": "^5.0.3" + }, + "devDependencies": { + "@eslint/eslintrc": "^3", + "eslint": "^9", + "eslint-config-next": "15.1.7", + "postcss": "^8", + "tailwindcss": "^3.4.17", + "typescript": "^5.6.3" + } +} diff --git a/apps/fo/postcss.config.mjs b/apps/fo/postcss.config.mjs new file mode 100644 index 000000000..1a69fd2a4 --- /dev/null +++ b/apps/fo/postcss.config.mjs @@ -0,0 +1,8 @@ +/** @type {import('postcss-load-config').Config} */ +const config = { + plugins: { + tailwindcss: {}, + }, +}; + +export default config; diff --git a/apps/fo/public/file.svg b/apps/fo/public/file.svg new file mode 100644 index 000000000..004145cdd --- /dev/null +++ b/apps/fo/public/file.svg @@ -0,0 +1 @@ +<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg> \ No newline at end of file diff --git a/apps/fo/public/globe.svg b/apps/fo/public/globe.svg new file mode 100644 index 000000000..567f17b0d --- /dev/null +++ b/apps/fo/public/globe.svg @@ -0,0 +1 @@ +<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg> \ No newline at end of file diff --git a/apps/fo/public/images/map/layericon/BML_CBAS_PS.png b/apps/fo/public/images/map/layericon/BML_CBAS_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..5ff4add3ef67899ca56ef065952b919b8426d086 GIT binary patch literal 1547 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nBkco*&`K2Yc zN<f!FypUS}H#V;r8ce_d)2~P@&^OdG0C@?f(AO8g(%f9Q>f(~1RD^r68eAMwS&*t9 zlv<o$T9gcoxHM&uRRvbgMX8A;`9&f5`8lvq49LhY$uG{xFHmp}HdD|D&&*57FE7>v ztM~P_^2{qPNz6-5^>ndS0-B(gnVDi`<Z5p0Xk_kaV&V)8bypKdGh;(%XE$dj6H6Bh zS7&3GUYGpj(%jU%5}4i;gkC3{dO=Acw*Y9fOKMSOS!#+~QGTuh*vnR#xZPrb(>$o& z6x?pH#Hm*w=oo!a#3DsBObD2IKumbD1#;jCKQ#}S+KYh6+H&5{UIqrHdQTU}kcwM# zCdYbA4wN|lzxuh^-KyftM`9}$b|eHj#ydx=Nojj7R_fibWOhtktBRwzr;AGL6JLcX zP9asojgm^Nvyv>YoZNEAS66w8U5Los;>%~ht$SX1yNy%n%YpY#=RBYD{eR7zVv*&a zHg7yw)KPTEN8<3l%tLM_g0*X7YcHPdDrJgV)VE?sNS)uzi4)u2J~Hz-$nY#Z{b5O+ zn|F2jglp2BSwbJzieC`a_ZJb3;`&^C;m;P%xwd6GyY5cNP>d5PEO@UsWuC6v_uqA2 ztlg|m)V8_oF?{%<)YbL4?(SgT9XV^8jz4d=GUMYsCQ?~=c0bqc2kI7fy9%~0;^Ao3 z`RnX=Zd=fT{>}|zGDZ)d-L3kexg^7*Ma_@fQ6Qz_jGbq|BgbUpPoIh+uUG9-IKJeJ zkN3)jv-tO9Wgb5Agg?Wzc8g<qUWk*ktB=p$NzV<nOl#ugr-?nAn0{}$#OxW9ESQU{ zvW%{psx03-^`qSJ4;-6}E>~tflT*nqwc24D_r^eK(M07myPQdht9O1E(DK!JCiZNB zzeiH|raMOx65h_&*cMm)<@t$<#hNS+^COS+R2N!$F45U>`_2aQz0QG*+fLXNDYaDy zde2LpcWy(^SyL;u`NavPsi);W%v-$krbKb?sgs)yJid0_cHw8$;{vP29>hoX<vp8q z-TnF23PV0|y=f0zqr*G?r!wkodiZv?V@RxKv%=bg&c~m`e{`IrA}P1oe|eYV+qJJV z@}GBiu<hzBQ`CvGHL$s7`0uUyyZigtKL4|wQ1{!={BLZVtG}4s!NtF#ZrEE~y!kqz z^_8!DaAsknk#V-VkkHqFRaZagRDOK=T4kP1^}d(MzurIp<KDo?pc>2aQPz!58&o`d My85}Sb4q9e0Czo2EdT%j literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/BML_ELEV_PS.png b/apps/fo/public/images/map/layericon/BML_ELEV_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..83970a3311924d9ae070ef863066a89d337b9ced GIT binary patch literal 1030 zcmaJ=O=#0#7!J-&H=Oh5qB14R5EX3xnr3ZS99`47f|;c&tQ+Xel5cI;k}pfX*{mSq zK(HP}$G{1C5cQ}>FT&gof)g+5%^y4ndKjXhh)2J4ZRf!nl6*fr&-1?D`#xVeJ#@0Y z?LZqr5bdc!C4<LZ!MA-2{$IaQ5b>}dC39#PPNJgb0wQj}2|%VSEe|q4Gv;R2KrcZw zQD!!Wa_T8bhZd~`7}~cS%qEE5KHt&wDS*fckT-3a`u5~0MVf|8jYL#dbrPUp4whUn zTpG&ir71mTP<<!JUSGlj7C;*5Thq2D`7%|}mGC^+W+<`(K~pldkyK7ilL_boGD3$# zI?HjSDAJq|5k>Ae$+H~Ku=o{2oFGL+iSHq+4~3(-#-x-{2CA{}N~Q`3ITFJZi$%H^ zrlFf>xL7O}Xz+XpBSPMsjWj=Gd)+k!1$eq^I>>}J87OKKa2ClF&UE7lmQ$Cty=s|o z!5Ck27>;IxBh`Sa`hTcp)zKcxfX#gWDePtE9Kd9N2WMR!H*T^!2<1o#7ib8&SqP_V zRZJHkf?feSWMWt(kB*qO0gK+T3SL#El<gtS)<H^<DXc)7rXeNyXtbZ@VnRd^I4&vl zM|mz95tX=-NOA+QWR0spebxdts&S1?ZoDBku!7~_$O>@H^S~Hzp+#1XESZgS>1n7} z<r<B1i8kaiI2k5r>|c$pZDIEW)4FZ(qHcU(W4F85)>pg6^Y}`XQc67Qzg=8-*GhEl z*!szpb4$(T=Fz1y@8_M4z4tyJX?=NxZrN=<Ts!-0Uz7Rx_KyYn!TrURvT*b8hmPdO z3t#Szug)z0Jk8#@bm;QxD`EY0(eDgP&o%AWi_sQ`=MMh9RoJ%ElD?Z?J1;J;l&$ca avGvdjF-B*vflPW&a5GcMA>~p3x%oe+21+&n literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/BML_ETCP_PS.png b/apps/fo/public/images/map/layericon/BML_ETCP_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..df9e4957ba7412d8684ee344371ee72728a40899 GIT binary patch literal 961 zcmaJ=zi-n(7&Q$8tyBrYQkYIo2at$=#dZ@brfPi&jfATxv6PH;>}z5r_8I$voeqV< z0NsF*m7R$NF@O*YLnS1{!o<SNKY#@1G)Wm6EZg@(@4fH4?|XOL*uAs5a(#tinAQ3Y zY|`;^_FY<{|7XwpDjlwoYKOG&K1u8dF<UO~B2f439%>@n9pC$mDh!ijJ*z`H=3ULf zK4)hbF7-poW|+!m8rseP5zs|FFVNXv@7}Y(b9J_@n1UG^sPF9@M5uMJYdHr4r|hzu zw?QS<sDO`%4N`v?#9FGe6J3qYvu&OQ69^gT>}gURvjGeoA)s)@f+L6`P*qNp6;%~) z0Z9-gUZAg95M@nKHE9D(AC^Xo+<mPHYtvYCrL%oPLXGE>B;k@Ghoc@ZmdoW#Ly`&< zQHaL@vC~2j=VuBK#ZKgf#KQr|6zwh^5uK%(o*uyu=dwXOEfXympV}cWazb{b8PGKU z5B2>yIwnnYmhZX3u{916-$XGUMGkG;em)BoYDR=?f+Gv#;jD^{J|;Ns;}94v72Ifh zfs2#)<^*q=T0Mw~9XO~Cb(Sh{p66;Mp|&Ln5|owVhA39$vLM4!8J22>3^!y!m~kO? zMm`G2jO(6ps|&fA75tD!hA8sxBexb|A54y{d5d$|UZ^+ax{Gr$7IJx-44*ajpGMEN zsC%;M+_rQvH$Doe+aqf0C*Rb^^hzjoxMii^yT3P&j@Cacefo0+KDAEX{8+u3JASx) t!h9UQuyPmjU%tLNTw6ZeTUW-pi)+l=m;BEM?Vg!ks(N)7zTVz@^cR&XC_w-K literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/BML_STMS_PS.png b/apps/fo/public/images/map/layericon/BML_STMS_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..423f2e8fcb87d6c1b9192d1547a4cf97c3bb7292 GIT binary patch literal 1542 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nBkco*&`K2Yc zN<f!FypUS}H#V;r8ce_d)2~P@&^OdG0C@?f(AO8g(%f9Q>f(~1RD^r68eAMwS&*t9 zlv<o$T9gcoxHM&uRRvbgMX8A;`9&f5`8lvq49LhY$uG{xFHmp}HdD|D&&*57FE7>v ztM~P_^2{qPNz6-5^>ndS0-B(gnVDkc?Br<f<mO^%V&Y_MXy|I<XyN4I>}X<S=w$9< zX=Y&w)9aF-T$-DjR|3<Ug3xP(Q!gkf<Q4#Jc1bPDEK5ysE6UGR0DIXg6Q^68-Ef)* z)tiFbEe1IC>H{644~kf%h=vIPQxAv<Pqsh~JmIJ20aJSsFj-$;(cR9#z*Obw;uunK zt0c(RUpP?2_Vdk!+ghhNaj#`{R_sz!IkwbLsHd$}+C}UiyZF(i(!#>!Z9mxW?6};@ zEo2|D%REmdk7w!IEnAsXx3Fee%g-}U<hb@J?cVOs@AeeG+xy(^WNGXd>76loozD!P z&)&Lq>vfBCkG(7`X&G_Lf*+s096UWhW9E%h;$|<RRWGLLH{NOgQfXzo&1P25;|Ci$ z7v4}Xnt3JmSNzx04(~eU7Vnhr<vmy^>vw%~()q&4|I^Q@J~*G4D0Fh-ibWa?D}1IL z51*v6Bq*7&YTk!CH|nJ>%zXC!xsRIdY>y*~lO3j=&^@SJFq1VhVC9tnohe>l^nO*X zP<L6){rU6en{P~fHotk;b~y3HEWXvZkH)QLJ-w~)>nWL4S3e!)m$$clI?+9yv+1q9 z*{4e3_h$DN<(4m4J!?M0E|$|ij}FdN)#zfs_*bZgY4=sDBp2q})uC5rm1=ByboJdl z4oOayi!VzOt?$;mghbZQ`F8Kc3kw;yU3SLpZofGuJ+6AWS}R$@h)0*f*HnPlo#mZa zVdSe1!6_edtg0)s3{(zoGqu^X_eG->i}{RD4GRY41&6okY|)*q%AvciH|O7ve@!<; z9XA-woavCdymN6H^VUyh{3qjfojsf!BVmxh!!o0{)g_C`O{3{bg_KIf2h)PO>--B| zvZ<+0iiof8uQ}MVj8kwWqkQ*7VP(TL&+-z!A2_srZf)b%KiyAuP3k&0q0y_9{rFox zrd@uHp_4S`nU?gb-qe_7I&I14c^MYBSwknL=H!MamP>c=x+`vEeq{D5w?u~hVSvEz zuU4gr?rloTWkpWE+rB>DZ+(f4+~>6Yfm-4_#s0os7x9nFfMHhRx5p)mI~zeIv!|<{ J%Q~loCIHG1Mo<6% literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/BML_SYMB_PS.png b/apps/fo/public/images/map/layericon/BML_SYMB_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..497589bea2f5a6aa1ee6c8f4756a96a4ec8b6bf7 GIT binary patch literal 970 zcmaJ=O>5LZ7!DMr6beE;XfKYl2o>CXZ8mm?rfZvI+ZD5v?Lya!G@DF!Lz~PrnY!76 zSiSi(`~md`sL&NW)RR~7CVKPW!K+Xw+uf~)t|7^M@I24^&ig*|YNNI`J2O8c2*PZ2 z-Kz8PTJ}v}<^Nm1&s;v-WOkEnk{#A{V=S!rq=i8>blbR&UB9>g2`>r46bu?o)^r{r zkA$L|VZ=0~oGl1T<&?VKE@q&G+d*W&U++#J2z&!>6&=~3Chi35hcVtftTnvDU9aTB z@-kRT5f=zCb3q#JMF~m`IM79Wo^4AI3?OXRfaggyoef};7=xl%$a}J)09_Xqt*GnD zJ)p{pD#`rS^NNOwI#Tb0;RAWJ*xx~Qt1^tmR|f1bMv)|SyIrwc5J}vYlv1gbX{c(R zBl1ZvVs4s`lH5qa!ig6Llm#RLnWEbw2h4yx)AJ*QbSxVs!!q%LNvTUEMU=B6jew5x ze`pwv(Fv>Li+nE?P8vOmr8-W?LG1Cy?c}mh6qzx08HpQ&?2W3p(IJc^9YTS*se^^B zAo58!xjVo+4yr~8b0ZH|Edz1|F$jF5n59+Iv}LWRX^LWNEB0!^UepR^MJ;K%x;Wxm z#5)La#712Ig3H@9fty(&q&%{P<KQXwD=`Vd;K(SLn2Tjk)EjdBiMd#niCl>%BV~>K zr_rM=?w)Kqwk=<bjgKSl_L$qc{k|;mE3sU)RvPKo)}OPp^3<K9{ly!7`U1{1`#+vP zQ;$zh`yU_N-u}==GyQK5=ieTk($`<ETwlw5?>yNSre)!A4}Si+a6FgYuBu(L-mGrF F{0katFXsRN literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/RDL_BYST_PS.png b/apps/fo/public/images/map/layericon/RDL_BYST_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..1e78cba6874b6dd9f8f3d1ce95a120e0ec52dd5e GIT binary patch literal 1196 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nBkco*&`K2Yc zN<f!FypUS}H#V;r8ce_d)2~P@&^OdG0C@?f(AO8g(%f9Q>f(~1RD^r68eAMwS&*t9 zlv<o$T9gcoxHM&uRRvbgMX8A;`9&f5`8lvq49LhY$uG{xFHmp}HdD|D&&*57FE7>v ztM~P_^2{qPNz6-5^>ndS0-B(gnVDi`Vr*gN=xSkTV&ZIRXy|HU;pXCG>E>i^;OJuN z<m%)E)9aF-T$-DjR|3<Ug3xP(Q!gkf<Q4#Jc1bPDEK5ysE6UGR0DIXg6Q^6u-Ef)* z)tiFbEe1IC>H{644~kf%h=vIPQxAv<Pqsh~JmIJ20aJSsFj*f-*>IJCfl<NJ#WAGf z){@|hf(IQ$e0u6NABHq=1u$wE)P3^Sa$x;&mLEt4IfW=#d9ZJ^-h8aLlIQT5b5HM9 z@814?F8AtHT>pNy)(IT{C~%tb#?nlypKc4j32kqDx;@2v0ppbYTLR2w=B#nrQhxMN z0~6ou_h|<f@$8V4vNT}d`FSO)I{VB<J=sSSPUJ9hE<fLB>hk2c&?`pw(~ZH5-Rb%% z>W_l_=KW`mR7zYRop6!M<G~Zf6F(OH3Hy9QdH>=Ak)1)?9S%C(mwwxC`_SR{9qWy( z>`Nzha87l7^inrrRmIZD+()1IyuQV;=ZLbNYoCeyqW;5N`DTH>;l?gXf-{%Me3a78 zU#$Fl&YwHVmoH8<&Uno@^<H#@#C3_x2HW#5HU50Jyw57ZU?g26a{1>U2T=Lp>FVdQ I&MBb@01j)NZvX%Q literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/RDL_CROS_PS.png b/apps/fo/public/images/map/layericon/RDL_CROS_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..57b5f2ca51d03eb08728f311091e33ba37747c4f GIT binary patch literal 1083 zcmaJ=T}TvB7#$Kz{443Dg6K98CA2#;yX)vqZlXK8?nWcFyP!dV<IGiub>>bp*LIYk zh<*rs2`mW0iU@<qtbE8yG^C;^G3ZI7q<ZKfh{y*cqVA}xJ+uuobALGJeBb@PbI&$5 z)Rz=)Dx@f?BpwqJWL)Qd1*^$_%lF?h88+fbGftv5oRKX^)vBl!g19cX!vvJo?!(Vv zHAUsoTB;d0OZx-`>0a5zcpcp&Y>KL`aZFiBLkwDByJm#wuMfv)ps69csX}5UGYmVl zSdRshJq;<PC#?ikx@Hfkb_61zLo5SF?=)<|3DFC>0-3wp3=I|_I31!FlWLY4K^R#O zRCxU!h2=QF^Ik4c!SmcM;A1%-!;+WxZ~>u$7krgq>7hw9OKlSpVst4MS%v5hj7@=I zGMS7w<M$$~o#BGPpsV5Yc?iN|cN<uCJchk3s~|#Ku{0BF$N;XQ+={wzh$fjX9zi#k zWet0&Or&6pBbyB8W!)oXfs*upsID)gZJdBB`TkSbPIa4*NkAKQSqf=f+cr0pDTFO3 zV`QZe>daQLu>)abcOVmllRVhjq!}v8*yRg&NfP3Qjb%fDaWO;_1+S*50vq-P{FPN= zAP}zQxJV!v;H#?GfUhnb^>ds*nB|H{>C&Nrvs`tB8_CIat)QDEvIs5h2vnmM(!s)! z1ub_jbvgBxxN7cP!a2DNNrrJ7`&Xm0Tf{x?blJ9Kv21*35Vu>z)(>9$zL6_&J1*9y zoar~onUV=mJbd%$z2fu~Y$<&TipFc!4;2^PABhd`+`e~uZeYiOyRUwHIs?kC-a3%p zesbtE7p<-S@Yuj*1NoQi%SA8k`9o{o{gnIfT+tKhUvuXZsr2>4i&)=4|J%G%qhrsM zgV*xQpG@rU9m$+yKTf{ypV}~yoV*y_{kfisK8hTldOR~xcY*hxZ0tQX8kN!<`(?J^ lhPG<1=9s*;mmi$nI!?vb^=)?A=1bk{9FH`JgLN$@{s3DZXz>65 literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/RDL_ETCT_PS.png b/apps/fo/public/images/map/layericon/RDL_ETCT_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..29c0b77b4ee74276df8de9416fe284e4c8bc15ec GIT binary patch literal 1016 zcmaJ=OK8+k6b&tw(vJ!*{1ogXU8vB>XPTs)II*3XOznWFWjfFSH)fL8PUs{rO<tX} zn--yn3!xS_T?m4pE=1_Um4buR-%fF(?(9ZzBO-1Di7(U6)P-Y6@;;n%?s@m#cYSK| zd~er@E{dXha}#QwjEAGIvxEHme}p<2j^k_*Por5})jde1OjLp(XX|q?4|Q{C;SEeu zR6A`Iinyp<kPT!rdW2yD+a+v@N{$AuZp=drN^s6{6#CnfXEd-(g`N>LPIEJ`Y)veC zaC&*NU@XrY36mZ@2a<tI1Z;?P5ZD#Rmji{a>&j#vZL>6}L-4#p@0u!VQy_yp2t;Nm zW^g<YB#Ge#QIhyU5a;+f%aK=#@q#Q$a(o!<Jv52tnX__U9p8&ZRtjCl*p*qfTCFnG zAqIJKET2duB8_-FMi4Q7$-#OMbNqpZf(m`Zvs`Q;2Skc`2`yrUCQf&cV7pCO$KOj6 zNf;aGF3U4qbfgAQ)BX>&?IzmCdARTQpTd4&$%Skl`e@NJNa1D&qEN1!@t}^8S3s!J z$l_EPVdR&Q3o_FZI6Y%ICaU^p>Ud3)bB>R7$ACFip@{-xS*ARm&19rhd{__#k>|5Q zN)$#$QrT=;Oi1Y=Dc#_z$XK+YgBx6PpF7f$8?}P%lE^CbtSitQ_mB<hN0zPDUWk)c zUUs==YcEnuE=$a?QDOfobYqKjPc&_|Em<@hA3CJlJ<`@6+h6XGD^ba*sY39nv^Bc@ zD}4Vr>=~;C%<tj$t=ea<uh`$c@nPle=0mlwcK=1^z0LLQV_WaWX84`;SKR90YNfVP z5#C-37hWIvav&+(e!6<?<j?1KzPEJ?r#5c&r8W;fIJB`AhT+AVN2#_RYP~~TJ9`6t PjqYMDJE=ZOU%vVWRx?RH literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/RDL_OCUP_PS.png b/apps/fo/public/images/map/layericon/RDL_OCUP_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..8a1ac0074ec2fb6ede26d23e927b6fca22809356 GIT binary patch literal 1061 zcmaJ=O=#0#7>-tp>_^m#%!?s|Img;0{mI&}x^+$K0(R84*dBH;O}?(#mV7b!y0*iE z8*?alQ&5?^$i#!92*ZQF8;I!1o2VDBDvTW_3R9S0y0-IR4N1Nqp67Yr?|q-|a$@9U zd&`j)f*{((VIhgf1NOJiiT_78wj?}splBAQU>=nu6A)nq<^U;b(ilhrNvWKB3;GGd zL8<91%EnLeGSu9Xjd7PX1G5RDf1qqg@&rI+4veXKh+2R8k|I?lL}mPOCT>JPK^>kp zL27y=El*F#L4_JPLH3t<ET91-k!5XCxA=01s_OE1Zg0~RS%sj95Vf6DHl83O&;+F4 z?RCiv%aR=DW_^B+V|z&t!+K~2znqKp@qUi?^pUlP!qH46&nJagEf!vdr~*O;Pt&DR z$zAfgp*cpg!C=tV@OWGp;j$_^lFBaK>Z~gWz>-bXKq}NpTT#lvA_`GB)9oW@MnhJ& zYGuL&qsx*(vu?&dQXLqN{~xMp4YY-lU?<;y3R~%l0q7*KV9}Iu<MN$$D1(ofKtj+= zLpWKlVxj;Mv<lE5BPovT&ZxQqOV;r!J|5>q-9nNs15pT3Si!BT3h$3{0UyhReSU9@ zWuv};j|mL<W1g_bi>vMp*SP|eiyF{TovZ9{hnjM2D`*CeEC5rT0!qw;8d*IuuQtym z&{VI+Rhs7#Y|5o^GPK>;zZzZN!tSxB4cp>H!}vhQZa1;54?CBG_)6Rqg>bt3Dc9T6 zv-xhY>&x02P<F9PckYPqe}Dg)V%oWtdyi%mNB-{8tlD+s!mIoHoj<;f-u}oCQ>%|R zoz92LEzabJwgk=0?mnH#TvzDP7w0<;UZN<f?bpxsV?1+lZZ7ehaEy<S@9}?rQf&3M z8R8+w{6gy>8$Q$ftg<mbb8DICBd&G7*?VPc>+0gdDnYIg;-c_cm>i7R7gvmq2oHwN G&i(<yMpM!N literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/RDL_RDSN_PS.png b/apps/fo/public/images/map/layericon/RDL_RDSN_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..5629de9fb47f5db0a03cdc950a9827f52c19ed8b GIT binary patch literal 1313 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nBkco*&`K2Yc zN<f!FypUS}H#V;r8ce_d)2~P@&^OdG0C@?f(AO8g(%f9Q>f(~1RD^r68eAMwS&*t9 zlv<o$T9gcoxHM&uRRvbgMX8A;`9&f5`8lvq49LhY$uG{xFHmp}HdD|D&&*57FE7>v ztM~P_^2{qPNz6-5^>ndS0-B(gnVDi`XliC^=xA<WV&ZIKXy|HUY3gch2@G}vV@D?^ z3sYy9UYGpj(%jU%5}4i;gkD3OdO=Acw*Y9fOKMSOS!#+~QGTuh*vnR#INf6Aiqkx( z-V~f}F>}MIS0CsYeNe<AMKnwZn0i1=c(Mg@;0Zr95187EfXSMvSvH4(fpMy*i(^Q| zt)xHy|JyUGHn^s=`ZGU%U(dr+|Ig6i-#`9kk_|P-?Efz`(UOmp^^oVjFrmud(wi;T z&XujL{{O-mjg24Q*R#l<N^3dQ_+$RQx}+JKi#3_M`x=y*Wu{9wUvE`a*{N_<Z;oSh zSZ`zJ{NDD5r+!zf{QmoDax_oPoIN}~H&jx8s&trf9A(hfv~8<RG(M11SC+@t{@;<u zPu^HUrhb{x4UV0O{j3tnn{o}ETe`Go)S4A)9{ywcTr%pK9K)wLr_c|EbK>?*c64j% zfB56=W}dy#X$z$`Jo=W$ChMrm7AaTQ7AbzsuqHJj`N8AF^dDcIsz=BzDSY~q*TMXM zQpKNNns-=x>Z-N>H9P%!ak=}!1>ehD2|Ip0GCRDnU0kB1;;Ljzok!#14-emWJM^A^ zurXn23P+!)Sc(1FU0e8savi=+Ex+D)v0PNJw}olqnk775%-uPw6j$<g9OPs_@{jrH z|5i1<4Kf~Y<Rf&B+BGdqjO1rt{GsUm|35u*CM@x3VhoqNlk(%wOJ!!|r8_4+GGO2^ ZU@+eGM%ML^nhU7V@^tlcS?83{1ORfP(2xKC literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/RDL_SCLT_PS.png b/apps/fo/public/images/map/layericon/RDL_SCLT_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..7281dc61d8365c62f30d898053bea5bd31b1d779 GIT binary patch literal 1072 zcmaJ=Pe>F|93Hbogaz|vQNBhD!**w9UANs~$5m%`b-^`R7u-XTvolYfbmmPnPj~c? z5()`Hc~Sy{qJteWLOMhTmHyFLyad{<lVl`Bfib;NS39%~GxPrNec$i*e!uU{ba%CT zD$Z0;6y-^Fh-orbx?g!2`Pb|^5*ey-Jd1l!Kh8@gq*@h}gCMC%127FGW$flh7^SFE zTFqo}Hr2_=Nb^Z9#%F5=VN+BzW*d?`1To0L0afSeo!2WgP!*o;ZA$r5h5!fEj&T$A zjCW<^@gX^)(6MF^wK*c7K`a4V8`dq(=IMQ1j?CR{h6ei(JjBxnNo7;rKtLu0O}<92 z>}OdJ3i;SzQz*n<1_3`CVEp6_dD$S>6ygF`z~MuaXr|K7rNzWyEVAP1L5vNKVe<LB zFW=}x<^aP+A`w?35bzR&*BaBYWP5e1wxA$FOEy<4If~qLf1;n5Rjm2S?D1BU#-# zEE6dhV@n3Z`uy&Z3cytA|4>akLR&ZukMsSfu$37zAd`j`8Zl+kxc*u<l)(umlrS<g z2n`pi*gc3avIda>gq{$n?^SgL<*iHm_*9BZ>K2xC874)ZCJH`PRk(04oQMc)V=yQL zSvDRFxB5d7u}z4F*?=InwH3G`l1DVC;{sPX<_3#$T`On?i7Y}>9feB5L>kyXGN%^L zg)ORg$W@Bx5-7@LNHUDu*uNTG*dp$6r$@FWizDMhow(g3ww_N+Z<8zWBq_FL>`%Ep z$BC8JO`dwbEhaMSyG~<nvE&ui@No5;v*Vq0CSon@eNUCp+upsqa{YtjIPWLdD=(H+ ztoi+ur}=Z850<AEr)KA>-rSL>j^!7RO6H#}E_r6Ypq=WiTfa;DWA@MTr5|exXZwWu z(UPxIC*L*nF718Z-27ED7u{;P_VUKY#N+QLny2rb=fN;_AzoJp?~3iUPbsiUY0<a# S?!wg#_YNoHUE)$(-|au~PGi#m literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/RDL_SEPC_PS.png b/apps/fo/public/images/map/layericon/RDL_SEPC_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..087b4e94149966fd4edc1dd5b27ac50e40a4641f GIT binary patch literal 1068 zcmaJ=TSyd97#_94Y=wl1?4`4#fk8X7v%9mG$<1_UH<wzobwOVWXJ?K&=**dBj_xSE zBuI!o^bkG;N<BmrLI_0{$d^RBKJ-*jgb>t&Bt>Dcv7J#@duSVG=3Mx`@BhyK|7X0t z?L>9efhvlks*|l^nvA=huW|?ZAN*dB$WV*pUAP1F;GASas#!r<2$GuA3)4_ihR-j; zMvAJS)l3)eN}Up9q%o3%VQkGHY>H}ZvJFY@hZtmGuc}AsuaBP4Kvkl2C!g}Bj2P@w zTSrXTG18WiNBZT6LN^@)jkZ7pG>9c&YXiC^*im{-S0Hm|o29`T1oubjbyHobb`V1* z1U%#S$X<>E!63s0_+XGb0(@T1$9l;d^l$-z4+_2z*m!6X%~X1Xw3yh4MOIO|4`V}M z*<3Ei<opaWds!|Li8vZQpNAkk*07Ex+oM}`MFkOBvZ)$aMLKX4r7Rl6QJOeiKZ0g# z%Ielenn=P}TQXRV@j6E;0#m8~Lp5y^ZQ(TB^7~I=D>H0BHVrK_Xv(B;J#|hfLx`DB z!pO`ZG*HZ9dmqBc>O%&Ibp$~}r>ZL`XB}R{r&2;vx3HwkFeyf9qQI!CB8VZLWVyv3 z;Qb=U#RCyB;g5N}VQ)Ab3Uh&Ykt-s3P=h)ya+NJ^pd{C61<fFlMQEx+P)V3b18YYX z)Y4u^*-Lp@=PISW_)2nFVup1J`&XfhTcmrO>1NxK#b)C}opifN+B&OUY9Uu*Iw>}1 z?04CGq0m&}YB>6{E*zeF|9kB6!i9axtNW*4*S2nN*da#p@XF-m{H@h5Z*HzuQ)O<q z`<aU>tEs7R-3_4+-Tc+@i!F1bCztYXXN`Mz9yhjCtURQq64zaJe#QOk9GD-v#?0+q z5+8j0_UZYar{y<hW|$Y#1rS^~4qmoS?&{uIHFdk)^?7-DY<6N|qSjbE!yhW&wx8-h V%kh;z>g%2Rn~b-KGcDbte*gsmT|@u? literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/RDL_STAT_PS.png b/apps/fo/public/images/map/layericon/RDL_STAT_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..13d8ea6899c02aa0d0917b630ca9f697783fd6ff GIT binary patch literal 1075 zcmaJ=&rj1(9512<`H{#)kqa+fOw_P--MZ=;1{vKZi<T^7ksUbDwGY-n`%3%91`#q1 zh#tHc{|C89NHoNRgNvFN<53T4gcyl2(SuQ=s3FW(VAF%MY5U&y<@5P`f4*yp{<AHO z?Tr*gwZ!`(NwOYxzJ`P3-|@99ljRtWrttt8!Fkz&R9HnB2;#at3X@P)rzW1jE{dwB zwNx6XrSpP<bdT&{JO$k(Y>MjYDVVY{1~JIMQOyX^pH}bFKvP5XU_kOprU<iI-?Rk> zru$RM^q3M<>7H)TRS<}P4zUah`nX{Wg%G`?E0Dc&%+O#5g2zJiZcu3{0Yqd$5b*fj zikD>p&wE%d!1HV;@OfDu<0UWeW;r3i3%=7}@1cn|OC1rCk=ULuVuk1|#-_k9`F!4! z_j`~v%CNy;(9!Vu+yvparwl9?+=lI{C`6#GSel77WB^A|&Y&C)(InE{6m+vHYuI~b zA_Zd#vdOR>uai;*C`tc^>UtGz<0SkO?>~j@)RYOCB(zb^Qb^-QT#hSK5G^QUWTg-q zuT(LSMHtyxWCC%32PXzKLq&P}<PKhvgt%d2*-&6S5~7KMN7Gb6<ilZ(3j{b$<XAS! z5krhcqyB&x=#9p>GZk(GDLEY)xWZNcaQT{CXB2dkc#c3zn}ll2LOR$<S<q_7;;*T< z$5m^`!qwz5BpAkN>|c$p9Fgg9w$-sEMs@I^L8jdzV}1OY-y&DyRy-0;6<%ew%H^JV zzVupXjlM;>ZWo{HyvOCIS2I^-|6J?Z0Wkk`VB^ijLzBFB=EJsl<;(3=cId&}xjPGs zpsi_Q`Qf|pQtxK_1*XV#|N6FYsjW08nU6nin%`GDdOo)o{msL(3qL#dFVEMxR<e(d zG`-+9xZ+J*qI}fR?%D0F^3wWx`NwlFn`nr&lv=N^&CH}XR_-n~xK7pWYo>;76pH}7 QeD7T2c(gyV)H{6nH~m6mg#Z8m literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/RDL_STLT_PS.png b/apps/fo/public/images/map/layericon/RDL_STLT_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..489524b5c4cd57a22db674f7ad8897be209f617b GIT binary patch literal 1089 zcmaJ=OK8+U7*1WNwN|WBL`&5ny(qXzW}Dr*p=%$>wq0=Rx?OA)!KTTy8@9=$$<*D} zR}~LdJrwoe>!3off`~7AC?Zw`6;TgG5D`3h5H0AzLvfwdZtKA{B$)@__x=Ar|2Jca zj<!|h)#VJstctZONjg?~Us);rZ~mTF>9B!ByGbYRBU#l!OtX%A5r~;;KT0B1A0B*$ z8W_gM8mVs59p5Qw*yL0X!{tnyvKgkKF=wk<1`*JU`VA|>ew&<PfuTp(u3%h<+cHWU z?IRBA9O+1DBN;8MvyD4ILr$UsCL$`xnFE$9<s$67u0-eFHqU~22+2g)KS_1R6F|le z0zt0MuL%%>P>6$KFcgB@KtO;2UZ8Kt4@D^$k^=Q$;bCbsNAHu8O6x)_x{9!ALTriW zv)L?{t>duM&%<yy>}do7ev0tB!xm9<e#@;bC@9F)9K$9Cwt%Oo_TnKDVQHp+N-*t3 zS<78GCVF6ePPKW+30_GBU_AbRsA(>uU6Mpg`TkSbO%2<KPa+o&IT~$TU#%C)mShL1 z1Uo5=2MVW{NMnNCG`4}<83J3n3`@sZck4Vp9+zU4OH@lkF(txM1<o*Z35wgpEzzJL zigF0Ts2Eo2p)7=>uwD+<i-BN)t6*)&L>4J<^(8JW%Jr;Z+BC9)9OEF;TODkI`I050 zXf9&3sNMosFPe+kT9nJvWO%Q!e>J+WMcv~~7i~)yi^fM5b-P1tov{<%mADgAnp3%V zy>t0|qmQf1JocT}_aFYUa!>H=Ohwb{Q`a}W2UWh=v{KR}um4yxULw?J&tA+PTlOeF zbx-+~&rdVc`J)?`zv;QP0-*fv9|BC2U3_)5^-@XI<mkRqAz&VQH2ZC=?Bw?+YoC{n z9l!ti^j`aM_V8S`=Yk_Y_;CE<mBGQEUF`nx)w{}{-i7DZl_uo3k=lpr&wM=TTeEKB p<;$-<vK@s-ZmjuKetE(-%J`Uy>I2u>W^VId1+i#{a<ir9#BaZ+Wpn@l literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/RDL_TFSN_PS.png b/apps/fo/public/images/map/layericon/RDL_TFSN_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..6dfff66966291fe05d398c61b76a5b2928fe21b9 GIT binary patch literal 1291 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nBkco*&`K2Yc zN<f!FypUS}H#V;r8ce_d)2~P@&^OdG0C@?f(AO8g(%f9Q>f(~1RD^r68eAMwS&*t9 zlv<o$T9gcoxHM&uRRvbgMX8A;`9&f5`8lvq49LhY$uG{xFHmp}HdD|D&&*57FE7>v ztM~P_^2{qPNz6-5^>ndS0-B(gnVDi`X=><d>TGCfV&ZIOXy|HUVc=%uYVK%eZ02m} zYUJt$)9aF-T$-DjR|3<Ug3#-TQ!gkf<Q4#Jc1bPDEK5ysE6UGR0DIXg6SrH;aheC! zn}XXd7C80l10ACeiddwGh6w>v4~Pj*wm=R%;iu*SQ+p9GSx<7P{msC@SnuiL7*cWT zNbq@YCP#@{<K64>{xujiT|43Is=hl#K*R0%KL*Ywy;v(2$I9*nR$tk_$XD<$%HG~r zs;8vm!5OsD`P8o0@2+o8ov=u$BICiqb7y|v`+o0CpMnyPu}YgvE$ga{B@GLCA3x|R zywR^vHJ7nGu31-a;ir8Eg0_^@8gF0_XFoZOKWk5(MSk6ZNv<BVk_C%5aBQ=g`f!<` z)sFUk|Cq8)XbSl4Dzas-51i?vdU~<s_HE+oRct%APqGUWUtu$CVb?^jvQMe)rSj3| zS8q05nBMI$*SIZ~rJQSmpmf2Jo#n=Rl`WFuSD4su`pP0$T5&F0Y=N5H!u$e}-`1xJ z!x_WoJzV2{%ZoMYnQX?Nv=kFY+vuig>zaI2kKZ|J#uz7X$9DY@pZJ2^2XfX0RUW?I zbf`nXX?K6Xve)x2bFaI&H)^ZumXpsn>MRzM3KzZ;_@^XqcR}0vR+;S&_OS8Hs|qY? z@;5spU(VA!we!qB`{f^Y-<f736z%Br=XdrWp#+B3@WlnQ_~a*oiYHH3KbLh*2~7aw Cg~qV} literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/RDL_TRCT_PS.png b/apps/fo/public/images/map/layericon/RDL_TRCT_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..ed1a72d8a405f43a2288cee485a4a32a82db722c GIT binary patch literal 1412 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nBkco*&`K2Yc zN<f!FypUS}H#V;r8ce_d)2~P@&^OdG0C@?f(AO8g(%f9Q>f(~1RD^r68eAMwS&*t9 zlv<o$T9gcoxHM&uRRvbgMX8A;`9&f5`8lvq49LhY$uG{xFHmp}HdD|D&&*57FE7>v ztM~P_^2{qPNz6-5^>ndS0-B(gnVDkcX71!{VPIiwV&d#*Xy|HUY2s?=YGL5)WMpb! zZer;O)9aF-T$-DjR|3<Ug3xP%Q!gkf<Q4#Jc1bPDEK5ysE6UGR0DIXg6SrFoaheC! zn}XXdMmY8A10ACeiddwGh6w>v4~Pj*wm=R%;iu*SQ+p9GS=)AZ&0}C-{Nd^17*cWT zO7Q;d5J!Q3W#!-g?)a`(e(z|^jzjVaQo<8e5;ko7Dxj;PVD^u@sW)Ny+RzCmU28kU zk{0&Lu?Y6IyJ>F>IN#vN;bkFI^z7Z<?VI22HW4cew=^&~Q}g-b$Fu7;TuYiULBgm_ zZGpPKymHs0*Ru|-4$_F2op)fC`IE$x68|Qo-YqM?Tv8I^l=WL;b>HG3EoY(R)qB~B z<a{=sT$i#)eBu{Js~(S+wN4L|D$Am0KT=P49-8%IXX@@pAEbBh>x^Z+bi-TCIF*Al zu{V3^1|AJn#i@NK_0NPpJ|z>q&u2-UDAV1p!y9&Py<7QEW8Z}0hdn3Fdm2U9nqr@& z<YfiBKTB&<b?Z{D+WL3vy)51H=Vj*4nm=dGi!WPuc^^{Qc*TUl$Vg-1MC~)FTxG7u zn4R8==-!JuaOrgFnR9-RFE;<K<~o`c`)i)v`iZfV4c345E#tb8w$6lE$gD?$<74t$ z>#%!!k8gY_DPv*PsGw6|*eCxi{m+Xh_e##q51r;e+2_57%IloqC7JS`vlhhYC4P;T zzQ*{P{d@BJ7aC0m{^!iRe<@!5ZpqD%Ad}7)Zu*{j5ig3p9!v@0knUyUleKG__gRaJ zsbb#uGY{)8*~hmZurk*FHLu+I%A+Ozk6d<Ig{|(rzA7)Ou;E2{`SZAUvw!^mf9L{B bJ&OcGN&L<E4-b_{fXYQrS3j3^P6<r_lz|TL literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/RDL_TREE_PS.png b/apps/fo/public/images/map/layericon/RDL_TREE_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..0ee84dedc1a31c971f4388eaa83b174f3e17eb4f GIT binary patch literal 1136 zcmaJ>TWHfz7|xuRG3))sDQb+M4%eh<yI#U-*EXvw*t&Iv6%<*ToONL)Cri$3HlI`! zL`4N3)CU!%DkvfdGSQ)e=q8Fd5Y&NA)HhLapgySaWUkW(Ye;e~eBbx~|M|aUUrTDk zoa!aj1VPM6H1laZ&bObcnfSe8+!F9mgPO9a4R)e}paUWz!5knHijW6sAV_^Z!=Qm6 zDk(XWMcL#=PJ{|A*cjSWG|VQ5hOns#VmCl!4&-GuM18z*iy~zyM77r^T}dqly5#15 z9klhQGGc$X7?h~+da}Xfuz&)PK$^-n)!@t!HKEJlxxLL$<OBqDhp694Ws@yr4C;Wa zr#(*5#j>Q&N3-5~pO390-7eP6xbW?BvR<y<$GQFF<VE3Vy41;~`S@fkyb4iW2x%O{ z6bc2p;Gv<OXV_pcXluCLPK<CGeJT=6r)sP!De%A$by-6)R7qP=$iZF|qHw0aOHi~a zS=E?4CVXIwDQFB!yX=xmz-03OP(_(S8z>F_<oi!yBh#k=CJhYOtBbgCovZ9n8W+=n zfS{g%a9imVTe={EMi<n`SeuVr+b*jTEEu&D_+*kxs0I>L5hVB!g%xO7mN-5V^!xdE z#OsauShmR<^~3`KkJ}#!G{ybVK%~Uwq1dYc6_vQsA8xcP*S3P9;mADD<?TR<>rf#l zO6KJ9xdh7UO>(93xdh8{8JrAbH}<bam$tBb?CF$k@nXvOK*es?v8}Uphx7Q8c$?rO z8S_Q%n`MP7>AL0jzO6XbQ1#~N`|;hc!z*LQ7JnjM7R}-v;$rna?VOeRaKN$f!~sXg zlA$%j#FdqekM0tyw_MwO`_5*oMs<6}dS}e0M<XYS)KB)pNpWx0hwq!7&2Wvvr9bxU z-|6V@`4LXFyM(LDq;*4I^6SWvQ)jK$jzw`T*EqhTXC%D0c>j3K8K<>No=;q#HvLP* z;OE@CaNJROc(CHk+3I6sTZ7AHwH~^(V6Ikl?Qq_+25TQ$5%2TbC(Q>B-aJ}WIq%i% p*3R4KzcOn*jZy!R(-lO;Ok&{YWB$SF^#k@lAkmcKFGo9e{Q~RKeFFdh literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/RDL_TRSN_PS.png b/apps/fo/public/images/map/layericon/RDL_TRSN_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..15675cb315243b6ee8ea7977c337e3387ddcb6d5 GIT binary patch literal 1375 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nBkco*&`K2Yc zN<f!FypUS}H#V;r8ce_d)2~P@&^OdG0C@?f(AO8g(%f9Q>f(~1RD^r68eAMwS&*t9 zlv<o$T9gcoxHM&uRRvbgMX8A;`9&f5`8lvq49LhY$uG{xFHmp}HdD|D&&*57FE7>v ztM~P_^2{qPNz6-5^>ndS0-B(gnVDi`W@&0<Ze(a;V&ZIWXy|I<XkqT+=;&tR=H_N- z;Am(9)9aF-T$-DjR|3<Ug3xP<Q!gkf<Q4#Jc1bPDEK5ysE6UGR0DIXg6SrH8aGD3z zn}XXd#yIur10ACeiddwGh6w>v4~Pj*wm=R%;iu*SQ+p9GS(i^N{Kvq+c-hm%F{I+w zl*x|%w+%#&|KAwATq|_9qlSXwEWfDRvdiW!D|~*e)mnr_zESx;<3U!=PVP&6yWdnR z_zKIIB}lCnXrJ1`HN_-%(zSzzOB|#XD=tl*|MvU5xAX4@A2M)J=~{GRW7OJz!p#RQ z-Iq8D9Qa<l<#z6lb<yHwnxDEKhwyYy^n1?e<iaHHvQ#5{mBtIJZ)N2@j_E?uyVm7% zPtB}6ad3{>wtw@IK0h(ntNYjR+Tv2bp;(aD_jaL(X<PGde_Odn?tS9Y%2vzU({@$d zbXfiL$hxn2+jook&$Dsdvs#FkYvB(otG4s&w6E`f{#m0hW$D|>xR-@KLd*iK2hQ(1 zx@sX;^uhN2`4dj2O?>fthNIqe?&L#t#}5{rJ#=YO=d#Kshd(YVvzE24TJ?_qu0oQ6 z*>l%LM$cofWT}~%N&TJ7*MDk#g2KAmf(ebe!8_|})+ipmp)DaGnqDd!pJqJi;O-*U zqcbl~H=eNd0{4YkL5coBCc2yD4NfR*<f~HpQ5ALYr<3EWn-Sb;kL#6~Cml%eSaJOK zw{D4mS%+qG^RLV=UoIBO_*i&yC(k^U5AXj+U8}KT7i;mz<S}0Q{qNTu+4El?t6E;1 qT=0G2-1GncOnNKxme=Y&mjMHJ-;Gnw9~*aoiabwOKbLh*2~7ap5BypH literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/RDL_TSCT_PS.png b/apps/fo/public/images/map/layericon/RDL_TSCT_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..ffc22515996bacdfbece7d30e3d5afcfd20269d2 GIT binary patch literal 1700 zcmaJ?c~BE~7!4kP+-gKctlNlFwUP@GASK~Qf}|xDLd58lYK{#FklmPF$N^e~ieg(~ zP;3<usnDt@BPuP3f?BR3YFkB(1}$=VK}IM?P_P>W+CNHncK3J8d++<c-}iPlGjiQp zX9o`l91iEq3+D*1(arkU+hXr!{cpwCuo&fv&}dkWYQ-857b1ftAiz_J<3Ir@mg%?t z3I^hEGYLwe2o>=o7*be86k9Pwol1?dak#)BomwnS08u~!#wj5t!CX~C0F*K&VFQg% z=BwGDLK$w*fYF9^La8A^8XzMCv4B7w0~1hzs2I?x5+Q`4V-m)78Q9#qO(Fo}5Hx{F zc$buj9|^Ew4G7SPKHgF?g#ys&M2atsPN%E^sALM2M8<BqH^rAhqcf;}z{EwsqG@Du zhJX_`5er)}2?`WdGe{(@R!h|S5MfOmi4qVHVAY^fy)lG0qK8ni&Kp9OPbzRgM5<A$ zQ6&rkRz<M{PC}UkEYo)-sMJ%k5HfL0*nyFBVl|0EBwI_G1oHX+4^^qA&<H93|H=11 zg%P1%4Uz;P0w-ytSmWf&t)bKmwgwcVuto^OiIb-osen-!QNU_|9Zd&TZcsupSc|M0 z$Mg9N9)zG`NDA^eOai7rR4QeR05**p%B6?-`m#eP6t1s-s2`0>_6zk3poCKWLTQs+ z4lGSlfe<>$l}&N|$kTGIR#2(2$Q)3kOa^6P8dwF4m&{O3p9^PNy$P;t+Fa<|X}KgU z8IrZJ|7!H)7Umx7bjr5aV#@d+gt=XV*_sLU$g!_w5swoh)IA6k#40}H;>T{9-nPDk z^6DR$io9uMF|)VLSzRp(NnBP0h`4K5_Pf4Ugq%pTXYFw)v!8uZqzHa|>VEJxvg_3k z(!a@kRhYK^PUP*JqRj7F^KbNCPBDAlGQ}?S_d(=0hw{zMi<=fo@XMQ5@4480GKa-) z!5{Iz5`(*I^ILMAc4vf*?d>gwjc$BLBt_x5qj1%tr2Dp8Z`%pFzi{hz4|jL6Dah6f zU#=(vo4VJoxw@jFYa``~c!^i=^PN?v3XJm_n}*@k_Xm$$ADnl>h|7s+`lPnUE~mAr zzO42M`Im5|sj6h)<Fm~X=Q;B5sNT;vSDKIA<sI;v6CpRmS7Z}CO-C!L#`0bO`)khw z?lbas4WE9{BC0fus(boevug5-AEq29?^rg{c+M$5c}Yph3(@9LDKe5?-oIV(++wf@ z3U_2|y1X|H(igJ?^A<eccR0PZ%8n9Q0`Q|Rc=Y|LoH<fZN_c$0tz&T=cm7ChBs249 zQ!wGfTZor(#?S2wX8q)u664gHR~K#}!rWsT2VLUDLomLwVswcAMlapip>_P4V%wAK z(6BYJ@`tl$+)VagHk{*?_zxW4Z7y)kZQ{XpiVJv;!?JSQr!Ivp$zUHFvYqP~QZvf~ zZ;9^EuN`VVACaXZ8m^axX{*w68ok<&8Oisd&Xoa1wbAv_>?H>qf+RunJHL8WwD)Oq zuF;+KI;?$XiqEC~cxQcV+nKDqit>1M*RV_Aa3fA$dO_Xx!lhoa(423YQ*)Xn>`QV{ znIxA6tLr-tIhFa$y0cr|J44(j$w;Wt?HLl5Sw3pZMVuqPxOeSplxsB_|E#;iZMb2y zAHEdn{b(>VGu!fdW@`WS%YmY(I%9LkdtC+fmK)t#{Mi2abALpnZ|-e)t$Ul_8+edd zpOC)3E;r{%-KWy7Itt4oEVkeNsu9=ULaC<Hu61Tt;N3{6R6*?#MojJLwx{ghGZO!L z78if`+xmf*M)A^-qW0K*V*~wB`L|k&vzVLypmz<lufO5gKJqXtquiWRdO*>>*~S)^ X+MJ>?k7n6e{~J8+I!<ZmmbAYC)BCkP literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/SWL_CLAY_PS.png b/apps/fo/public/images/map/layericon/SWL_CLAY_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..e603ffa9c315c04a81e973b4175aeb218b878850 GIT binary patch literal 1146 zcmaJ>ZAjE$9G`_Em1P7{TC`@E(cNvkx9-+mYBw(rogH^qT0}UvM;+JptnIn(G%C;_ z45Ipy5q&5M`&K~_LPcqPDItjHi<BRFu~#!NP$Z~l=2;)Q#<u7AKm7i`|J!ftjW%vC zT2#7-Ac&$!9UsGMvGo)d;P=|epCVpXq1t8?hixb=8i1&gVJjdbs@M)<K$JTVJO%-R zSV$>}X4EV+a1vA<qJ?o}R2_R0M4&38i&7FGvK6!|T9BH!bDts=IY>2m1V+$9phKza zGC;hmF(Gv&CBIBnZ6yO44il&ViDX9IubEsXNX_zccyArk6gdk)$sqMRsb(QchM)mR zkHck`7?vfyUI**;c)hHRbTX`yX7KH`vu@7g<(!+zxr@Tl47rVq@!`2x*a}h|2<aS6 zr_*Ui+U0;oJI(t2ev8BDv}1(b?9`B$v1?{|mVpPRWGFgPphjAZVk=CcAcZsiU4p95 z(`x2in{dPEjHuJBgRx4=0tMm!P*t5rn<xhU<oi!zGtsF7ItEObG9)~>wsI?!&V>vh zB4{Ka+@I}Yv;!h&c0ipB#l2)@lcLEmZEl>!3j!C>OeAU&i10xQGdL7Q<`|~N$#_Ce zw}%a}Y^@txe5ls%^M%7K>ka#|zC4stD$r2YSN`Mc%IRxKLDg|&9vI3&Acqa8lCvdq zO72{koP2Y>a_(HPWOCF&<78-Suzw9YdxX_vZRcf+jd|e%4XfS2vMw0j_85N>Un6`? zA~SL&Uca=PDIPCgvAMF8c`$PCxZZ1Q2^8+F4lGPgy=;{~G{i6NTv4%ZylnLD)2sP> zB58|mQl%c-@R9!KQ$b&T<-kB+>FFi5o->`d>uwZQP|Tr{hFve8MEVDh4Qj>9hYA12 zZ{J(W)(D@5F6HI5mv8UB-YZ_1d{(kJRnao>Y{TidPy7o?s!`vVZSY04KAnOEACHbr z+*`Ij`oi9?oH#Y}ZeQ8p`6iD&w)*g!l{=2Vsyxegoh(}F8FiIZN%5hZhc3_Td4$}) zFW38A=PFLTp03|xpB&mfT}^z>e>n2~$MP0ppx^AB>A5v#{S6|ujr_H3E#1EWplg9C literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/SWL_CLAY_PS_RED.png b/apps/fo/public/images/map/layericon/SWL_CLAY_PS_RED.png new file mode 100644 index 0000000000000000000000000000000000000000..0e5450688f9dda207fc2f3679b15d7b2a3e3c982 GIT binary patch literal 468 zcmV;_0W1EAP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0clA@K~y+TrIXuj z+b|S{KdLGu%C0GrvMt4y^VA~Qp<N)$bcG@dBxxr|vO@>x5(TnDUjyZ0ojg!gEY(1p z^aqG@0r~0YMM^~YA4TKFOQm)l9Q*9Ac7Fc4Rl9W$IQE&GetI9eqCox0YL(*4kDCD` zV!Rk=qYkp8R)zZX<A;IM=Q9x1FN#D0WJggO`eSGPH0??<TcK^mG%uN%C0TyJG%uN& zip*A_Hr0NBFE-fa8eeQM%P`!$=3RM+DQn!k#*{VrVzVD$7c26j#w^z4McwCazQWDd zn8ljHuQ26mKR{c@BzH`#4e|Gwc@pE9Sc}d*lbIg?l!*M({g2gOrHIg6UdWNt@^JZW zZ@j<y+STWB<g_%`=OQAANZ3M>Z2^eWU?lDg#pxpeZ`1IxIBNk&5_*M~`29@A4`-+? z@a8#JF`Rr>^oN*iA$<gW54!2{rpxa@Z$nJ)AQMQM9zFP(UZW?=z<p|eJ)s5w0000< KMNUMnLSTaItkApw literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/SWL_DEPT_PS.png b/apps/fo/public/images/map/layericon/SWL_DEPT_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..fede6c3040284e14135cbdfc1cc59d590c331826 GIT binary patch literal 1079 zcmaJ=TWHfz7*3gNvI{y;Wb?se>b$_(G+mpmVRf|0>I%ykZP5u6mnLUz*pd^IGn<V) z3>Bt$!xtZ%G8F`6vIj*G6a*)z58{J}GN1Itm!arH5X5>i*Xn~cBsmwp@B9Dr|KB;$ z-?yiswz-y~sD@;Zm?GnP_gh;{{#%xdG8vk1_W(|#VO)?cNX1l?g&?WRIhca7I)3OG z?4+nFTFVUJ0jZZ)knWdVjNj2s!ltOsF2|IW5r{z+<}@Qpf4cvW2AUeB_l2c^WC}2^ z^-NeWJ<*p@CPtKqN_XuBoeoa~bcki(=%a?sJ5hQ?mnU;~o1wu91dl}N-$@Nf{Xjq# z1Yv)hPYJLr;5a`U3UeIW3W5PP$OOpC`PdL2=J;ScSbb;`%~FT?l$cnJMOINdkFm)! zOrcQl7ux*D$}wyt5^*(xK_5Z*>~RCjj?b{YB?S@Milv!YLk4ga<t!S*QJQ4>`v|&O zmNo3vGLeEYj%+flKj0pz1eB!zLv_83ws8vn$@ibac4pj!ObXg)%u-0>hP`emlNT%~ zV`OCz8ZA|^KaVi7^T-53ngcucX@-gl_O2DYB=JeZ#<HQnq!^`%f?v~AzB|z-w1<Rv zC>#`6wmTGSPb7qncsLS^#N!>YaEU7-WlV<#E^*aAT%jV@wSsPv$Rf0~!%$6FNCzuN z=C#VXL@Mg7a@ESY#42(bk__WE_OC{lwupP&Y1y`9Q8qp_h}$h<>&C@z8_AWJONz0K zvzYx+EOu43Of}AUTCe2THN~6U@U}d4EAisa{de!*9zAfV`SCGndG=cN`d#m5cCg0s ztZkdV_`O*C;N7sa@aD|c>b*6usvh;;`*CU=n9Ie#-DaMo9yG_kJe8}s`Wbq1vi|ku zy3wDFr>{0$I{T99&s>?_%`NP|dXOCwz4PLcIxsiAW7}6ewKRxl&NU1@+J5|F@8E?S hvzxA;-<<SNo@(m()056ZOM2eD%E|6NaXvnD<QF%qV{iZf literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/SWL_MANH_PS.png b/apps/fo/public/images/map/layericon/SWL_MANH_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..75217f4948e5f016fb28163d18564a16a3ccc0d9 GIT binary patch literal 1559 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nBkco*&`K2Yc zN<f!FypUS}H#V;r8ce_d)2~P@&^OdG0C@?f(AO8g(%f9Q>f(~1RD^r68eAMwS&*t9 zlv<o$T9gcoxHM&uRRvbgMX8A;`9&f5`8lvq49LhY$uG{xFHmp}HdD|D&&*57FE7>v ztM~P_^2{qPNz6-5^>ndS0-B(gnVDi`W?|%N<YeSzV&d#%Xy|I<XkudQ=HzH(ZfWA= zXld*O)9aF-T$-DjR|3<Ug3#-XQ!gkf<Q4#Jc1bPDEK5ysE6UGR0DIXg6SrF|aheC! zn}XXdK<DG|hd$6T`k;tKifEV+F!g|#@MH_*z!QFI9x$~R0h9I81sOLP7?`>}T^vIy zZY>G+^bZacvCDt+IwkY%lxaq0S2#F2yJs<Io9!w;K50XcQ2Dx!&UJTYZcx$r%d6AD zo!rB$x5YJg;g(wyx0O67eK*_YyXRyk@3<nd@AJObKDWMaIsK9eZ{DYk;pdDcW=mvC zd|UWi=2+gkh`W|QW}aH+uN|<i>%*&;kG)y6C8B4ovh9#bUt|9$Gh>UDL!ihPm6Q3V zoc>LW?<bv2s_9+yeZ7{#)a{>^-g<NWu&`>;lvc03j5f!aGB3X0_FOfx&|P?D=)nUY z-5Qm5*fK5A=P>&{Y0odqs-$0XzoX|%m0p$C)n_<vbfA#u&iuJgoF?0?y!+PKC_GMZ z_S^IhNm;ds?xkEMHdEyt&z^fQBbv*%!ZFlzZ>!hZhgPe*+;~kUsIqpYKN3nZYm45H zocd-bw?pI8zuRXV%`ss({qOmI5l;rs4>HP@Z^fo2M+W=mtbP2nyOBxYqQRTVDp$jn z^S6H588<go;=sOAqc2M~Riyv<^6(Q=tHA#P?p={#n+4oozAT(CoZ`yZwk%Q4gw5?B zL)Ri9BmdP`xgS`pf9tqTU(;^?aYI9Ko(n5$IFmeiZ37<u@Mqj*%PG;;R<_;!uh%mT zwou-EjZJq2SFh|%licqj)RwZ0#l+W<J63$Q?A~3C&x=-U@Y`dNzm0R5na>7e<9B~= zygn`9o3b!O(0bnOZABGzQalz#F)BN(pFThQ`C!xKJl#c%DgW>D38&2Edo8{G^tXda zVhxFs=br9RZGG?i`ckL;i{;$qM;lXoZT2{y`L=X>!%5p5=VPI@eVfE*zg?$4QSX%< zhYde_yXPkHw3sy-r!VLW7L~j;e8~S><DL1wcHWrRr98DE5p#PslqptMGh8b+uRZsl aMS|hfbLEJ6FTS{gifT_+KbLh*2~7ac;z^$X literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/SWL_MANH_PS_BLACK.png b/apps/fo/public/images/map/layericon/SWL_MANH_PS_BLACK.png new file mode 100644 index 0000000000000000000000000000000000000000..5d2e8a70a072ea91bf2d03334495edb47dc37f33 GIT binary patch literal 757 zcmX9)Ye<t}6#jN8ZRtu;%F?hDTZkrfp+EkZY|L4jZu&zg(rn~)(=FYUsk>ngFVjS~ zp*D&%hdOP4!W1`ikp-F{h+?3{hAU*2b2c-pM?CPJm-l&}^PJ}#ZDs~1n0AIn5JWIH zmBqt-^56tgkQoUl__#<C9w&vc%td~~gZhw}&LoIey5oQHkKive^Hw$+cv)FlRaMpS z@UYEhD=8_No}LEca5$Qqn+*noQmGsq90Vc~i2xqv>gwvAo*q08YmG*uN~IEu#ogWA za=E;`yj-i*c6D`uTv1U0T1`z&V`HP$Y6S;^ot>RPT3T8lVltT^qE@SgLLr!Nf?AzU z*VfhsCq+d?P$(`g)@U@PrKQN|1x|l|KlsqEudfFO9a~#lr>3UhUm}snWHLAu2n2<N zh4@7|aFnCbVHNn0g&B}5D=Q%=l}cf$wzjset`3?Cg#r_yT|+}dQ&SUG0k>!YW9{wj z@UPeFv7ElXJ~%O(%@&JgbaWK{pI&$!f}L_7@iO>CBqA;@IhoDoaxr#C$Jp4L@rjAI zi;JIESJ#|Qr_1G9ce}qMHa0w-O~jVhyS=@$v*Y*w-rL(p{6%>7d`S>JR-T$GAqe{P z!6CgD4Lkt2%w;jN8T<nK(Iu+S>-C238lTDOAss^+w;}azMPiaEo%Qa9V`1gyhx2Kw zv$4_c`>_QE&-zP2l;^S|Fl_!4{mR0e&v%;}^y~UMh335I-+jypp!)qw%d#0Y^?6h; zd7q*t@8`J0WF|T5iS_3s)0{skoQsGiv8C}VS2yjW(f<_lNo|CU&ARhqM1N1AVh)U) z%T%z@mltzshQm*r%^?_ed(0QnNYAOSy+er!A8Da^Yher8*&zClYvF<bZ^UVX%tfJ4 eeAMVIhC)dqa;@<N<5`YS3`ua=87xamp6WjjlWKMV literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/SWL_MANH_PS_BLUE.png b/apps/fo/public/images/map/layericon/SWL_MANH_PS_BLUE.png new file mode 100644 index 0000000000000000000000000000000000000000..e521cb84a4af361e8a499dcc02da5aa598bbc5eb GIT binary patch literal 785 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%Grd0X`wFK=Gj5Nzu8p8`eIVwEur#cJGuu|NV3OChhs3-nq4S%89tT6?ID< z1ZMUGW>1)~?|)Fv1fa60(zzuwPEXwbKOnOwAhR!`cy`g$;|X=ELi48-O*<J=zAz|v zVp{8_yh(?Hvin2wrcB)TKdNkgO7q6nbuWS3_?qSU6Awp~&CBfAUNY@;+3X8}S^Yrm zKr4VM!;5C6v~0}k-j&_Gd&1toerX*cxs!cUI};mL1FZv+g;S1)7tg9%a3d(IAE+g+ zdYNBZXK?PM%&r}MyMFm+^n?~nk1UxRSvt=<so6WJ#W%GBXb4b^UwW5+dbfWD5CNUt z8<5o(2txfq*%N|tCIU?e$(syxUTFT*u)-PPKvXmnXi-G*tmyLjF_nvAs}{#rEs3jM z8eg+4p>8G6CCN?e)7!VEcWle-+>zO}GrM<h-h_h%la3TlIaamcdiBB^wM*_au6)$A z`YF&~b#6B}fWhrm666=mAOi$yYPPnnuAZKajg6Bh@7%d-_wGG=4qdx;=l=Z%Po6w^ z`t<4Z7cX7`!J9Yl-n|EcPoF=3`SR`Cw;w-#{r>$I2>t;<>9w76fu?d6ctjR6Fz_7) zVaDV6D^h@hH$7b(Lo|Yu53t=};nmX8n(|}j!Wuro%a7Jv*`i|0sb?_X*X63pt=s3_ zZyH8Ul2%c8k)@LzA|SIScd~@e5e^XpjZV|+n%q1mPy2n?{D7G&B!#tIWm!w>&)>Ii zS7|k{1kIVF>~vUJ+3Cs?@57EvCxeP+GES`g$oNjLRe@2JKYMr0{trJ+OxQ5PVgked z)Fii{2LFN?ixPb%*abAWTHHGAWvqV5-#hBAFN4N`1Im)G76i#Xp1oR8`4pE>!UK`( zzWQBU+y=tQ?4KniW>knCI(+ymtHLLZhDJt)YxngOh3bmifu3aWboFyt=akR{03h6M Ao&W#< literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/SWL_MANH_PS_GRAY.png b/apps/fo/public/images/map/layericon/SWL_MANH_PS_GRAY.png new file mode 100644 index 0000000000000000000000000000000000000000..e19f3d8b36c0d5c05f2bd0156cde3a42819d0733 GIT binary patch literal 1054 zcmX|9dq`7p6uxS{W{M1_SrG(+mJc#5qoUBvC8e2)FwNA|d{&~SNl+mv^+)tjs1Qpb zQ6$ZUt_RM?bZ$PcZnNp;eCwuOXD(BlufBDo1NYo>&+nY`ec$=rCn3RXYsOv%K@iq~ z7yLu<W*Qy~6ZkmW`-ylNWrec+h}ypWbNJYm<QwEm5Zq^0n{lQ%+X%T7eja%qkEc{B zcXoEBrlyvcmz$fL5%=}=!8bNG3IqZKLZJ|zj=Q_NaXLLcO;Oa~;GjaGz)?#}3+)lm zWwdW=YeT-hy?u0a6n<i20v;JYpTD`ei2!h7vADCdQzDT_rBZrMPfrisE|<$Ozp1GS zWjN~Z??+2(Yb!h^V-yOyy1FJOC+T*XOora!;b9aH4GoDzB1{HJjYb0rV6M~Y(2iax zMGYh)k4n%3AF!I4nE`Z1M+fF0KQc0c7(jpk&)L~oy<QJK$N;yuw->nJhM52Yy@7!N znkotahnOVEv9U2=p$3zY2O@}}7@)|Y1$zecf0=Y8Es!pzR|G`N1To;^3NV>Qq_smP z2tzw=Q>9V?bbNdq3kP#t7IdlA>V<^`tyT-|*h2}+wg%UqpB)+;MwpwMGnsaFES86d zM?e6ZeGQhBl$?^1T3A?ER#skKSI6ZxL8q_-+(jh$U7=8o0>A+Acl@kct<lWQ%>#m> z7PU)DKYjoQKtB!kYjt&Pef_t=ut2?j1BQif{j=?D>5EJa*jQ#<;A9bmO`G8{65Xy! zz@K^`(BC)QB`m(h=C!F^P<l;`bz)wb@owtn{0momGUkZLm-CwCCUC2D3^~KC;Jdqd z#l#ewIJH-@C~c`+DWRBW8zR`YPEPNRlcZ<%m9!|o%;?;5hC_%r;dim*i$>^vGpus$ zSbd(DC`fm>!^>G&;eGb;Q9IoTI!Z7&<VTlkZF1VuJY~VvMW@;@Ba?4Wdws1)%XtuW zj<a>zs_gm1hvLUF$KKK{)#73_zbO5o->0`*PraP$y&H0OnXz(n98C)DhF|>VT6Enx zr(R!jQvSZ%s9=x(N_AxX)mPa*iKpJ=rTol)bV8V&<t2D^$LI3ljIg3uV@uCEi$lXf zB}%2#vErc6%-+cOR*H$$#eMOn_XDa3Mr<rW>>Y|oyXP%S!up87^TGbLezEy~00DNQ ACIA2c literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/SWL_MANH_PS_GREEN.png b/apps/fo/public/images/map/layericon/SWL_MANH_PS_GREEN.png new file mode 100644 index 0000000000000000000000000000000000000000..4503c13c63f182dc291aaa8184b523c09d5363ea GIT binary patch literal 791 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%Gqe0X`wFK=GhSDbcfYJD<#+{eNwEZ|bc7>mvG6X8+%izqPLHL}%)X;?@VV zLVFU!CnV4KzX3?j{J%bKZf@o2-dX?G1I0u8l453Ommlv+T~!)6C9UFQSHi;l@QJC} zo2p9>w}thmL`+GW`F}&g{M@XKRoyQaL`+FfSzcUvxIKPeZr=8~%G2F77bb-EC#9__ z4V#bxR2efXD|=&A{;r0C-HkK;t`F*ni<q1i+!>d)x-6t8A$@fj(5~27Sxq;lhV>@{ zwWKU73hIoHn3S5oqhZ>wHNiazQPVTx=H|rB%k^)L_HT&}?1%#z64VJq@xfj3!QBZ! zb3%F(LqRAB=zg#{$>9@I!Y8Ey&54+t3iL?i)byyS>CrPXV`gRnofJDOJ7Ioa;-Z42 z#f3>r3X_)>r7SB>U0DKjPv-i{+^w~_+v@Um)aUPPDBRmra<H}RNJsgx&c^FgfbML$ zGo$0toX)57fW9m3_*e!Ebgz;izhDL#AW&1YwRLs%^lWTwoIH8w&Rx5A@7Z(c+O<3P z?>~6*<jK>gPoKYd@d^muym|NTJrI2Q{Q1k5Z{NQC`0?xa@4rCs4+u)H?VJlVm9xMj zvY3H^?=T269?xHq0u;RI>Ealo5uAL0?FI|)s#U9|{Fu40hEMSFr8!@EL~J?r4Cec~ zTvfSt`@H*2!_Z06Dhe;Mbh1N4gx2Iv7STGwA!4B6ZE$@h2aom%-%pz#Fmr`GZD~<m z+S<;}a^rTDRs+kWIdhZ`D=kt!eC5e$We28}K}9zkFS2$vzSBFZz^KZfz1wMj$B`8q zKI~wbz_35HD9metf5DDLi8T}K0vcQ`uATNW*1r|+9d*~2LF2#yWyxm?f+U~MUazQp zic2Wrfyni<I-Q*SCc??=pCu(`RER1mDScs8_@vR$$jG1=p|?un@VjQ9CmB3l{an^L HB{Ts5PRDSD literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/SWL_MANH_PS_RED.png b/apps/fo/public/images/map/layericon/SWL_MANH_PS_RED.png new file mode 100644 index 0000000000000000000000000000000000000000..b8fa45f9c5741e6c97733ed15d9a80d53e171021 GIT binary patch literal 782 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%GpH0X`wFK=DZq4znE`o<v9g&&}<%vH72!-DhnLWN-EJI}sST!p-eLTwIT} z^#q_`cJ>5Y+y6N^bDf+{hlT>VKyjer*^Z9KLqb-$yHByRI~f|f(AjySt?ec+ufst> z{Wdm0L7>X{&dwXXy<a9J0lCZF+ztl@&U13w?&AYA=R$aRzqK_``vkD<vm6|NDtGz$ z?e_Ego0ZjJWi{E(uG7+TwTB1LIv@$OYnG$qji@M~;Xp0RTwQ^(lWc8w`1$?H%<QqU znr?3obRp3EW^?lvbMp>MOQ3>IE2}Omt8ObRpdr0rXZP9IKuiF-7N{L)3(##-?d@kc zILvf#06GI`3((n%TwE3dk*n(xSJ$PkuFKrqR=T?bow452bE}WfHXolIzP>yC{Pz0$ z9}EmU5)^bSIQV*0)Q#xqJ25ej;^UttBmljyCL^)~7}j1TL4LsuGC-iFW^3!}>gn0o z*f@Fe&Yin<@7}ZL(6wuK?%#j#<jIq#PoF-2@!}N_ym|BP-FqPT^!f9bFW<g>`|;z~ z@85rc;2#i_UfVerXewucM`SSr1K(i~W;~w1A_XXT)6>N<L?bx)0NV`~-czSfPyI1- zVGW<)<wa+vTw$^0)H9gx>vC1))a~o;Hw^<PNvkNl$kNH4A}_KeS6E)<2#1J)MxWtz zO<s<3XS+UceZb5$C7q4+xO!{buiv+CS7|k{Oqx6Au=63ML(Ny8cpq|L>I^E9WE9-F zk@1}#s{*4cfA(&h`x|a_Jh<>eVgked)S4=%2LFH+ixNu~*abAWTAVuVWo&)O-#hBA zFN4N`1Im(*76ggCoxE64`4pE>!UK`(zS=!JyavL_?4KniW>knCI&|m@tHLLZhDJt) Y#s0d7PA`?`1A3Cd)78&qol`;+05Lm9=Kufz literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/SWL_MANH_PS_YELLOW.png b/apps/fo/public/images/map/layericon/SWL_MANH_PS_YELLOW.png new file mode 100644 index 0000000000000000000000000000000000000000..b7de1fbfdfdb1b373ac6c53c3541dbf14a53cc43 GIT binary patch literal 782 zcmW+ydrVSc6u*>KQl^!)thOx7(aYJ~np@chgBh0Q&_Albw8v~cmg})K*B{XPfj~&h zG<#@IZI(4lq?Sq33KcHOD=?5i;oi%=m*-GZJM`Q4o%4O?obPvj=et=_T#(FM#Y7M! zS+JWY1fLq;3+94lZ%ru$$2co2;392<YkY7?sN@uJ5TsqU@NY#T<c^i>E#pJnk1G6V zLp181ot?$?HDEDR3YH%22>ZSV>@Q;hC$5*^1~~)?ecbv@jS-&~4!BN&>!f~TL)6<B zu(uFH%82&|WqCrNcLI)gkueR9$_RrJDoOLBprd^%>Vq2E_98r{A<Ykiu8+VI#q|U# zqirn&`k&lbA8@n>U0orUdUj?S8@xdnYO%qa^hhhFlhF27=tUaqW0Zx^%isxReGXZ| zpa{7-XQn4Xl7ILfX=((1U;kxa{}pWD29Q7vHh2ru-Nxe!WY@s3xL%6uWjHDa!N35G zKrJXFhVJ@@>-@(1eq%i-rz}mBwVAR$rL51WU(adVE07WR{U+$_2#$UTj&_Dzs?eX$ zVb9md__xS-Z;Uj9yb0Pq8FEdAJuv=u1Ns2|y6~K^xD;6f$jZvk=ko;uu~=MNt5S8T z)t^4~m`rwu!|8UrJs!`v*NXuNf+Q(GFcb=hqtR$AHaRsl4VVF(H>nzdHK}U%fwKs* zSQFojzSA#{K+r1Samv`Ghr8!l5|V#vwRdCppIltLWT>fMIn2vX%FcOI#4~38vgrz} z+XRZ$nHk>WTTUp~E`5EfHg)~C1!*~KX|8!=@}hx(Li)XPE>l@~?MhbW^{W$8He2;3 zQG%lJ0gJ0)vA9O}o*vE|f$&T^<Blr8AhQ!Q7#mVfsCRy$W8d{}EqQX}%TaFiA<@37 zx~7Vg@?9k&eqOJ(Fn5Px-=2dbMF_jQo0X0|7Oub>n%A*@GMAP+)67MiCCr66%MQ;E nrLU~Ju)Ig3i6mwO*&;Cm>D!;3^kS^F7=}ay{9;}kxBSvSe_-5< literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/SWL_SPEW_PS.png b/apps/fo/public/images/map/layericon/SWL_SPEW_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..d260ea3a668f2d7fba866de62fb10c4220409ca9 GIT binary patch literal 1217 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nBkco*&`K2Yc zN<f!FypUS}H#V;r8ce_d)2~P@&^OdG0C@?f(AO8g(%f9Q>f(~1RD^r68eAMwS&*t9 zlv<o$T9gcoxHM&uRRvbgMX8A;`9&f5`8lvq49LhY$uG{xFHmp}HdD|D&&*57FE7>v ztM~P_^2{qPNz6-5^>ndS0-B(gnVDkcWM*z=V&ZCSVrt}UXy|HUX=-NdXzJu@Y3^d? z=H_Aq)9aF-T$-DjR|3<Ug3xP%Q!gkf<Q4#Jc1bPDEK5ysE6UGR0DIXg6SrG{(T>Y4 z5WOk5-C~4OuRhQ*`k;tKifEV+F!g|#@MH_*z!QFI9x$~R0h6`2pt1!61EZ;@i(^Q| zt)xHy|JyUGHn7fo{OXzCg)Mh?ml-9QGA!A-f4#Wt$M^R258ssM-#>6wQTh<aCnlfI z)8*|0c?85Bv~S*D^OMVb#p2D}?}T=6C(OD$X>y@e{k1zgC6apd*5wu4cAOPFNvKfD zApKrVTPwG?(S}V1#v)>(&9RK-j6R=#`_C_wVwlw5-=Dr>O}-27k<;7XHCZa0^`CFs z?7gq@XOp8#4AV&tO@o!Im-T#TS~t(m=9SKxH4mgNGM-r=e7x`AQN7qb2Tn|yIMp@i zkfDKrgRh6UUQ9wkNohOxoBMl(eT21-F%=7W2&r_uaY;HdLqdZ^MEZcm)07wgV;W6) z{-^&<Pw+`j`LX|cLt@uPuEP_rpW)G#yX%tJ?9ejDYR1_YHH{DF-?DdeV+&{7^!fAu f*#DA@Ogsz=!)G|>&T#n)DpWjO{an^LB{Ts5>LH|o literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/SWL_SPOT_PS.png b/apps/fo/public/images/map/layericon/SWL_SPOT_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..84c7992e41cc3c681f1b6ea44d7059de78fa2a9a GIT binary patch literal 1067 zcmaJ=O-$2Z7_NeZAS8HlkQi!_D8}_?KZO;>&(`5)ERr#Wi-xZKHX3NZ+J3mPi-3s{ zNIa+qO-wW#^g=Y=NQ}{hEQ%)+Pa0!L<e**%@t_Cd{0iIf;B4A{KY5<#eZTj8zWJfS z(+zdabp$~)#G+yxkB!b(TZ8{CKMFD)nowjE4Z{@5$QB^_RhR^1OqbIj4rF!u@*3zS zh$>1;jG|HLte`-hmK_Y8)lJMMi0<C3DJv5Ikx7u&j3Bl7{3S(dYLFW7ORQvu!MGO9 zSztIfm{4*PN<gK0d&usrfCY4bWHPHy8n%!PQaic=o;%wNMeab*M3CA|YE&8`!_Wex zpZ2;Hmg7jCr#YXW=ebj)hvhsBi(lT&`2;^Ncsj`9L*ZzaniAsTKrt3x1*vg_Oo3rC znGBur($GpXTp$o|G&~+RM!4;11IbypVYikPL|`kHW+Dw5q@yS&;S>r|IMdxD=w?~g zu#08F1!J<Z$#6959H|79r2j*8y^OX|9PH)$PhmSTZ2~3^Y&c~pxN)ggCzL6KEg&Ok zB_NzERdHw>B5038lMD~@<cSf@P+`Vy-@!|g5HoBf8w!YtK?*C-nx+Z?zgP6J0gulY z4sl$>*Xix|L|8uJ3w8Ltom{xY6`?Yv0|S+~>K@lyk?UANH*sVUSlSh!4p>kpcaAJ* zm2+V$>J_<a<y^RmTm~n@IF0?Q(WNcy9%ov%Enbw34-D*f3){N-`+5jpi3c&UKau^I z+%6P)tJ-GfXG5>%=rIjQcW&Qo>3Unc)bwn6pL*j$in+GD<hfh;_50%W%;snAQ%`PT z_UD?hlDdD1XkX!9xRwu9o7$r@u5~}Lv9Opvx2nIcacxCfb2Cd_E%kjh>#MPE9}4+= zzVPMNW8D>vMz@cjJldAt7(4&<NMq>Tf%U#)>ifmRjBBfzeRyv^Sw-xxC*B-Hr>^D$ QPo3)<iwufSLSu7(0R2;3BLDyZ literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/SWL_SPOT_PS_BLACK.png b/apps/fo/public/images/map/layericon/SWL_SPOT_PS_BLACK.png new file mode 100644 index 0000000000000000000000000000000000000000..fe67f8f98d1c8ab6c1a56e28f3410e3dc08a1fb3 GIT binary patch literal 217 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G|s0G|+7AT1;$q@$x_YisN8@1K^IR#H;Z+uOU`V#QvN0VP3x!3+-1ZlnP@ zoCO|{#S9F5he4R}c>anMprEa%i(`mJ@YEhlJ_ZF27DmB;|C4zmKX$bGZ8bi6NqUmP zgc-Z9PLfOg>^<RKc1OI=f*wN)=JN{_n3-RgyYN<6G3+z{u&fVg5QC?ypUXO@geCy} C8$LJy literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/SWL_SPOT_PS_BLUE.png b/apps/fo/public/images/map/layericon/SWL_SPOT_PS_BLUE.png new file mode 100644 index 0000000000000000000000000000000000000000..691f2f45ea31e638396a6ffaac8a3873cd0a1920 GIT binary patch literal 217 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G|s0G|+7AZ-}A$iHYqa^ud5Nrxt{IJbD~)%|B4Z8@v20y3Z^$S;_|;n|He zAcwQSBeIx*f$uN~Gak=hkpdL7^>lFz(FmT}W68&$z`?>O`0sx*Z{)|0R==&rM=wcF zQkXDf_ti;qsh_<kyvy#0_gT<mXu*7bfdVu03v(CV3M+<v<{y^z0S#jCboFyt=akR{ E0Qsjw-T(jq literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/SWL_SPOT_PS_GREEN.png b/apps/fo/public/images/map/layericon/SWL_SPOT_PS_GREEN.png new file mode 100644 index 0000000000000000000000000000000000000000..d09c4bd97f3a566ac39f37a872bfd70256e15385 GIT binary patch literal 217 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G|s0G|+7ARRTqtY|@S)9Uoe+p1R_ox1hx(ld7tn!Zc302xpc<QL4~@a#q! zki%Kv5n0T@z;_sg8IR|$NC67kdb&7<XarB~vE*Y=;9y}C{P#bZH}YdgtKU}RqnD&7 zDNLBL`|2dQ)X&}%-eq^h`z+`&v|v8JK!KV0g}DoFg%!g-^AF4VfCe#my85}Sb4q9e E0Mrmek^lez literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/SWL_SPOT_PS_GREY.png b/apps/fo/public/images/map/layericon/SWL_SPOT_PS_GREY.png new file mode 100644 index 0000000000000000000000000000000000000000..32d0bf519850afb515d1d0c4e3198b74d54451e6 GIT binary patch literal 217 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G|s0G|+7AYETyKXKy3dGqG2UcGwHo;^p89=(43`o{-TdO!x01o;IsI6S+N z2IO!SctjR6Fz_7)VaDV6D^h@hww^AIAsWF`do1}F6gXHI1^@j|=8gQ=(dxI=_~<3+ zNeUBY?7lilF7>nbgm>8;@jeTB3@w<?FHm4+eqrvyTVchp&-}x(KA=Gip00i_>zopr E07Dc;WdHyG literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/SWL_SPOT_PS_RED.png b/apps/fo/public/images/map/layericon/SWL_SPOT_PS_RED.png new file mode 100644 index 0000000000000000000000000000000000000000..a2da36f9bd0c68654350c5ed8840a5a513e05c5b GIT binary patch literal 217 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G|s0G|+7AT7?tWho)yuc(-&t=(#2G2PyNyRWbE`itTq14@GYf*Bm1-ADs+ zI14-?iy0XB4ude`@%$AjKtWqi7sn8d;Hf>9d<+U4ER2Hx{wMQBe(Y%V+iHCDlJq2n z2{U$Iog|m~*?Ypf?2dS!1wDoq%;y&<Ff+d}cj2wDV%TT?VOby0AO=rYKbLh*2~7YF C0z6j$ literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/SWL_VENT_PS.png b/apps/fo/public/images/map/layericon/SWL_VENT_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..834eeec21c796bad217bdf5a76fe05d9dd069a31 GIT binary patch literal 1033 zcmaJ=O=#0#7>@fxHa7-4%z4m{Oi^LYPn%|KSU0+4KLt~^wz7f<OOvl_Xp=7{-)uGz zrUymvpf^2wks&C0RhTeg;7P=Tb9fLD1U(G#D%3As+j+2tB;OCu^Ssadz3+E>AwAdM zd!m=3sQ%Qvk|E<@@Ez?T|5Lwe8W~3LOde-Z5mz-AQb_|9AV^u-3d}&wSiABDPEb@Q zZRYYguU?RJWHDNRVSLLWY>Jwg@*PbtLktRV#k3Rj{>xW1FpUJg6jeFZkzvW4Uw2`4 zJ)P6n%X-|PrzXLKFA)I?Vh#9K#r7mWLDzL9G7q*{8q^`UoS+X(<<$isBNu`w6A9@Y z&jV3pcp)l^{1^yxe3<3PD~5PMii%Qr95f!9M01Uzlu>3IvB)YxmoRoDmaSH+Of|wF zcZKES@pzyS4u=RL<gM9Q^Fy{b+Eh@Wr@N+uO=N>WQ7fQToS=!*gA^>MC2M<)V<HE} z`kKS?3>T!-1gh%)p_bJ`dpH9R{r*$f%dI((%|H*Wx;iObaWn|!NU{qxjNBYTmF6if zln_Q<2{}N{is0OmX&b2Oov-6nRZ7_&)@&W7lmtx_7}GQ)IVlT*m>d@bd79^EgjhVn z%h4DwipiJ~my=Ddg7j4j+PKLz4!N<m+@KXKheTGOYhH!MtcxsAPgyeCdx^HyYjBPB zUc|OsmY89K!v0n0<`(ImVA^V1vS>9vv`M$Sq^<957f+HaaV@1JbN*i8cda(nd1j;g z!TT*^Wbx6(9fjZCy~7P}2$w$Y4#FSLN9R7@<Q|soC;MGG-WVIm^m(D77j$O#c+cI= zg=3rc*xAh^m;3uBySZ;)BKHgIv*kVue^?%R{k@~|?$+Cmy`2ue^7u5I{rYKsu}BY7 ZUB{{Gwe;4{>_A|IO3kE|r_;+f{s2UANB{r; literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/TL_SPBD_ENTRC.png b/apps/fo/public/images/map/layericon/TL_SPBD_ENTRC.png new file mode 100644 index 0000000000000000000000000000000000000000..8e7de8593acb28bd70cc17bc07f51fe41104a3d4 GIT binary patch literal 1260 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nBkco*&`K2Yc zN<f!FypUS}H#V;r8ce_d)2~P@&^OdG0C@?f(AO8g(%f9Q>f(~1RD^r68eAMwS&*t9 zlv<o$T9gcoxHM&uRRvbgMX8A;`9&f5`8lvq49LhY$uG{xFHmp}HdD|D&&*57FE7>v ztM~P_^2{qPNz6-5^>ndS0-B(gnVDi`Vrt-GY+`0%VrpV;Xy|I<XyIz<XldzU>1JVR zVPR<m)9aF-T$-DjR|3<Ug3xP;Q!gkf<Q4#Jc1bPDEK5ysE6UGR0DIXg6SrH;aGD3z zn}XXd<~a5010ACeiddwGh6w>v4~Pj*wm=R%;iu*SQ+p9GSzA2OwPs*oOz?DZ45_#^ zCD_*ch=V}w?%4$eVnq+wJEkUNK9=9Gb@S%yr~J6<dwUZU&8{s<NLP-Ch=`VLQtD7z zeo}S!xihNOo@d(iauU+h?(Z@Gy=YEx#N8VuUfCJR3o5i*YhEf$F@DadYASNz@6S#V z);|xQT)W4p(`fi0UF7kzHxlp9`_G7tIdtyd!Y53tyw@B(`gCf(0z=QPZF?G2wicA^ ztCd-_E9@Eji&n;}km|ehXBvsHiJZ|l*L{~~l-U<CMdHb<Q0|6nUvK8Hu^r=(jEFw( z{AjY!%-~3-i^*N9mIf<tj%iw!yXD_@mh%TnO3p1kn)$1m?d{{!C71gqiD>S1xR`N| zJvQ5C?o3u`PthfQ5-al93`?KC+#KK4)4bnrwtm;#UOhuS$xiNBH3#lG?~)07@@xLf z#2-q(E=e`?ujg1?p%eG;x!<Dv`N2JV_U(PWXYOXk-g|Ku<<IyAY8CIYww-jKpMja- Xi(sQw>ZZrDK;@68tDnm{r-UW|S17>0 literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/TL_SPGF_LOC.png b/apps/fo/public/images/map/layericon/TL_SPGF_LOC.png new file mode 100644 index 0000000000000000000000000000000000000000..74b0adac361882af61b2f8d1a29c7a3f4c8063ad GIT binary patch literal 1383 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nBkco*&`K2Yc zN<f!FypUS}H#V;r8ce_d)2~P@&^OdG0C@?f(AO8g(%f9Q>f(~1RD^r68eAMwS&*t9 zlv<o$T9gcoxHM&uRRvbgMX8A;`9&f5`8lvq49LhY$uG{xFHmp}HdD|D&&*57FE7>v ztM~P_^2{qPNz6-5^>ndS0-B(gnVDi`Y~<|b;_T>bVrt}UXy|HU;p}W+;cDb!Vq)a# zW@79F)9aF-T$-DjR|3<Ug3#-NQ!gkf<Q4#Jc1bPDEK5ysE6UGR0DIXg6SrF&aheC! zn}XXdPB``I10ACeiddwGh6w>v4~Pj*wm=R%;iu*SQ+p9GS-(v#`NF`!c-zy(F{I+w zlF6sNr2|Edoj-f#$;Ca(9JefR6p#;PcHZT2l>INWj@BaXi5gdYx8E%dytG!^wII^9 z;Q6Ai0P%Mr0$G}wZ`C-QF0}G!?F%r@RGVL(=OMwJEN)q_<Bs+BKj)5{KR03s@jdbF z?9<&EF>&H28UHD=1T`s$be@TJYmI(%^28qHs(l4VPW8$&Ht~udsoCUlg3EBf%aQk< za+8_=3w>f;RDC(J(RRk{aIKoHR-!w579Do=_EN3?e(=nfB(<w4FP)3_i0wSh(j&}! za-zYN1>E-2ls8<rWm*y*$LXMWySsJgG@+C=ZVWw#%~aZ%0+`Q8Cd}3M+s@?>_x|9s z?Gjfu@T|SeZF`sJvA?p~y<c+}=ifK)S|_}CD^o&Dd2;^oCXWlZY%i2AK2g8Em@PuC zW^R7F)T7wsx);YeA2!bGbbS56DLZ)Hw*@(m&i7hOe=Gj!`!?%V_Nra1x4ge!mh<7e z7V2YTThZHCcab+fZSkQa|Em_TrS9=;Dcp8H^y7oe$A4YAFTuxoV85Kf@8}agt{aMj zmT31oO_rDPs8#$JsCVJlEz8`saTgu#_}2b;qxZVoecGn|M-JR%Ow(%kq;c7J-zSyT xlMfy@PZug$8aOS;e5#drsN|Yk&;KYKU|^SOJidr&wHT=A^K|udS?83{1OV%G`K15= literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/TL_SPOT_NOIN.png b/apps/fo/public/images/map/layericon/TL_SPOT_NOIN.png new file mode 100644 index 0000000000000000000000000000000000000000..4800beaeb5d42b54c5c28451bcecc023bbbf7506 GIT binary patch literal 1009 zcmaJ=PiWIn9L_czGB(&{iUakLU7W1>*EU-oi*rrdt!T>V>egLkY4Wy)EqO6{v)NAK zVJLX;ASi<1P4OTeM3EutO)p+NO+>wU5k)<C5$8+Sb{?!D$@|0ieZSxP{l0g3rZCml zGuXp0OkaLlFVe9;{`Pm%|Ir^iCLIouY?;jBB~mj3#7x?_f<WFimr)U!_WHS3Xq;iX zSf^AbW#crou*;b-hKpREvKeN4BJxdZ1rbm|%Z{hAU$>sIz_C?!K5Ynwuc4|ly%C_< zjY7%VSg{nFoj3u;BS-~YL`)F5t6m5rm96VSI*+$`7SthRMP+xBDjPFE!vO+mE}5_d zQ3SHgiK(<Kiz7f1M2Q#ZD<{MhOv_Lj1&xQL(E@u37WG^s7G0@ql@K5De63dFYDo?U z%e<&4N~|GC35rOB>mD(qgclAq6?7C@f#VYgdmvUcD|n5lEX{QH2(I6f^}<G(Xu<f% z^m&mJ;v+SIhVg%>>$cD#DWbi6|0x`n)_uemQHa+9i#Bd)C=TUAEkGv0K?&p4W))|u znBcIAeW1<C;Mlz5*|-)C*YSn{^Ik|y&q8@!WvK$^I5t#9vr<-*X{n`*C}vZWiae$$ z$y`RxjtP>KX>xUJt+~h}O|HGimD+M+E4V(5tfRm=kL+B4T~I$VblT>U&b8HRaP9WF z2yMAMO@@yf`&XlzThu-Av}IemXc-@Q)a?Pa_2WyMkX{K|y~$Gaw(@IdXQE3Il1Xjg zWapj2t%`oodU5Z;_tfT%g{|Q^ZNc9@@Z@;s>$685bzYa=b$@)LU+d^Kra!}=_pSv# z?0flp>cUpJZ?ST_|H_~+();}8)i3X#o_g59baXS{J`Ef`^K))HzJ&Q~LBF3_y!Zzu Cr9T`1 literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/TL_SPRD_BANO.png b/apps/fo/public/images/map/layericon/TL_SPRD_BANO.png new file mode 100644 index 0000000000000000000000000000000000000000..8d08dca2996d0ea7bc0c52c6296323f9721077a4 GIT binary patch literal 1044 zcmaJ=PiWIn9F8j+b2uD$*;MqAq0G7FU)yXAtJ~VFu42pRit9nJY4WyaTk>M^X45gD z4h9Y;c<?gu;Ms$J5Cj>b2r@l+n;-~+c#<OONf^$TuB{%dA<6s0_kF+L`~AMRHkmrx z*>SjoqNvWqgq$X0m-n@|k^k`@y9yb4@OTzap&49MY)Fl1C=WrxP-bBoDq89C8#qi+ zK3dOYaW;8gQjx(Z9)@uZi?Atbc*M07bsl1nhqJmFp}%fEr-80T=;=_BOIk5l&?lB` zIJK0@s7v!|SffYIfMHi60tUniaE%4ik=zJf)s@KH+h%D{h2Z%Jy_ZxrISFFOh9JZQ z{3^%uKol817!pN(00<l}upD_sKOdArq9hE0+C!6Qwl*WB<#;U?Sw-jq#+Jmg#bS{u z1{h?|vV1rk_A~^+PY`~mWMakjn@(?CL57ZM>lW6L2|Pt5j}~!+CYkOX!LS;#rc)~u zDH!W27Rxi7cceNnnfyQ0FdAqFr{SM`|0(QbN)}|(&_Ro~N*XuQ>xHtUm<<(-><mH+ z^(syl5JpY`Ss*qgg1%|p)KJkmRmCThQo?kwVyZA9M`)tJ=(;Aw#IPLWhT_4HFvj!a z!KlDRhXTQPm<#Z{7?kT=8L5i~G;y7)HMn7}Dc7@tVUfr(wDl`ci`&Qm)gw!K^IYVn zdNr=rG?$_Ard*aJ!+MSVtI_o>;vR3>uq|0Mj1NuXcAMDxacX&)T#4%mc`W0;&+qK+ zj`-T;c>LF;V^3DDb$31OUr~O3|GW;wL%!8=>xQ~*p1XAt!lP~F(OeG1AUtv5Mx|0Y z@a5futxAiws+IP&^@r{~-250nqWDHr7vGjo4{U!L9PJ6?*WX@#*etHCx5AxA<%4&( oT3+qfySraR`)*DM<vW<_%2B!7^wnn@b93H3O^m1H`_bIWZ&{2_H2?qr literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/TL_SPRD_CRSRD.png b/apps/fo/public/images/map/layericon/TL_SPRD_CRSRD.png new file mode 100644 index 0000000000000000000000000000000000000000..57b5f2ca51d03eb08728f311091e33ba37747c4f GIT binary patch literal 1083 zcmaJ=T}TvB7#$Kz{443Dg6K98CA2#;yX)vqZlXK8?nWcFyP!dV<IGiub>>bp*LIYk zh<*rs2`mW0iU@<qtbE8yG^C;^G3ZI7q<ZKfh{y*cqVA}xJ+uuobALGJeBb@PbI&$5 z)Rz=)Dx@f?BpwqJWL)Qd1*^$_%lF?h88+fbGftv5oRKX^)vBl!g19cX!vvJo?!(Vv zHAUsoTB;d0OZx-`>0a5zcpcp&Y>KL`aZFiBLkwDByJm#wuMfv)ps69csX}5UGYmVl zSdRshJq;<PC#?ikx@Hfkb_61zLo5SF?=)<|3DFC>0-3wp3=I|_I31!FlWLY4K^R#O zRCxU!h2=QF^Ik4c!SmcM;A1%-!;+WxZ~>u$7krgq>7hw9OKlSpVst4MS%v5hj7@=I zGMS7w<M$$~o#BGPpsV5Yc?iN|cN<uCJchk3s~|#Ku{0BF$N;XQ+={wzh$fjX9zi#k zWet0&Or&6pBbyB8W!)oXfs*upsID)gZJdBB`TkSbPIa4*NkAKQSqf=f+cr0pDTFO3 zV`QZe>daQLu>)abcOVmllRVhjq!}v8*yRg&NfP3Qjb%fDaWO;_1+S*50vq-P{FPN= zAP}zQxJV!v;H#?GfUhnb^>ds*nB|H{>C&Nrvs`tB8_CIat)QDEvIs5h2vnmM(!s)! z1ub_jbvgBxxN7cP!a2DNNrrJ7`&Xm0Tf{x?blJ9Kv21*35Vu>z)(>9$zL6_&J1*9y zoar~onUV=mJbd%$z2fu~Y$<&TipFc!4;2^PABhd`+`e~uZeYiOyRUwHIs?kC-a3%p zesbtE7p<-S@Yuj*1NoQi%SA8k`9o{o{gnIfT+tKhUvuXZsr2>4i&)=4|J%G%qhrsM zgV*xQpG@rU9m$+yKTf{ypV}~yoV*y_{kfisK8hTldOR~xcY*hxZ0tQX8kN!<`(?J^ lhPG<1=9s*;mmi$nI!?vb^=)?A=1bk{9FH`JgLN$@{s3DZXz>65 literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/TL_SPRD_NONM.png b/apps/fo/public/images/map/layericon/TL_SPRD_NONM.png new file mode 100644 index 0000000000000000000000000000000000000000..e68c05ab606783899526d999e99e088f96d1fa5e GIT binary patch literal 1049 zcmaJ=&rj1}7%o{D1R>Fr;)O5e0@1Z=*A~_=eyy7<amzAhn4aj`Z(9THSK4oGEJTz< zjXy}>X5z(gFvb}F0F{V|2Ti<r(klnigpkNV4<z_?u;IbkwEceMd7k(A-uM0PrBj!B zy3Th|6xEZMQZi&b?R}ko^6%R}RLRhbV>vvH3b>*=kebj@9)g6a7GVae`r^VzI6_fA z+Q{Z`E_qqjkjbbXhN+r1VN=w|Sk+dwIfy|X77Z&x@4bFY14EC{Gh#BBw4<<OOw}AX zT}x%P+ME{F>9J8TQk98-39$;Q=Dg*~)d*eJmC4-OW@%7|;JFBWWGa_TgD7$!5SdUw z3vwKgB!&}2N#ZU7KFINGki1fW6J$}6`5|!p&?K6p7vzi*KaNFK5xRu2EwgN;Qei3~ z202BR3x~s=2G0iwBH%7sSgi&ux4)sFKv#1N8ym<1o}!vZWgMZ2)1xDpc2m}JkJCgF z##U9E<(Qy%qy{jV{6Ew*n`jqj;ECUV3cJ}w8?qVbqOzlr!WH_xP_`U(po)=`MQFZ} z#dHZ_<d%>PqSF!>m@zCJRouZkKADsgmWx$Og9#-<69vXFbeWq}h9y205=36&xR?;; zL*j5q9Fk&TNg9rZ8e9cwWfNMs!PQT=LQAgK3Z_jWE6_2nLp|;w6V#6^8?C*NvbXYb z#MN7S;ahT9Vutk!`&XeGTcmruX|rv~qS^S+BHiwgwqAJN`<+~g)r2yUt$xiP93GDO zq^<XR514nq_qGe&<%c`|En(w=|Gp-6TGXp}>ULtlzqGv8aphab)BS@{E|puN^3+s_ zS>2(&JX!7=;&}e&EdkNb&ODv~(MRV7+QHeiQ{%O(v;Ot%b~~5;;d|l#wEJu2^N0D3 q9x&K__lB^tIlk_*VKLt}ezT3bGx}!tT6|ORE^8u|QeIBZuKWSyOihgd literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/TL_SPRD_RENM.png b/apps/fo/public/images/map/layericon/TL_SPRD_RENM.png new file mode 100644 index 0000000000000000000000000000000000000000..4800beaeb5d42b54c5c28451bcecc023bbbf7506 GIT binary patch literal 1009 zcmaJ=PiWIn9L_czGB(&{iUakLU7W1>*EU-oi*rrdt!T>V>egLkY4Wy)EqO6{v)NAK zVJLX;ASi<1P4OTeM3EutO)p+NO+>wU5k)<C5$8+Sb{?!D$@|0ieZSxP{l0g3rZCml zGuXp0OkaLlFVe9;{`Pm%|Ir^iCLIouY?;jBB~mj3#7x?_f<WFimr)U!_WHS3Xq;iX zSf^AbW#crou*;b-hKpREvKeN4BJxdZ1rbm|%Z{hAU$>sIz_C?!K5Ynwuc4|ly%C_< zjY7%VSg{nFoj3u;BS-~YL`)F5t6m5rm96VSI*+$`7SthRMP+xBDjPFE!vO+mE}5_d zQ3SHgiK(<Kiz7f1M2Q#ZD<{MhOv_Lj1&xQL(E@u37WG^s7G0@ql@K5De63dFYDo?U z%e<&4N~|GC35rOB>mD(qgclAq6?7C@f#VYgdmvUcD|n5lEX{QH2(I6f^}<G(Xu<f% z^m&mJ;v+SIhVg%>>$cD#DWbi6|0x`n)_uemQHa+9i#Bd)C=TUAEkGv0K?&p4W))|u znBcIAeW1<C;Mlz5*|-)C*YSn{^Ik|y&q8@!WvK$^I5t#9vr<-*X{n`*C}vZWiae$$ z$y`RxjtP>KX>xUJt+~h}O|HGimD+M+E4V(5tfRm=kL+B4T~I$VblT>U&b8HRaP9WF z2yMAMO@@yf`&XlzThu-Av}IemXc-@Q)a?Pa_2WyMkX{K|y~$Gaw(@IdXQE3Il1Xjg zWapj2t%`oodU5Z;_tfT%g{|Q^ZNc9@@Z@;s>$685bzYa=b$@)LU+d^Kra!}=_pSv# z?0flp>cUpJZ?ST_|H_~+();}8)i3X#o_g59baXS{J`Ef`^K))HzJ&Q~LBF3_y!Zzu Cr9T`1 literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/TL_SPRD_RWNM.png b/apps/fo/public/images/map/layericon/TL_SPRD_RWNM.png new file mode 100644 index 0000000000000000000000000000000000000000..e68c05ab606783899526d999e99e088f96d1fa5e GIT binary patch literal 1049 zcmaJ=&rj1}7%o{D1R>Fr;)O5e0@1Z=*A~_=eyy7<amzAhn4aj`Z(9THSK4oGEJTz< zjXy}>X5z(gFvb}F0F{V|2Ti<r(klnigpkNV4<z_?u;IbkwEceMd7k(A-uM0PrBj!B zy3Th|6xEZMQZi&b?R}ko^6%R}RLRhbV>vvH3b>*=kebj@9)g6a7GVae`r^VzI6_fA z+Q{Z`E_qqjkjbbXhN+r1VN=w|Sk+dwIfy|X77Z&x@4bFY14EC{Gh#BBw4<<OOw}AX zT}x%P+ME{F>9J8TQk98-39$;Q=Dg*~)d*eJmC4-OW@%7|;JFBWWGa_TgD7$!5SdUw z3vwKgB!&}2N#ZU7KFINGki1fW6J$}6`5|!p&?K6p7vzi*KaNFK5xRu2EwgN;Qei3~ z202BR3x~s=2G0iwBH%7sSgi&ux4)sFKv#1N8ym<1o}!vZWgMZ2)1xDpc2m}JkJCgF z##U9E<(Qy%qy{jV{6Ew*n`jqj;ECUV3cJ}w8?qVbqOzlr!WH_xP_`U(po)=`MQFZ} z#dHZ_<d%>PqSF!>m@zCJRouZkKADsgmWx$Og9#-<69vXFbeWq}h9y205=36&xR?;; zL*j5q9Fk&TNg9rZ8e9cwWfNMs!PQT=LQAgK3Z_jWE6_2nLp|;w6V#6^8?C*NvbXYb z#MN7S;ahT9Vutk!`&XeGTcmruX|rv~qS^S+BHiwgwqAJN`<+~g)r2yUt$xiP93GDO zq^<XR514nq_qGe&<%c`|En(w=|Gp-6TGXp}>ULtlzqGv8aphab)BS@{E|puN^3+s_ zS>2(&JX!7=;&}e&EdkNb&ODv~(MRV7+QHeiQ{%O(v;Ot%b~~5;;d|l#wEJu2^N0D3 q9x&K__lB^tIlk_*VKLt}ezT3bGx}!tT6|ORE^8u|QeIBZuKWSyOihgd literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/UFL_BMAN_PS.png b/apps/fo/public/images/map/layericon/UFL_BMAN_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..f2f64a641080ceee0479ecc735869a2d146d2513 GIT binary patch literal 1552 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nBkco*&`K2Yc zN<f!FypUS}H#V;r8ce_d)2~P@&^OdG0C@?f(AO8g(%f9Q>f(~1RD^r68eAMwS&*t9 zlv<o$T9gcoxHM&uRRvbgMX8A;`9&f5`8lvq49LhY$uG{xFHmp}HdD|D&&*57FE7>v ztM~P_^2{qPNz6-5^>ndS0-B(gnVDi`U~b~(=3?e-V&V)8bypKdCpQZhM*~xHL!gkQ zs~JqMOMY@`Zfaf$Om7N8uM1ASprnvn0JPa9wJ5VJHN~wcKUV?lWvfiwZgIqE9#n4% zZnrq$)T<A4j6Nu0ks=x<1WY|3COp{!Iq-y^ng>knMZjcjY$NByz`)ev>EaktaVsa- zJ6kwV!nRzla-zv(6WwjgwuYFqF7;R`7OvFs-{DB>gH<~Mj<ntmdcj|y-sD{v7`s!y zOx45jWxhak*5s2alh4dOcjj!xy9-l7svn-&Yy5fc`^t3@u{*o#ua!PBESx_>ndRf` z8>)5!_Q!hHZrtpfBeZ@_l<j*9Q=WF`C&jKO3}*1L{qwz^YybRz`H^g;3o4&Ky*bqJ zr*P4$HRsRjN1S~oD$&+CS(x+owgq!T)wAxX^J+d_YteTt<NwSKcfM^ITk0~Gb(+W? z`Wz*}Vs~CsNHqDv_lMuBHN?CNvUq>gl^c3alKiw!qDJTCl(e+cotnRx`<JjR%QWJa z-Zu4o$E}a^A3Gn}c;w2LHGIFO>{wg<VTqk(s#IH}g2aRw>L(9<TmJpI)$W}i+3tVe zxA3Z+)6N+8jUhrt9B~=!{AyZ!hYZflO5<o2)J|XWQPfq?J!!%7t%)~x<wjiPn^ktM zEr`pf*>y>Vk6&s_@7d|kjXWkvY@3-Zsea-q_pjo!R&$M&xmSp+iFZ8p;1CbbH`P92 zo~r^Yh0?7oc${x)h<SNDQYgM|Ww*<Kc?p}3cgj*Nv#G0B%f2bGo-2K|lD%$~LWWA} z|NSp!M(E5=)ew>JX$z{qB|hbo5x@QV*jS;TNsM#Lx+ey4d~5DZlhm9f;x6qf#Huy< z=z-Gyg>A3qT{~#^@!Nw3;zenUOM@&gH|DK+CcW~+tY!DLr&{Hht-t<0Yg5>x>l1~_ zAFD*Y{&uU|@9IN|(-(GKP;vCk4$RbCt<rcsQ+dikIZOV|f+q^sZe9D7vwLl-pUaIh zzB?}%W-eZLT`{KCep}}6jt?e*F$Htq3!Lu|T~uh5_I*o8t#J9V-v3+%4DT<CPmb93 R={%^6_H^}gS?83{1OP?;O1c05 literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/UFL_BOPC_PS.png b/apps/fo/public/images/map/layericon/UFL_BOPC_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..0f8e99f450f0251ed7d479bad07dcdad72226753 GIT binary patch literal 1132 zcmaJ=TSyd97#>})+X_VyrBK7@LqWSUvzOU+aNBgp&6P&Bbs=8@=W<pDn>pjmv0Z%; zBZ?jh%K{-Rqn@M7Lt#WkP$WTxLC{N^6j@;wMFpC6MqTZpZJ3#J;rqV-KmY%o<H@Ey z<*O@J69iG7Xb@6(T<d%*%kY2ew>b$9n^AoWYK9q<l`KHis!#@GLYLY=3P@^q=VMSq z5H3nfx1bhrFRwt|D>)c%PB$@|AZnsHQ&KtrB4yB~84+sg_Fan9)CjddC^DiM1MONv zj|G~0n$k*7hZ0t)=q|D*$72B<Ac@TB2MwFgMW}gQ9?zX^nj+^Rs3SrxB-J7&$r!W% z8T9%+3d6D_$9dU6kmJ}Lq>o{JG=pEx!v^>u$NNI$;zQwRmYU&HLVPh6UPY*OgiM~M zv)QaS>-R#djb_8)u%qGgc`(9bcN<8`c?`R%pdbKSu{0BD&>$T}Nrqi0Lg7poj-Z=M zvWC4_CR{K&Cz&+sWt<}wfTH++sID)eZIlAb`TkSbPIsGtP5~QsSqg4krpgIr@-YiY z2wG_f4;HGJY=;Qi?a(A+%^bOHzh<Z~Yj2;&iz1&eY$O>9NC*)MD|j_c<wJgsVM5_R zAm|UXY<-|MROhRYhjzw7@w!@ujTg8ARJwFvpaNH2<_3#$9V_T2jw}F6I|S6Y1$A=% z$h=lO7hh4mMXp*r7k^PMjgz6B#{Sjl!WMRqGhMPRUMv|O7})I=wzX%p?j^nw`GioL z&b^Xn=H{X<_lAudXJ5W}CikD+M|5tE+&S=dRDV5ku5Vq2Xee=2OiWF+RaZYcykq6{ z`}d!pfAe|r*u=-q(TkhR-w%V#(Gr!;pRVjGaaC8Gy0j`Y_Wi?H=SXSd<f&`J!};Fb zyNSV@(u1;F^57<S>wxQcUwM9fTsCdnwWhJL(U*5Uy%1e7cKgtz{OiYLWwrb5yAAhB zFBAP+l7m;tHT|xn+&45d)Hg7&{z(P^kZ*locB6M@X7tPSPsmJ9|D1A1duNY)lH}pF htwPmy;!IUZshi-wpAg^66XVYPPt-RFSL#|1{{cK~fpGu; literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/UFL_BPIP_PS.png b/apps/fo/public/images/map/layericon/UFL_BPIP_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..dcc3622a76eeccb7c555f8fd9f30f76ce8591f08 GIT binary patch literal 1017 zcmaJ=U2D@&7|tBbF*i^Ybl!N#5EN{_+N3nBt6j6Xf+?dbtRjA-$ypoL<izCErn?Z) z3zdO?zzc7^5@8o2GIR_EyK-0r^~UYaJB6Vz*{mmB+j(IPNzMn)^StkQ-{(A<&RiNA zI6Xj7)KGd#$&&GC@b&kR|C#NEMuuTLk;gM=4p%i7Qb_|9AV^zU5oV!g)NZZAQHtuN z&0HSm)yuMuEJh13jBh!FO;Mu>-_i7Wh(Q4sO*>A1d;Nw6rV*!SMU_*X6fBuj3oe{l z$mH~ec|B&(i7_zh%S6C}SOdOQwmsR8(@kBO%!6%~22BW_kJI}}<<)7BLM{X%6AtMd z&jU$f_=qS;`~@Izyufngl|p<(7A0ATg4RQmXs$6QXO+oTEV7EzC5#=JWvkUHQw=l7 zEwX$p77H{4Aw&=%uV!P-582*GTS0-I?wSrZkqrVxt$->xPLoXck6<|+S=(!si4=_W zHHYOHE;v#fsH*>mT2=?`;VeAJ_n*REuI4~C3q4eEb<()Gksy>Kr(CFE<mM16x2rf^ zLKt}^<bc$S1kTNxwt=eN`6gaf<+SZ#&DLRBiPJ=ZF-=2`hEvILF)|(zBLdG)L}Dp1 zniP476Ozd&FGky31?d$F+PKX%4!EhV+`tN!Ln15CHE%;>(nS_%9$7ZK=Mw9x*Ww!8 zb4hmPvLqQcXzX8&Zf_Cy1k;Xf$)aO?XcM=)#MbYA(#Oe_u+mC0=YKBjHX4cE!52$Q zjp+NAaN|R`uu-q~EH2l!A8&nHDh{$w6VU(h>+I^Q#RtQ8e($dL*H<5w?=COzHEw*l zvQoZ2*2C@X)DQO=Z`XF7Y;CUG|2TB2vhwW6<h6^vCpQm$WvG6RI<|J=`)<a$8eGQo LL`Hc&e)HZRuXRo@ literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/UFL_BPOL_PS.png b/apps/fo/public/images/map/layericon/UFL_BPOL_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..4f1102989f57aa44d1e1bf3f632d278dbebe9924 GIT binary patch literal 1193 zcmaJ>ZD<o`9KTp_ZArmFVO4y2xNhJixwj^#ITK^NOWLp{#5CBzRJ`0hZH{^`-d(+G zKWyEQy*eggvf;)y1O-849|y|XRYo0!`9YAfRZ3-S6C4ZJic0J4x!TlySa#gq^TO}< z`~UyX|Htz|A>Z54zNH<*u#Rk>P(<S<|7+cd{yQFcA{sW^>9XCg5894sLM$cg6$rAb zI0TDOlt)ke1mhUif-9x6UCzDENxDjiK8A2r1F<nIo^%aS8iqEgz#&CT;D2A8z=0ws z@PTNK${9SYDt%)n>>taQq_JTsCgaI{AntNVK!vslT=lqSac%-%)#cFK-zIUe3bBV1 z__L(SxdPyI6M`tw6P75N1}sa^ktoa3A;3^HLsIBv!*qm;vK+G;tUWl2X3B$HQOK;t zLaPK`wQYkVNyl*rr-#tZA(D>8V!j5$gb^ZajcT^&hBd3Zp&&p@G8MyCbPf25VnrXZ z6FAEBSqZAKE~{B<$Ak`ybVY-t3Cb_20nFw8AF8VBXv;3b=lTApuvHp0AX$W#K4MC! zaf97{D1+loDB8MN()HtwQ!G?<TeqsZ0r-9v>>N-uS$C{gSMj+Vm(?s=)FhY{5;#&I z6h-FJDL$3qX+9E-Ff^Tx>|yzgAjBAoN-+YxXLo}u=+cM^HM_x;pL2z#T;B?+fg%gg zR8B%UW9lkcEtylA=aOowx5ky5=W?Jamqf{seq;aD=*AXuk3U_vEn2J_A8N?$CbIRf z`Q9ZA3v9~@sgnCk<&ozlTUtN5k@a4v1liM{eB3b=3eE<)H+e6e{VZ^+u<y|1DSp{| za&~W_dOql`)Z0G%ZQ;)J=GH*wOmaW==i%?dHGEg_=KS0bm)fc?&b<~YFaHd7Igh>j z-%G({`6v}1ot`Yz7H-tvOSfOVmn6u^4X4HVcb(wG?3+EGXOD>P^5V9>o|f9+r`V6b zZ*V*FcNX7XSbAgom*);19`77KmIf_PpDxeTA3oUIdE&gZ@W<B^!GVVk6FPWpW}LiO z{`M5LGt<@Otqi??^6^Z4Y3q*bVrWa-D=%*>FHTj9{rL6yx4f>>1uxL?sQ0S?_~Jr( z{G3OfQ7|fa=r8YPePud+x5hC0^S5VfB!jh5*vQm3mCMO1bN=O#P3MIx2adh-4>{eP A^#A|> literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/UFL_BTRS_PS.png b/apps/fo/public/images/map/layericon/UFL_BTRS_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..557c17089a8e791685cbd7fed39d5418549c6531 GIT binary patch literal 1097 zcmaJ=O-K}B7#=mH{OONMvxCD(v4uOcv+j=0u<PHB=2oM!Zn%dKXJ<a$L1(^k=F?q; z&<cZopbkZLh#<OjNQycHW|9{RNy1Zj5HC?kAXLX<`$k>u&^FA>_rvo%@B6*)^Ihv` zJ6%#(UPur`Nw`&v;Bmk6?JmIoiXUki4@XgR40Xa@l$0$%G^#KT$gnQ=fe4V*k-_&M zKoEJ97LB2pbWTv9PRkC4PU$9Q6GWgsWy(rFKx7>BX-1G*pPr>iO$}0Ae#s-5A&}5o zM=j7f+7?wt`xRcL>g&irO27g-Kr)%q2Mk+C1*r{P0neRnh9Wm0s6R+;CKZ!9$Plyu z>8GpRiic%Mj-y$hpX1mn((7Tpj0eA*oAn8PPVm-{TMvb!S!%Bk5nHxm;Z=}IAY=** zlT0S*WHk+~K8EFa-qG-S-5BAvM+_vV+=gA5Q4oQxSel76XpoMg9EU?FNa0L3kD!~| zvWC4?CR{KkC7TROdz>R>fRglosIG6LZ4?1J`TkSbj*ggsi2xf8Sqg4kZ>1B;6han| z5wxNZ4rHp>k$?!=322g`PL6bSX@&}u_Q?&rBne@|MzW!Ruo$GU0<CGPAo^<kjiRT< z=WF6ww%NyvA#cdbi`BfRwu$9K8LkMGAsrYf!&P^<wOP526?79v7J;P=1GUA1I=OLV zLCc<tKdasrSIwRamzB%lWEiKhe>FO@h27&!w{43T+r|e5cDsdbtqfh7!B=7?EH*|{ z%kf|7bbaXT$lO@LQjQ{h$t^fi*4`SslX$Sc^5*J``(>_ORbO+LyjJY6G5PY)#QN&D z;_qDL!ra<gI=OG9=hcFlS2b9^Haq@0F;M<&ns9|bKFM7^Sls?F(6l$NWisdHt#sh` zz9R8<Y2Ag3Z&xes-iS9mn#dn!h&{zjk9~mdT3Rd;=jT>`=Ds_B?4ERDxyVKI7CrCo xxeoQ?r#_5*PUp`zlwR>vp6PB_lpho0L>>{GGM>WaPig0Jhnw5PsivOGe*l2=X6*m~ literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/UFL_GMNT_PS.png b/apps/fo/public/images/map/layericon/UFL_GMNT_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..6081d8b00f9a9d5a9e9ee32b353bd1ad1042a5b5 GIT binary patch literal 1166 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nBkco*&`K2Yc zN<f!FypUS}H#V;r8ce_d)2~P@&^OdG0C@?f(AO8g(%f9Q>f(~1RD^r68eAMwS&*t9 zlv<o$T9gcoxHM&uRRvbgMX8A;`9&f5`8lvq49LhY$uG{xFHmp}HdD|D&&*57FE7>v ztM~P_^2{qPNz6-5^>ndS0-B(gnVDi`?qX)?WMJuRVrpV+Xy|I<<ZNi^Vq)Q9;Ar7$ zYGiB-)9aF-T$-DjR|3<Ug3#-NQ!gkf<Q4#Jc1bPDEK5ysE6UGR0DIXg6SrF&aheC! zn}XXdPB``I10ACeiddwGh6w>v4~Pj*wm=R%;iu*SQ+p9GS>M`mbt(e`Ba^3#V@SoV zHIr?*4mk+4syjM<5SS*XkX!Y3?Vg4kw>T^tm#Tkc2s0~t#h7E$u%JV+cT&&ivUG)i zOQP8AJno&TKDlZ4T4Tf75Vf9`eHTL43iKWFin!9gILbjwr<KL(uO5$l%gha>Tudz? z7MwhvG>c2qpIvHB&$xE|=9StQ=CX`CZCP2XE}hRfagNDoVN=Gl<843f68C+vsc1`6 zlw$C2YuNjD+sySRZ@;%%5b2R?S<UjKqA)w{|5pFajdEO@S3TXB8@fdLTTF0r<oUFR zy_y@6Y*mi5ir;E}miYRn&Yq3)478rbz3l0XI=Nj^s_JXx^S{T<*yNWiSS(XBbJ2y@ ce}obkrl=nbcUXVr8mNTuboFyt=akR{0Hk-5^#A|> literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/UFL_GPIP_PS.png b/apps/fo/public/images/map/layericon/UFL_GPIP_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..5d7e86fd28d67d9256ec0e6f5b6c5a70b5e3038f GIT binary patch literal 1103 zcmaJ=Pe>F|93HbIBuS&fBJweU6}0nb-JP0gH{IQFYoQfe7u?XI*_r1$+02_}-nOer zsnx;i&>_lBNd$JP=p+egWnee2b*S(lRD^*A9fIwRx!R#^n3?y7@B4ng_xpWsq^<Qx zRprh~ilVAwN96<=tKDy71^L%46%;b;z%41<j=FJ9u^|=GP#S`mp=4kJDq7#UH!wg^ z<+Pqm;Z*#Xq#}b+Tnv*pEW)O!KvUjQ)Lw`|8fJ7eNH0!K(LmRNbca9A#jObJ(U11q zu)V)EsrL7(qDD6z27$ap1Pq83kT=enj+775%eoSoyW1=cmLa$|NdHMH6>kF(WJBO* z8a*n<^FR<7-scwten0SXyqD$3D|mRH<QF9G0kHDWB$};tO9?r;5{s;YbPvXs#Im_u zj>$DL$j-35D2lFz*Xtn&kJD#jCGRnv`l5mi9o5z?tRoY+ib@(~agZjN{yBnSt;(9t zN|{K(*t}w~Jj1z1Dgxv2|3eL9746^zT+8>L!cMZ!f@}ghC~K>vaozQ9C`*diP{GJf zB6PM`#kL-Vk<)`L5NQ{{-VWW=P|n%6jE~2qnCW1}RAEdG(nNvLbxq<!jWRF$Lq5Nc z=lK?&$VK^ZODHVxQD0Q_aYe3-)T{wbT;ytN+;B;*YX!q1k!5J>=b;w0kpY&EEa|0l zIapF}g{zg$MJ&l>NiwY4*uNTG+#>FAr>nLli&f)8lepa`wtg_}NaRYqipim5{$2WK zq0m%b{p;S?*tddm;%(va9cE}f7;YBBqa$Ti)~C<jo9jkv_pYz47?>QmTedLpY+`Uj zM=j^|&S%%nUA>X28WigmwrQ6`>Dldrn_h4qkN1hE_FSKt8JpQUTl++x#?5n6LyBTW zCVqSe@0%;X7Orsp>GDq-E|i@)R4;TcEq=(1K79DIPMhq?><R1|tQdN&oSNQw)4DW2 zQq$0-@9w-c)K&R(N5keV;};VR6=1yP+DWSVG<Cn`w*7MA%X9aN$68wDN8!`MzX3{j BYD@qC literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/UFL_GPRS_PS.png b/apps/fo/public/images/map/layericon/UFL_GPRS_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..79c120f205f75a4cd9590008f5cfc0b0a513531d GIT binary patch literal 1408 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nBkco*&`K2Yc zN<f!FypUS}H#V;r8ce_d)2~P@&^OdG0C@?f(AO8g(%f9Q>f(~1RD^r68eAMwS&*t9 zlv<o$T9gcoxHM&uRRvbgMX8A;`9&f5`8lvq49LhY$uG{xFHmp}HdD|D&&*57FE7>v ztM~P_^2{qPNz6-5^>ndS0-B(gnVDi`X=vzX>1bkVV&dd%Xy|I<<m&3;XklV$ZfxM< z?CjzS)9aF-T$-DjR|3<Ug3xP*Q!gkf<Q4#Jc1bPDEK5ysE6UGR0DIXg6SrH8aheC! zn}XXdCOGx#10ACeiddwGh6w>v4~Pj*wm=R%;iu*SQ+p9GSu@w9+cPjQe(`j145_%4 z^dv1Q)q#EY&yXbzAyNYEPOV|gA9b$#m(NpN{rl5*ac1t0hvKud&z?E6<;~U8&u#eM z-L<OkoEz`@{$OyWp?2_wL*d8$uE+oV?aX`P4AUe26Kw`{_RDrWd7l65#jCR~d3?_J z@NCbIOFLm*-|Ofb&AenHqjbfu@7E``tnbfp)JtIcw0QoWKL-mw-*Rocu0PNC&%dv; zAKt&eUt(6{tOF8UISo5RjwCd7ZrJ#z`s>fTkNLNsleevy_Vd1VN%Z=EzbnNuUhAkR ziV7TLdMtZqQx)@sUF=6<)FbS_6>s?PBzseVM8lJFe}C5HKRy5bdgB@03kO=6#Z0=b z9FHu#AMfx(VL~SNkz)ZnH#^iw+)dTt*}<r>#oXD@?|_rvpU1_F9>umrf8@oU^o38j z_CECbrITrCkAEE4@Ks?M<0+#xJo$YmmdyR0w1e$Zk4)>f_xrWpTr!z;=9ucC56`}G z`-tDE{q&n*LK#Ehy+7#_Qw|9IUz4+jXOYk(o<oZs@%Z!0r|<ax{<`uG#%F^1vW+E% z0;{JMbxH5u_(@7x`h!Q@v(sn2)9wHL`xxsI5%HybD#z`8>HPAIbBZ|UOqpmbtRc{t zxzBx0=TT<MfAW8Sf0Z~<%X?&#!yn;}=L{cX1A@|yOp<0TIP#ypq&0#0-~a#T9XJ^{ a3>dC1zP@JP6>&yTnds^2=d#Wzp$Pz-{}=QC literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/UFL_GVAL_PS.png b/apps/fo/public/images/map/layericon/UFL_GVAL_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..e8f7cde2e6b5547f88f9d06f44527a8fdf956cda GIT binary patch literal 1426 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nBkco*&`K2Yc zN<f!FypUS}H#V;r8ce_d)2~P@&^OdG0C@?f(AO8g(%f9Q>f(~1RD^r68eAMwS&*t9 zlv<o$T9gcoxHM&uRRvbgMX8A;`9&f5`8lvq49LhY$uG{xFHmp}HdD|D&&*57FE7>v ztM~P_^2{qPNz6-5^>ndS0-B(gnVDi`Vrgt-X5?&PVrt}KXy|HU>Fna_V&rOS;p%MW z=4xyV)9aF-T$-DjR|3<Ug3xP;Q!gkf<Q4#Jc1bPDEK5ysE6UGR0DIXg6SrH;aGD3z zn}XXd<~a5010ACeiddwGh6w>v4~Pj*wm=R%;iu*SQ+p9GS=UH!EoWe0V)Jxy45_%4 z^ymM7duFR02hX=_axnHt$=fgF*l;J>SpMA4^Cyn{u-5!8UtOwq_^q>hpvbCQk;Z>= z=Kh)g@L{1^+y46h#tv%}YHG{mC!FPYwx{&VZ~jYvl7D*ntp5KuJ)yskLGlno3G3sf zSBn+&ejGk@{J@zb97oP1FgjLdwgq1@;wfrBzfj`CiEAAPc{IK=othqSG2sXI7rWD& z=i5uh+3h{Apr~*lfx|@dNxkKYMQZ7?2C>_}bKN)~?!dE2R^{8P`|)gcj*4u{>>Yyd z)l{7?`1sCrN4DdSzxQO%sXgQ4@jCU2N8e1pxPeVU+2`WxetF4#|9>7nz#_zGIlpyg z>%(Vfl?&AOR~8*-KKAeP*Ujpi%FoTY!*}H{%f^>qPA=vNUqA2J&Wdjr(!VrJo*0_` z<Ht+W!_WKQ8!(w_=*;vFih5>z`u+X=F%7fIZ{M(9pi%Mjld-c`mE7TFyq_hn>BXO0 zkehI9!OEp)7`peBu6|b6<#pm?Lge0>PkH|@@U(4TpJ#AqZ?SmZf$Q=;8f<lczfFGl zF1N+z#GzE~Wp5H1IU7vu>wihCdvJ8~^Mu=p4~|a{=Q+RM;l`v(n|KZ-NjY3&WE0Cd zDe58;{&my$ZKD4fHeTMGZSiLA-nyn6u9gQiPRbl^*r%DDcxL|TYqH5H3JfzOG*}YE sb7E|pReTq0XnL7=WZGO$Mg~SU2FAd1S2y18F$0y7p00i_>zopr0Fdb%6951J literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/UFL_KMAN_PS.png b/apps/fo/public/images/map/layericon/UFL_KMAN_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..764ce8ba5dcfbccd8ca87ccd6a270597c2d441a0 GIT binary patch literal 1572 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nBkco*&`K2Yc zN<f!FypUS}H#V;r8ce_d)2~P@&^OdG0C@?f(AO8g(%f9Q>f(~1RD^r68eAMwS&*t9 zlv<o$T9gcoxHM&uRRvbgMX8A;`9&f5`8lvq49LhY$uG{xFHmp}HdD|D&&*57FE7>v ztM~P_^2{qPNz6-5^>ndS0-B(gnVDi`XyR(<WNct*V&V)8bypKh7dHzFM`JewXGa5L zOE*WDUYGpj(%jU%5}4i;gkDFSdO=Acw*Y9fOKMSOS!#+~QGTuh*vnR#xZPro(>$o& z6x?pHz^PXs=oo!a#3DsBObD2IKumbD1#;jCKQ#}S+KYh6`qIybz?{W2!_&nvq~cai zuywXbqKNH%bK~Dhljq(|xt_9EDJ#*zQ?MyXwdqD=XGg0-m{LasN0?&o*0~%>s$z!q ziYikDgr}64bqQ>8+`Rexn=@(8pYC)Pn*73iPHOtIdDZ7_zxU0Wxvwqxxl&>O4#zo4 zA{#w*gx`1S&%Zv6uj%SS7BNG2o6X%zx8#Zox(Z%esk3Jv_x9_qiyyMo{BNu9+cD{c zjmtlSm<{>iTFDwy-5yrz-FnM5r7uu#x?um5z?C6qdwb{iSMPntdhGrrmET-(n;vxw zCkt~NX4t)3?~ullvbZS4zNCBZ8n=`KP95ogfB(Y!>h~wASNt^AoOEpUrM#ZGaomiP zCE6I*>PDnV-OS-DlzI65n^?_#=bb@Q7x8zTzI5pCC6AjIq7Ii<t1R<0GW`GXtzi1| zwD`o-ufng+=|B0bno?}}bmu!^&w}EL6U&y=CCv)6QsjR4Lz0Ir$7}KBqJ*d<=`@vt zp4zD!zY9z`sP>52Y45#-e@tZ3rERx&D||?l)ZDhQJH$#^(RHtRdf2kaCv1*C%8%6; ze~1i~T$AB+S^Pe~K&#**gN3TecNQ&PeA9=o@x9thmw#{WT&}lSan&qwhE}HOl9e{O zo*QoDndyuA-F|UQCU(unZM#0j^Xpvp5=o0V^Sb&|M(nqQuKIoR?9EqRy2&%kPxeyx zBKe6w99<PXH_10Qw)2=z<}KFVo*KTcoBj2X*HO95n##>Fdh_2j&d{onU46u4r@WNb z!9|sG=Wd%Iej?gPZB@F<sZH`c>$X^*i`<=X`KL{ae#??A6LmrpcX+5WM)|VWo{v?1 z&Uf*?{{vxeM}Z#e-d`f>i*&SIzo$-}sFJmPmP>Q?yR*jM^e$TcGkrII^%3QySrT`p li<8%f{uC1DXa6sl!0;kmk>gzTt=FJ(+tbz0Wt~$(69BpkPN4t* literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/UFL_KPOL_PS.png b/apps/fo/public/images/map/layericon/UFL_KPOL_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..d9fa712cf6c3528d5673c19c6c3cc6aaa42fe604 GIT binary patch literal 1122 zcmaJ=TWHfz7|xtjom2NBIzc_lKoo4!)HbuBb#}?BMO#K&aOy<U<ZKIDa$<6}W>dsF z6J(%1i6{!9h$y~@^8(Hx-awoeHWV*UKBxngDT0XgWUkW(Ye;e~eBbx~=l{QRpdq<x zM%lbFilS!3S4$}}R=D3(5BV<~&C6t{#Py9hjhb;zwjdQ%Q5J%@F1NrGl+~`S_hFc# zN@*?Ah#M1Y1qJDh>|z*4Hwl}f!nKYmD{T;iENsz?2>tQ;O&VxwgkBd+_!6cFTea2Q z7EE_1GfH=x5>n~f6(H;gL_mjF29Dlt*n$(G$8-fUcehy@j6rZ)g#MjWW1<0w$bulq zEb}TpjsrZ;aDgDtb4!8W$N5<wd3i4v5Q4nmuL0u^O`=(9vyhTv<FUvpLbqaU3M`w; z<(S+u23ajE7Yc=34Zq(@5MH~>z_Q~t?COGo1Z~CAOspXTxQcQXb>Ik1GW~r7-JFm$ z?C~;@g0YTlvK-@ck5m9A690$l`UKj>DflPfe+t`~E)%jTXrm5GA&qOUc0-whXh9hx zD}zvbp^6Qy2qU`{nLteQVDUQ5P*KiaGKNnigt%d2*-&6yiqJ%X(KJ;E1*K>#Aaa3# z=;yflK!^|WVzkaD)`X;(C<Y5$2`L>qG;o2d{^9zIa$PIvCW$OTOY4Mc%tAUCJF=h^ z&803@RBxQC7SF|3l*^K2Shul%HM+1x+~ZCsY)cjs#)k%RyG3mMF*#gKuEbDWie{V_ z*&q3QZ7JW7-ZZ*d6pzb~PDILIhQsCQvq^aSOz*yuS%ZVmCO@q~uLjQTpLT3ZXD9!1 zJ(zQ2+qd4Tsue$LAA3%g>iYaAO*?14zPWA9(UL3Z&7$X&({sJA&v);^{Zl=MMkZ~i z&X@Erzgw~Kl37(6f4B0>UB=V9YF1@);KJUiftn)=dMe*mJUq3-(>Ht9VL#t~Vc`3l z<et&|+sj-&+TQg3(=~8!&6JU{?M#2AXQm9xhjx{e4|s;-kEWldZe0C*=j(@0BL}Bb aljl-DmuEMO_TReW-uifbQo2~TW%n=aj(TSR literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/UFL_VALV_PS.png b/apps/fo/public/images/map/layericon/UFL_VALV_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..1b5d701789180cbaf325f70f88bb39c24b46746e GIT binary patch literal 1058 zcmaJ=T}u>E7@pKD3{fhAENU1j3f%eFk6Cwc({*PzH(XnG7xdEEnWH=E%$a76?J8kt zq6rojArweP5K&MU-2|2u84<ZZprS8?E-b3s3ZXN)yLHhv%*^@Vd7k$@@B5soSjW-o zs=6wIAgUv6VjPdP_P4bR|7R|wc|7b!p)QnwJt!lYfCwls1;~gd^@2E%l%W$ZKodcf zQ);pcbw%3+8EUj-W9Y1AU^YQCHD?V;?gxlWfnHVjQ{NUIQKYK)sZLLnjT%9aR@;V6 zkQnYr%ESG#PobKRkWE<u3upjIWL6u{Eg|ct)^!Cux3?LJT!)~3KedrmS2RWjp$SM2 z?Q+O0$B{fwb8ZjMa}A`E<(v$QU*5sF1rIMcy=4BOa5Pit5#nMv9}BPiR2m^eV3<rM zLuXtxG<zA&=kwVbPNxGS9M+JIq^v`?>I(`Yuw+v;kP3CuR+Lh35cw&b>BbQ>qbRFe z`7+^xF<HrAIGVMOQ~*Y!|A%T?5pAJ3_>=EHg{|a}0hl<j;Gikv#`V<Op$s8t0trDg z3E@DYim^0A&`Lvt3?_K;P^YRZFk>BF$48?=M7NNn%OE29DXc)Nsv@{KJ{S&p!)}io zS3Trz<XgRA7wd9yL7ok=;R08L@}LHERNyK_ZX;WgYg<7xaAXmf>Peu4O{kIUM;6r5 zxrin8@?524F5XZ{E`yU{?8g4p=)x9uk3B8g7B7m%2Re4UiEaJ<Zsr5N60;F8kj%bL zO<#4-jqZG0wsfVhPrS7_@_E;e@+sol$7knrV>Mq_*M9u^ncLGeHr>)p%vD@!;U``# z#gk%1;(Kl((_k##n3z3teeLa=n$a&0_rF`&E~f8~tkl&$seXE(aqmEP>n9@ja(Q`t z{4gE3Sv?<{yu8J`?>4#3e9(QcqCGHPdG=hINX%@$SUGk46tSt2m{>hMKY8!ibNkjt LLLK6r*6y+26oFXm literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/WTL_FIRE_PS.png b/apps/fo/public/images/map/layericon/WTL_FIRE_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..4137a3f74526c367650a0bf2b998b01a3fe31e12 GIT binary patch literal 1072 zcmaJ=TWHfz7>=xLV>qt}I&g;UMP*Hzu1(jlI@@NKf~m8st`91v$ypn=<izC6c2%(K zLD+-fi-Jthc>!U=7x6k}n~cG{AWnTzaD(m17bo*Y5a-FZZa!E;l5^qvzW+b}|DFD} zXiH^9RRuv1m628<hQ}@TS6+($dlr`@JnTYE3DgcdQARQW5maCjkP%Hvff$gK-qTZ{ zfgnmKHJ(5T@enUVjh1W-oz)D?CWwZ{tRcx=0Fg<MQuP4!ZDf=pRV6@mctw|Jgh5(u z&6%J*7mdrgF4?b8jR(kvERO{=fFv@jb?X+N4N%LvJf7Rz3`H(OP*;FjNh%?>kzr^8 z(o5GlWf#km97nSrFUPU9q}#>185e#zC+p$89Pjp#s}F^vnMx-g6Pj0J;Z=Z2BV_Ol zlgVW0OdSo)6vO)cep|!sc4CCn>eZ2yb?R14K|uhPY^nxQp-$S0QWEx{0EIJMIf7=a z$?Dc>nQ+0FtYk1O?Xr(l0E*)Op_;aawonYL=lf4#E8c4WCI&3nW6HR3oi%nSgAbcP zLePvu*j=b%TN)y0rJ+HF+c|P?hpH<uW9?hUiy|M<EhOnOhzJ1+E6}Q{@UEcO%dvG$ z9xoea*(OiOSI-IIP>2(Jg4<i?FK`7Y_h>*z1+KErZ7#~St)Lk=vH(o=3{aX)sFBM@ z=GEf4gp2B}a+Tt_2t~OJPKL1?`&Xk2Ti8AJbj`MSv1WXrW4D{w)=&Gl-@sSmc0>rq zv!5nn?4~@q(UF>&gTJo*o-Es0HZwLc-xpVF?;PD$I&eJQ{iHgjm5<+LKabRx4n0U* zCg{!Ie{3C!#<tDIpPdsPJAxO7^U=oXM<<TGyE=L4dj5Uok^I}){rTA!j<P9V>B+-C zZxL_8C6$Z$s>tgPfrXyxdB<2qBKhThwB;)`{_5e5U~b_2+|t>F=Pz4t4x7<~nZfCa a_WTAyAH6Vm<>PMAzQd8GsBkZIs_zd&Kw|U& literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/WTL_FLOW_PS.png b/apps/fo/public/images/map/layericon/WTL_FLOW_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..285f7edfa81fce7e403067fa779164e206500b58 GIT binary patch literal 1137 zcmaJ>TWHi+7)~t?T3gu_#S1Pyr0!O6XOc6Q*u=)}?4+Z!I(3|mwm#WRa@xi=IWak% znbw!O%Ibn3!ipj&7D4u*%C0P|s}EL0t>S}XABvz9K~O=e)Z2qtPim+7;A}{8{&V=g z@4qI$r<&GRRV=Gu7^W(*K}pl~8}FIpqwng8NtG^3Nn<N%#_c4pI*5ttIEz5SR69@_ zse13Oo2Z^)%2^}RN?MbfBn_JZ)x!h|rcK!lQ{PaqRjmsVkVPGaC9~s~F0;VUWws@f z<db#`bs8J`9Ms&`l+pUSG*M?8)`9whL<LMlR8TOxEmtbY?3AuVZSR<4!4!ma$?T_~ zT9YXd!wv$GK*+E05CTC6z;Hwm;Ey24!yw1gTkylM6cME08Zdpa)SIKXOKBxO?ThYY zwv!NB;<$W1AIOIS*y-S)D2kp&FzBZUzuRjOwcxkhnxcY&T+K0TVqgn+ifR`35SgWs zeoDc#XJjpRx=gfSTtT%t7~s8>ioj&@|DmQigLX+8eUA65!fvM5MqC=XxX00G<JxOH zSGE*$kV>$V!MM9v#Z)II*zLqNh&2mfWs70yIPb2S!Y7kb!g7gfX(*w{EL8{?hAxG| zaZ!MLI2?g72phvuYKTIe2*WTQ7eh*st6;6iL>4J>_0QZ$Nv<~vrcFI7$T4zAk2}}| zQz=VE=~#j#^`^Oc=~zM~xf~6K^BVg_ql-s$dOUMxZ0TlZ@R3EQ-JxT>ZQq>%`bj)a zDA7#ee)j$3WJ9?ybo~Av_T}!}>>8ox;AkadG;RE4-^9_Amv6jy{XRPQ+h6<`b8m1( zYSEd0w5|K^^$%*?kZ_e5o~`WO^9SF?EbX5+u~~jo{p8i;yAd9y=GfO~3D;I!oAvL2 zTv6Qug5THHo*wl*+OfJSTlbu;TwMNlG&?$SerU<?g4#ph?L9wo_ua9bS9}*PUTk}N zW6huJ{G6}*S#JDcIs9qMmbsV8#y`NZBm4gw8$Mh!io~-^UfjA`c_H_FS#G;_psen( v>bren?a^<$r2hB=_J^&5Pnm_Mm@*%;YWbnPrw70R?<bIGY*Nns-1h57DF%Gn literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/WTL_MANH_PS.png b/apps/fo/public/images/map/layericon/WTL_MANH_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..5f2a57cfe762948a8b11b67983fcd1a4a843829f GIT binary patch literal 1557 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`<jAm(=3qqRfJl%=|nBkco*&`K2Yc zN<f!FypUS}H#V;r8ce_d)2~P@&^OdG0C@?f(AO8g(%f9Q>f(~1RD^r68eAMwS&*t9 zlv<o$T9gcoxHM&uRRvbgMX8A;`9&f5`8lvq49LhY$uG{xFHmp}HdD|D&&*57FE7>v ztM~P_^2{qPNz6-5^>ndS0-B(gnVDi`VQ%K?Vrt-QVruAYXy|HUY3X8N>11x~Z0PJ} zU~1_G)9aF-T$-DjR|3<Ug3#-NQ!gkf<Q4#Jc1bPDEK5ysE6UGR0DIXg6SrF&aheC! zn}XXdPB``I10ACeiddwGh6w>v4~Pj*wm=R%;iu*SQ+p9GS^s~$av=i)Q>UkkV@SoV zCBeS_!hs@t-=Cd*-EX;r_i_O*(bR?9_DyP9oQa7Yf7qR4B*Ts!Int^vw(HVdPU~Lp z$NmR8)(P~e{b;;D%faP9(2TNMm&)w!e=cK?EnKc|d2-L5Io0QPe&?AObm+g#uIF_e zhMgLUDJ<F@ue-li{X6$vb;qxlymRXR+Nf;csFW~NWRjS(dRDIgY1Iue>>P?0zRbO6 z@_2e*sf4rSvU`(S{N7KBSn~Nu(Bi_Bs$|_6Yr_^^SmPX%cwy6x^)Iv6O^H2!>gdE4 zr^-ofdseP!JzXZyV`IYIIrGx8(va(Gxqmhv*l4ZJbWW<xYJyj_>6Gv5;w1H~&xt;H zvY7SQvux2{r?i$g2tD4hu3CL^t^fn4uE;FEZ5OtfYSw;WZB0Ec?R2i9+oNooLcU&I zYvt)9=NWiR+1~aXG{4Qada+f`QinMW)6;wkT0bs&y~b9;V)Fm3t&_5ue~HW~3>0LV z_U0|)sws`@0s=M`^aK^}Fb<YD{atX$mwy|NO`9YVY`6H!)5BFlHeXJ6FfBLM^jM+w z!${{^?AMcaG3syb9@6SM`}Orn=H|JvU!1SDOn(u-U=r);rnU(YK8L2gpCo=wEl}j? zdWE~jA@?G-%f1cVC{P{0`eAcR*M|j9wz8=^Cco19wO!@hp_0Qlrz~cDH!s8g{5Gqz zp*|5C=RT{`-Do)LWgE-61AH+SS0_GvzRA|U=;IHosfkwa-MQC%IdbFeK8yJ;14JEK zv-~da2~_6h^2$HUE}AN<Xk|DxdeS6y>xutmQ)}j&`ZOcI;!o7cQg*F*v!hpp9=6QT zVe2>VR%m!3v1a?6P0}7eH+_$9a9~P{`Kh5QdpsiE<;@zeq%~7NZOgIR>D|Zna{hUL aMmC1RZ)#d6L=Wu;71W-telF{r5}E*KPgV5* literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/WTL_META_PS.png b/apps/fo/public/images/map/layericon/WTL_META_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..22c7af31b32386e501fbc0948bcf4bdf44d58332 GIT binary patch literal 1100 zcmaJ=TWHfz7>-oSm~Ko^)Cqc)sheP%OWSC()wwmDE7~!-$_j!uP0rT1B_}3lHmgI2 zV;fT+L=;4P5?_4Lf#8b|-f%Eb@J$p%MCOY(ydd7^$+k`(tRcy{@O|I^pa1{Pct`ur zit_4milQpwZBmkqRqj{jCI9swXJj(0!Lc;%MBO+qTaap2Q5J%@F89DBl+}TQQ?QYu zJhYZd<8)%Ts36@hyBNQtn}khKjZKazE4>hdEbP&Y2>tHHO&VxwgzgF@*n}B{IjyZ= z!OlW^N-6XzVU=#$4jLVi2<Q;Yz|s2*TXZ7ytgcAr?lwb%SqScp&~r(p6CEImEC@pW zfKOpL4hVvu3x))N+X8r&;~AE`f{zP|AwlG~g87Fg(JZxFOiHcuvB)Yy=P))!hRNsi z{(QiXtR997hr_N0&-)0%XAc-yc6^3iTU3ystyr3gHDmx+QO=@%9HB|3b4Sq41zE$M zFB2&k<H#n%`C0c!MPMTFf2gi6plzIlfAamOu$>w(A(MnQ>bDfqxb9jvlqp6nC}U)$ z5b7&du_K2tvUA7;(M|!>cWH)-^7iIgd?F#n4I9gb0^?GICJKH{Q$;qw@`A867z}X| z$HjupEj$};4e?S-fR9CET#+jwrC)~zE^^gB+)zobYX#jTktJwphoIVOAsx&fS=37B z!k5&W=c=W136$hABpJqS>|c#8ZV~sm(*@g-#e(snLELT;Tfg#5?I2g;R$OXMIZv`b zW@ef^8;6!ZrQQq$FKpWPls&Qh>LT#q`lPr`Zy5YsK3ZdXGUspp{5HHNuxjnn^xN0d zYwJfRGM!G>WaV9Ix^8Tu`lL*?UAufdI6ShV?(TTcv*({QZ-aO0@OO4u=Faqf^#Q0} zmAU;gbxH^3w@S|i@A%Q$Now%dJ?})JdGDFwntPAdjcl5tb}h9>U(~f<d?<}AD!c!9 zu<G=Ohq;Rtx6Ym`d%0xrE7f%*bE#l#SV=8jO;sMqZuqjU>Aicu<FR(>N=xS0Z>&&g AEdT%j literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/WTL_PIPE_PS.png b/apps/fo/public/images/map/layericon/WTL_PIPE_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..c9c6863f68f8ce9b39d7758ae2bc1d0814d46948 GIT binary patch literal 1075 zcmaJ=OK8+k6n(8)wNlV3s9k7CD=0e2WI7W&Vbb4Zq9dl1=|HDa#58$rV@+O~ymr!$ zQi@g-E3Q<qpj5$~;!gZk(1k8kXc4Qpa9I=-(Si$Md>K2{g=0waKAdyzefOSsrnO~X zMR`>@0H7kdUrLd2z5lH#BmeE+aw-|N;zS0wp>CX29SE9q)CH-esrJAWRP~|$=P(Aq z3ff3#a7H;OXvkz#AH#U2P1pd$8a!Lo`XHvdV2@#m^q2cHG-c=_-5ybbiXDf&#{OXk zwhgzWwc$Q3s?!biRLm2IfC;fmdFC<86+Ds7>k4G<Z?iO&hu}Vu{+(1tX{F-GfmDR4 z4QN4*qj;X-!V#Y5_E4c97h;3t<pW$;i10#aFSYd0B$}gl3n@unibYl;-HWj;uxvJ) zWwNyla(Y-U8jboIp-_Mz0`8E7RWD$<)dd9!x|(Cy*gzKLE2>>+0E;xq^!E`=ds)_U zm&!y6#(JvFa!k-aQURza|A(69GTOx{_$S|g3cKkc8?q_rq5(%Ejq9%VL)k*yfhtB$ z8lhu_Dz^3_jND#iQ}H&Q+SzVcI?B4c@_0oNl9r2AOM^*Cq=^D!7`o70$2Ui0IUbI1 zagIxb>*S_LBE<8u6qiGCG+5wDNE<Mrg$rE$4_7M6^{rsqB(ek@V-V`HgG?%aWWgw& zOH)z3C9YmPm*%2emL$Xajs2_9g)QP9f4Xd2vRF1gw20dsVr$UZfykA(nUtE+-n*`! zxm?4F9b+4=luS*|aVuxu^n@zIphMgJYV%!har3sRGESZQ`EYji>%p4(iBF9TP|r^o zxm<4a<oL+Qz2MWwAFmBJUS50Y>emu|@!+!)pRYV9y)9peIrC#+9iRB|V*xxFn|{A$ z(~E`Csj{)@a`F3}tuNm`I#p6#)xV>%6Lg3h4=j`_r{4mXIVWGde)PZ%>+rQhR?RA~ Zatrt{J2@{+9zW|}<7A>my48GS{1?p)VJH9q literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/WTL_RSRV_PS.png b/apps/fo/public/images/map/layericon/WTL_RSRV_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..d7b307a61bcaa6059fe5565713ae6055c29d209b GIT binary patch literal 1057 zcmaJ=O=#0#7>?|RF*leyZM!UFtW31|=}%_EYU!GGE80=o!is_{O}?#RO}?0Xv)vFK zia+z<O$CRbAnM7B2M;@J!zqYtpgSm{Oucv!ROVm@wSMW^&Vw~1`F?nw=Y8MreZIN) z$WUu@S2IBnt<hmIfyXxcYih**?#-fvhfWkuqa++hdC3GsP=OghMm1>yB!Hw$pL`Am z2%?TsQ)!fr9TjA#(UOg!3z~u11ThdO7?L~*5SalJs_v)0E-X@{s`#l<Z;Xu@A&^yv zXH1Zs8A-`Ald?~t0*A?gf`A1yfF!b@<#bCZ_^Fbvfamr$Ly;v2n)FjUNu^_PG6YRP zdTF;)W;u@Jd7AThd7e8+x>(M|u=wSjoJa8Tf~%h_KNOB;D&s;zjFe;Hm7mHYWC#qC z&*$m9n}+5D!})wZTf^mYVuaJ0){#_j>Q+xhK?Ig;ss>V_PTGo622LSAg)`kLK{Kkd zx>Y_Vd|*sLG8m3#?UE|MSnU5$O{=0UlmNT={!`dWO&fqo01Hl;GH%>>j~&VoLMD(9 zG*b}fDyJCFLIkZWG{{hrC;LWKU4eOPe+eIp2~pibk}iX&=%=s(t*VOPW?4SSdt4qb zCvsfa6LdwmLwwll@kK)3aKEp@6`?$(0UcGi$}ZPklWSW+GjL=PnCdB@L`<lWrIH1; zb}np9y)sv+oeQ>1jXD^d3}ZL;uSQq4uzT!j)wXz1H9pX>+f8ii?@j3=_)1)hiosOj zZRTgO7^v%=ZJ57pJZo=BZmeCFR_<Nj_r8H${dM8x*zZ^K#g4Vy@vG}?j=`J3rIiEi z_g{RVmmG6@$%XnHG5qMtt-zD@8?d83+}qi;+R=I9_gLo5H{#RM<BcMBy0|s}as737 zOL6h6vVCT=?_Hatv3dEyp7YB@<j#+$%4bLX*w|f9f8tBSEKx^X6o$68jZ1U(rHzJ1 K#D{}p=l%dw(_DuD literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/WTL_RSRV_PS_GRAY.png b/apps/fo/public/images/map/layericon/WTL_RSRV_PS_GRAY.png new file mode 100644 index 0000000000000000000000000000000000000000..33a667a1e2ff5a9e01855af8b14631c9699d1c6d GIT binary patch literal 259 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!5N+|jv*HQZzo%G9X8-`m|w*bulnHb_71%X ztA9$^c_=hLe`A&su)M8CCS&$e=lg1$wki{joY~R5g=JNh*D;BwGZw2>nDQTHIAGDY zWXc1lPdC`srZos0TDLEC?t;)gN!Fb+Bv)nKtA18_%+mdO>6NIHmdpWOiIHMnnpdJ` zF3X(yChSMs{s-bLm%jhK&0eB%Ok;Wck14mcZ5S1f`OHr}BH0XdBZH@_pUXO@geCxp CKw=aC literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/WTL_VALV_PS.png b/apps/fo/public/images/map/layericon/WTL_VALV_PS.png new file mode 100644 index 0000000000000000000000000000000000000000..ca2b4788b74c2c48d2c6a71fee593031ab421a82 GIT binary patch literal 1077 zcmaJ=TSyd97#=k&P0b(>Lvk2}GTfP+buaGVD(lRu8;vgOf*bVE?95RIojKFYv0Z&p zQ$&j(Gcw6udJuXjdI^Fal7cQq?-3$hjGijGJP0LrMt9d9+J>1q7ryWN|MUOfnTd3^ zmlhu`CJ3T5+#y8qSZ;s&3h}@C$CiYLN)(EtZrF>Gk_m{Q0uz7?Yf>MG0!bM@`vNo( zL;<D7;wUbj<YcJPl8vELnt|B_(bSSMBzXWJG6DKjJwSbZ_=qA^B|!CfM5k!*pkM76 zF+ul8XG|U$ko^kP(o8m`I4qz6B#|j?P`9{LfZEpO@Z8>JC~_Nu1_IPhQgJat^3VjN zhi-7lPL?ITUYd1#yk54RbU9fU<HWDm!MZt*mvi~Z^h4ojrqatrg|>7oyb4hL2pJs1 zB$G)x*+4_Hk750OzpdeNIWWRu4eLlsIdrQgqaXlFHdO<uP$z9gDFKI2fWn#X96>X( zvbvQn6D}B&k_?8Wo%WG3KvDcZRMWC(3q`?hzW)@qV#5YtqQHVfri>fcTVsbZINk&j zf@TcD!Aun+{SZN`9~vaz?In-(sJa4^R^2vU6uGc&AxW1(SO`#9fmT(83%Pv0#-OLs z?O}PA4Y~axC*RoW6Ik9AbOzg6Gh6}6LmJRghO6vy{W-a|6*L1!7J#Xq14^3-HFEpN zoSHiqZ%(~5SIM1=FDIA5$uM?f|7vt*3%kdjW^IcXS>pp8yWPaLzWJ)_6TT9+!$L5Y zdXw1L+G;5%xv{XY*}gP0EAKh@e0g=Xs^0j%9&RgikBMda*u=!<C@S4sR;AR|KAWW9 ze*8T1_-O53AE8{FpZ85%xmC>fBr7i5*;tR{udJ<o8SU%&HCle@$n=Btsqy{s$or{p z)f0=0Rs1Qn?nK9jIXQSgSaj7D`T1^+FDfv9ALv?HUur#6ad~bwk{Ca|Jh}MtUf%Vp e>8IEDy!;YEe%*XruYA&OU*vG8Q@GoD=KLQ_Vqx_F literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/default.png b/apps/fo/public/images/map/layericon/default.png new file mode 100644 index 0000000000000000000000000000000000000000..92bf1f587e549c99cabe90492d4421dd2f8a8dbc GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^(jd&j3?%D+y-WjAJOMr-t{fa3iV^}#7cKqw|Nnm$ z%?m(rmXaX9U?7jdL2Km~AfL0qBeIx*f$s<iGfvg!1DT}d>Eak7F*Vu1jg5_`<f%~u z<DAnx(-dc|KG1V0Rpi)l)srbAdb5;Y3R*C@i@9#STXu6dP#1%ztDnm{r-UW|TDveG literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/layericon/reset.png b/apps/fo/public/images/map/layericon/reset.png new file mode 100644 index 0000000000000000000000000000000000000000..45f88920650da2bb99c09c2795aed20870c5aab4 GIT binary patch literal 108 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|#-1*YAr-fh6C~C>`2YX^v17+v zG)>u<JJ>iB)-dvm@BaA1RpYY5rpXW7lzz`{*&wxTB^!gCocK!zUrl|Wb_P#ZKbLh* G2~7Ysgdv9j literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/arrow_down.png b/apps/fo/public/images/map/toolbar/arrow_down.png new file mode 100644 index 0000000000000000000000000000000000000000..88590ecaf9a6f06c42759eeea8aa34471613f969 GIT binary patch literal 1532 zcmbVMU5FJ`9G|ciby+Oeqz{7AtfG<gc|W{!a+LMXy7ywUUe*h{l0@g8IrrYv-kCGa zob}$_LTVu>${w_*Fd^un9_*oqi1r~Wh$K=$2@3K-lU_3EDcAx#b3cZ)EXiSJ&e!k! z{@?%CDpQjq8y?;uNzzEU<V=h4{^VP?R{WpzCs)L<J}e!MC24px`R<Y4KJ}m^4Q-*- zSw8DN1u^qg<gpr2JANq8lC*noCq#ITa8M%+8rbrU<<De5JzJj1xw;z`Nt2cqBXVeQ zs)`rqu;s~n_ki6UC<uJQ5$O1>Ach@V?(#x0PqsA~bRm4smd6u;VAidGB8v#ftGa@9 zJr8zSs*%s;vxS|&)J;Rv4b3nWBL{OPG%e77WFal`>TufG-<Ks;w%p`AgqqfFx7Bt= zWl=*jEX&e#Q!`CPAe49^;HaYn@z{XDAu*0<$SDgz!iZ{Yp4+m}v}b}JrnEuacaw0K z)<L0WsCr^j7wF*>7tTkmu5b@)q(yuZ@K|7t6dN`fXK|DL3w3&YivZzT*G*;IRu|t- zMZ|pKs4%1NklUi;>Ox4gX%e&f2$PAULd~(nnh+Kvf;fw+jI{=Vsti;Hrm31>#|#ZT z){Y-vb%8jD6I&Kh%PM+7yj8sba|LMXPv{oZ^&Zq^9<49@6Dkk}%$T=8Map=HqdS5< z4C^fNkuaG0s6n(aXviRSBP_BOi-cgIU1s%uxmc`3tWI0vAfBGw2g(!0ykX_@im4i1 zbzK*hgP5ZLld@yW!Z|9X9?aoFc9)eg6qD4kQp;v71z}HD3Wbc}88yqyBQ&`0Fg%~6 zz~H|3Kkpxms3<|yx@(@KFq7PYB^ryUF7!+15P7~oYf;cm7l?3D2DXfo_!Cd=Z_~T> zK##WFB!cum@}dWeS)I30M8+G!TX)PmO(?G=1>3Vj`@4zVvsJ}CfQyciOw(2+7HP91 zf#`6NXk|xorz@fjzEO6@tA*p&FMdAqg}!-BWqFj}d(-`N{r6kRru}1&=u6h-cMt9u z`ryjat8bmWw*BY(e)#Hg=9ewUHokoQk0Ggib@|P$*M7b5%IMkG-}`cHrF43m`}Be5 zoX*IJYH;}5AGiPXz@;@0A@$^oFO|-H{LQA{ycdEqk7hnvITai`zV7$oJ<ptYO!|6w gW!s-O-?;&1-oF%oN6&BkB<auPi7Ds9ea|la1xp?3tN;K2 literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/arrow_right.png b/apps/fo/public/images/map/toolbar/arrow_right.png new file mode 100644 index 0000000000000000000000000000000000000000..7090c37dd874334c8ca2694e8e4b42c33e9d4e16 GIT binary patch literal 1931 zcmcgtONbmr7#;=J?1n|6mk=Sey}_)HnyTvQ>FH`SiJO_t&cM#P><(mofL2#k&on#T z)pqyp%&sUR@gNvbPce!t3ORTPUOb54;~JF+o^lZ(M};7W_yDnbW_H{pn+G{KOuwqW z`v33$>Z__Z78m9wCk{;Ha=FQRt-7S1`?71#n7Tg^%>AVv<5BJDB$wO!Kz7}gJNy3r zTyE?OzqyjGH0B*9gFNNZ75QEeDReG(<XA7FY*nP1D_VY7)~|g2rLOtBte-44P$Q~{ zwqM(f#q#DtlWndt!u4ZEwIe-81qeh+wO-H(6Q@_!`*9uho;5>V>qFAjvObd~)K(gc zT1Cb}v+@Wqge<K@^4Kyh(|%ktkbxn>5E}p&ouc6wL>vBel`ZC;vs67X%%#4{dOJ-c z2f}W*o9`C#GHyXk2!Y6eh5-};BpYE$dmv1vwj)$U!eT#4eHm(5MC!`5w5%(pgA#&h z6gEtTGAY4ek46yZQC3nP$k_-Nt;L;wa?YUWh(LsCqOf>`joLDmNn73^^r-u)1WMXQ zW0Yf8E<rF#k)*Ths*Ir^yP}ikMkL^pNaR|~#O%7FIh9otIh9z@RK`syJKGbrxJ_9z zjJ%;upY%g6yU8Ov28b$6MOjy~W&&iZe-qhG(RK{<7$Ocr1875X-`ltzst|^Q3Rgju zWjIagEy0{Qo{R&k3iboq5-<u|x;B#0smP9uRbs`iu(Q2hsVv6Q^E;{|S(-bp)n_Xf zCYA+^JnqwNG@N>vq%>rrUM=fNoV@RIhkBN0Ay)v;wF>}alK@f>2ozC?QJ2wDiIMH` zRms*e3uNO5tAR_VV*E$1z={|nVS)l?2C!X|0fGnt*z*K3Y|aTAh^N>*75i#I($3DP z87r<L7MX39NC5*wcnr9vVnrE8z_tsRW0x2frJ3#fPI78~qULyGxR92`i^I2$ul3F2 zP?jx<vd%I$2(AyC{ay69t<1ym-L_CcZ{m_c_C$JVm&RhIrL?=H3*n8(Cv^Sh)IDY( zmtzJ@UT^^;W)ToVJz%-6MT96(PTcL%ucv;EYwv{mP!`svVN0kT7V39i%<cJd!18}A z24)-Uz+v!O^Y#07Y{F_H`%P+R&t6AIiuxEGN+MJ`#p=lU<jmew9al-cI@7dIfA_=J zldqyZ_k91#;po)Ghr<uwv(J9?GW_7J18w+DGzAx@4}E%R<=pEB@7{X%(%9CY^HYb$ zf6_P3J@fW&7w&bwoj*A7^Gmh+9-Z1}p6X41eDVArf1kPk@-NGmds}Z-pB#VavlCy{ j4nO<*<gZtrf9~{y-yDVJkJ$PrJ1*<93)S<-UwG|b)5l~b literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/backward_icon.png b/apps/fo/public/images/map/toolbar/backward_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a853475e13a3663740a1ed30c7539c6ef7b7ad6 GIT binary patch literal 313 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9Q!3HFy+4N(86lZ})WHAE+w=f7ZGR&GI0Tg5` z4sv&5Sa(k5C6L3C?&#~tz_78O`%fY(kbln8#WAFUac#(M-ev=l8a6fqpM+|rFpuem zLCd^n^KEi;D>xN$lI<i%jzE6G^p|stxp<v8r2VYER9v#Y`_tWod1;9D(mxlNQjC?t z-`6r{d9lW1T;Nue@^W3pA<e~8bnFIqYOlpw!)H!{3BpS39d|T@Bwda~O}uxpzMA#L zfj%Jy=2*k5040~khq8-oKLj^hSw`t^KbZ9V;o~{Ki_X0lxZQkw)v6g=zxiex$ebuR zpY-fgA@jR=sgYh&mP@4n3^DFd)N-%9r;@fK-+TT<`Gs#28)|;U1_FJ?;OXk;vd$@? F2>`=dZ0G<0 literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_cont_area.png b/apps/fo/public/images/map/toolbar/btn_cont_area.png new file mode 100644 index 0000000000000000000000000000000000000000..044562b5548f28a1b6bc893f0f12889668ccf63f GIT binary patch literal 1231 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;=WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2v2c=CaI?h>{3jAFJg2T)jk)8oi3#0-$aN1{?c|g2d$P)DnfH z)bz|eTc!8A_bVx6rr0WloBA5~7C5J7WO`H;r3P2|g(O#HCtIc{+1n}DR9FEG$W1Lt zRH(?!$t$+1uvG$^YXxM3g!Ppaz)DK8ZIvL7itr6kaLzAERWQ{v(@i!swoov))H5`- zv@kN!Q7|$vG}AY*)HgKIH88X?u(UETRDc2{plwAdX;wilZcw{`JX@uVl9B=|ef{$C za=mh6z5JqdeM3u2OML?)eIp}XpbFjM%Dj@q3f;V7Wta&rsl~}fnFS@8`FRQ;6BCp2 zOG|8(fG&l2A-BNS7jAG~F*KlnL8f1kSfFpHXP}>(3-T9Ob#X~hD#969RTqa;7NqJ2 zr55Lx79|7YBTX5m85nl>EdnV7y2i@CC=(bdi8(I$$)&lec_p4Mwn{)5y_C!ps}w`? zM2n=P6kVfKLsQ)}1Cume%QO=MU86)xLo>r<izIU+GnhHp^gCO)x;Pt|xtbap7#kY8 zT3T4RIl8!67`r%IIs-+VV0u0Cic1pnl2c)JX9Dep>UF`Z*UGslHL)bWC?r2W2bKx~ zGV)9Ei!<^I6r7zwv2L!Q5uTZsl3!k|35q6&uU%4$GRsm^+=}vZ6~N(am5Id-#Q7hh zKZV@z(+4_AACy>-5)VuWm?A+;cvb*%;F&2k5150BfLTRg#qQ_8Z1&#M#WAGf)|;u0 zTulxlZS#|^d+c^zyGVJ*n$WNi^%dR~9Xe-IFD~N?Xz5;|9l|wN`Ir2jgbY(=y{I1# zq$TJ6|Gx6fdeOGTxgBB)nAat6%v%!9JE1|$qIqSrB9rL_R^ts!$-akGE3|L5@ZMg) z&bKLp|J{=KeT(jHe8_v|Da-w*DK{3b+IvHSX{qtN{sYd!aoL^I`fJTJo;VlqI^=!W zu`|QNhHJLhx>FmB{)jt^A2Et&KJW0pvrXk#3}1VQ(uwK3a?&l%OH}x>gUxcL$;RLG zXOTU4WPx+&Y)hqQ+|uWa`xHK0GU0hLHFy91hJFTShV5VNS(87zZ37iCp00i_>zopr E0D||LWdHyG literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_cont_area_on.png b/apps/fo/public/images/map/toolbar/btn_cont_area_on.png new file mode 100644 index 0000000000000000000000000000000000000000..0129ff1bd3273c695e41f32a12126067b2db60a3 GIT binary patch literal 1184 zcmbVMTSyd97@i8kq>UbYD4`n0hpuy7*PWT%OlQ=VT9tJpp@L>-&g!HyXPh~@qg_Zb zRL~xx%R>bgk#9l|Mj&BgbR{B*uH-||O9l00f-jv>*LskM24>DV|M|ZE{!f2hO?4>0 zFrOfZP<)@7#A`wD=B>ux!TwDlylh034X7SwP*!sRQEtFAAmf(S2$DcEI$EEAQi533 zZl)SgL*js}LyOS@4C7l4W)nndneS+NGeBe-G@5pd`aU*Jk){!&4n-1N!cjnzxv$d& z^_?{-y|Y=D461AoS?bGJfd!C8`c{kW$$pHQ*DK?FAZ96Y9)g-<)PhqDi8@k&E+8XJ z39a*Ck&H?VACW|%co!*fd<n}*EMH7>yv#{5$CHZ>g{`?pMoy|#i?;A7Ml~Vi$Sj-9 zW|?f5fo>zqOOnKL0xJkKM$le|jWnOOy`r236?nR9I>>}J8EDkfunom1?CC-XmXk;< zDYm`EMB$XNzUHtz!?BhX#5IrhP!jxhV_CG9>Tm#?1RiX2bzF~3QI3pr_jf}95PKun zx+X4))}lha%>p)xt1$}SFotQ!1|QYLblRW=z(?o|SDc}xOfg3bn#7mzx|og%B{@CI z@fERBRfMPz;khu+S4yH-RjyWvVO5b7EUCzG<F<!1TL(GYCbqrE<^Rf+6&Gj-x+w@- za$Qi@1QGO_phGH3Q1vLe?T~33Fzam(%Cr!*3S6@t7*#H`$oV|W<}yC~Tl@=r<A3wV zVyD=kS^j9AoCtShuw5Djd{`PLVB-mL@u<w~iH_niyB}A}Q~vvJ7qtBDz3b0bKRNt( zWO}&%RY<PhbbZ}aMSt(pyyK^e;LD*cBO7KXyI!2V_%pNN?bhiNt44-aM7DJe+`M_~ zdT;zkD|NoBNIX;U%{X$@Uv1quy7}0%bDa-g*Ue3>X%@#P%uhY1hn~NB*S&k};85RN zt$c8}H&nKkP4v90wRVKx9KT!0OmL<5J{+lKdnOyxC$Eh?{xW)H{K4g~SLgDk&dv3$ u`Mm$x1!ti3WA*0SlUK)1OikWdxt3_3o_RE}bM{j3&xlvns3R4}x_<#K!jWYF literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_cont_next.png b/apps/fo/public/images/map/toolbar/btn_cont_next.png new file mode 100644 index 0000000000000000000000000000000000000000..075111dcfaf770c5efd87bc215f87dfd915ee454 GIT binary patch literal 1256 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;=WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2v2c=CaI?h>{3jAFJg2T)jk)8oi3#0-$aN1{?c|g2d$P)DnfH z)bz|eTc!8A_bVx6rr0WloBA5~7C5J7WO`H;r3P2|g(O#HCtIc{+1n}DR9FEG$W1Lt zRH(?!$t$+1uvG$^YXxM3g!Ppaz)DK8ZIvL7itr6kaLzAERWQ{v(@i!swoov))H5`- zv@kN!Q7|$vG}AY*)HgKIH88X?u(UETRDc2{plwAdX;wilZcw{`JX@uVl9B=|ef{$C za=mh6z5JqdeM3u2OML?)eIp}XpbFjM%Dj@q3f;V7Wta&rsl~}fnFS@8`FRQ;6BCp2 zOG|8(fG&l2A-BNS7jAG~F*KlnL8f1kSfFpHXP}>(3-T9Ob#X~hD#969RTqa;7NqJ2 zr55Lx79|7YBTX5m85nl>EdnV7y2i@CC=(bdi8(I$$)&lec_p4Mwn{)5y_C!ps}w`? zM2n=P6kVfKLsQ)}1Cume%QO=MU86)xLo>r<izIU+GnhHp^gCM^TbLSIIGY+87#kY8 zT3T4RIl8!67`r%IIs-+VV0u0Cic1pnl2c)JX9Dep>UF}a*UGslHL)bWC?r2W2bKx~ zGV)9Ei!<^I6r7zwv2L!Q5uTZsl3!k|35q6&uU%4$GRsm^+=}vZ6~N(am5Id-#Q7hh zKZV@z(+4_AACy>-5)VuWm?A+;cvb*%;F&2k5150BfLY~bPEP{^10#p0i(^Q|tu<FS zW*rI;IrdRyM~F;~aQXK|d|e722Nxy_%49Q#mINn>N3ZC1ei^{7`6A@V*}d-{Sa*ot zQhNFSP~oK;Et8q;naocf-#e#T`1bc&?Q>ppq`uhXpMA>vwpf4nx@wbWEH=OU#M(Ao zHC{67$3fdkE0Wi9Zb@m2{-W~5$|vK|{NJ@TColQFn0m%$!yJLt6^D4eW;}M1&dAd7 z-gksO=$3=`wm{KHor%}jX3bjI!y{J6A}95drPL-XA=K=zI@c|S%TqYRP9!eoG*N%* zY87+D@AA`Vo8&I8eWt%RbhGbS)E0mC;^%^PK`D-}4|!%iT-?IDsAVqqnZ?Qb76u;j gxmoz1=^u*(!|k7D<}HQZw?Ji&r>mdKI;Vst0Kn9*5&!@I literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_cont_next_on.png b/apps/fo/public/images/map/toolbar/btn_cont_next_on.png new file mode 100644 index 0000000000000000000000000000000000000000..4fdbe3a00fb71d5b25f39c13621271dfedc57ea6 GIT binary patch literal 1204 zcmbVMTWB0r7@l-VT_bB3ZBRo)j}x>C&TVg*8M4i0ce3pUCt0@(38I*}oZXDc%o%4+ zvXeY%YcYA~OH)cKD2N~kA&5TKAf{VrsSgSZifECDf=?1bQ7ptW$!_XHDB{4(Ip;s$ z_uv0nDUY9u_4M^n6csC-Rw`sY8otrP<a=SIKSq`(@aPmigKD^;d5{`0kq$x0*6OeV zHFNQ`TX2Y?A`4b^3Qwue%LcMpEyS>a?GiRc4GjmbX3RnibXd2XEdA@X&uCzoS$Z<9 z@~T^aGuG)P51v^XuNq6UhGf#iC&5r469qQJ8VKw;$CraFy{lIy`%ui$U>AaCv-F-* zQ)(F$kOx7U%`k?L6v3dx3Ta79q@Du_UdV8~#0e>e7i3<Nc>%N^nppG9np{zeZCm7& zrDrg9WsYk!8f+uUBCpN~k|c3_f=eVAf?)hb2WtW2_yZjc3iJ)na<PRR5NgzPG>@}1 z@pLZ)+f~(l#g5-j6iFEuXf7wPJZIZsT)Su=SKvK24n+IaMHg}v=%abhAoZvXbjT!k z_cs&*i8u0uXOW_4a|$x%ZRp^VlBLNFYg(pk3WJ)c>n4+cLYk@ZsTw2IQaqE;Bq1Xh zqCS|&bo3m=FNo5Jl1h)J1wJVVqmn2VN0g$NR0>joNb((S$?>t~7_ej8BDULH<-T0G z;6V)|uZqxIrwht62qS+6xu8%8t3C*xnY0`eHT-A8GVMjJK+jr$X3;}7*v+$S9pJ-% zi+_)A{@?s@#3?RpmVY%*M?^X@-0qJ8IqVM;bjSpGWK>T4v2mP?S*xUsRD*BzyE{9> zk#yIi4{!gS`!0WZ1w5vI{{7CA(}&{8t@63vA6Mtj_sI_}U;R)6(aC)5<^0-v&2Qd* zpt<vU&>#Qgh3mQac=y(D?$g+^6hcl#wh_2<q&d{$<8MaZ`13^kctr1d_3`NDyScl) z%M;V9b$Z~Jk8{c9E0sqw?6JeY|E7VT-*4UC{_@J5?&eFEiepcw80V0_Ft(~b*!rk9 z_r;jCx&Bsd<FD4urFY8LKe$-g`r+c0XnJk+#T#F%VEw6quabP_S`QWFDfQ@2TjKfV QX80c|jgBkp`RTL&0D6XtWB>pF literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_cont_prev.png b/apps/fo/public/images/map/toolbar/btn_cont_prev.png new file mode 100644 index 0000000000000000000000000000000000000000..7e3fae7d2d13bf4010b8052065c1d8021ce24c64 GIT binary patch literal 1265 zcmbVMTWs4@7(PwLQaZAQsuFB4>BxP6YE68}rMB0Qi`|kiQmQntAdNA{K50zr%WSuC z`;<)6lxpe=Hwl5bOq=#L7}`VCMna&z0Ai|y1f$~tRpMd1pi1z-P35?43J=wUuw<We z{_}tT|NS>FjE_AX>^as000`!DViB)>-rIc;e-{^y2k~;$87VsxM%AfH76KW?s34fv zq)Ajnk}`Mxb2JQqe^xD(opRw>UN*Fd<mp6Q&BSN`hEuL7$y3OI6*Q^pN#f^~PY9?g zN#b<8Kov{@)zsX)g(l|5O7i@a%qc|bDLCx%*nox{3A);}Zu4%E*tW~#y(cCKxUJ$$ zC5atU<-#}=3=6?{BoUVBC<}+U2p#8GCN>BeicXLeN7At{Me`KLQ#9Ot2<**Ls(eu# z-Sve}NuuUBCQp*}dOcE)Mht6`q&bcwDTZX2FxCj$bGjqBVcqWUSP+pdTdL`(h7LW8 zQpK2Yk_2YD6M|+I3VViidpA)yWuz;aBpsnhP4nW~*0!A@`iI88+IDHqL}U@!#*8K7 zdQ|&6V4S=AJMt7U8~!;<#YK^(MMIv^knZHgB!O=timLDmJtVP}iV|iJ9S>KjST)R5 zV^o-tI66VgY-NZ^bnNVh7uYBpXV_SrrlK@G!m;dVMjU0MqQD7QlI>vgy6s51j5@wm z>|0<dIup;{AIl3Ck{rV-8OC&{3&v}PW7svrgo5BzeF#2zTGbV!ZVz~6+KF03mO6`+ zQOnTacAj~49}fR5{vEvXfAdFTQl!@`|7xC&2zR8n-5Ujb*c&FK;|a3xs03Edz70Uv z!+9}Na@Q+=Zf&Lf@vcLOPjBBI%l^LJWIt-R&-h=uupkB~-)0}Y0XE{|N+@vd;KqyT zcMhyBroT@wG~vwU2HV^Evbl8mDkb`-)9v2YUrjd9y8i0p1G&bb*0;W!Cqmc3=J3ar zqdjiJjfU=m^MfJsiId-fCI}h+iVP1wuo3LLCcrygtIKQV-OMw~pS^K-EBj+P_tn7C zL%$r@h^}=%c<oa2y~ds6ts|NK{x^&M%ny%+{_t(i!n0uY-s{J@eW?cf=uf}iOP|T* z`HRh$*9HSj`$&sxE-m)@rJL`9;H4L8S3bOQ>(+09)wjll6CcdAFZTK~pwxaOGto?a h<9luWd5~^&fmhyVmcKrA@(b@Llph%rZ)DG1_#0wKobmtw literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_cont_prev_on.png b/apps/fo/public/images/map/toolbar/btn_cont_prev_on.png new file mode 100644 index 0000000000000000000000000000000000000000..fb2d55cfd501dd6992eaeb156d36d47badd017a9 GIT binary patch literal 1223 zcmbVM?`za%9FLx8X+1VpH?6wvX=H4Q`FYJ<67K9>lXeEZdR&ir@ASFkxn8c#50lhO zI|r*2SH*!i26Jq%u@^%I+cEa8ibD@K+5P~LF<6HPLlIw$6%p%`w%6@Nk+DGXJkR&} ze7?WGIa?TcE8e-YlOTw=c2F(ibzAgyY{uUY&b}JQOHVLV4o017(10Eya)whuK(pW& zDk5l1ow$Y41Q9!FmdZgne^}NXi-r+~4lNh62_iiZx=<fS0jQuc)6S3&=dY2#G&1B- zA<yPr1=Y-h(;ga~9x3V5<GN&!0|!7ll(7N}1rUVRgzd{=hFsPw<9#G%NU#hE#xvxK zQ{{XCD2|7KKqo1kONbyP(VQTOeE)vHvs{v4C5G##SWadondQLhLt<;5QI(78@Tx6* z%8<1naAk&RG#YdxK|9_U!%33Fusp-_6h=_~lpVm3vi&`64Jz_=&vXORu|cE}R-DNo zLt;-?La^L?eoe9MuO<qoj0vI3a5T$URutDV+7F88A2-%T`=u!tF-7D%lb(+2QQgxf z<J>*pPz1!@$VWUA7X?nJjy`E2JJ8e&iEn7bG-QKIL9tRXC?0VFRb~6DlvM3!DIQ8( zlGDXXichxntjAZxgedT$C~$0o<Ax+r9L}l3VnS6U1xp6oT+Q|aXzQqL+r+k4xvA%J zWyM1<aJ-V^Otib8P;&yuuQ@JIl&I<{@a9p|Hk^jPH!9Og)GG4KlgJqM91ASxSvJ@4 z;lIVd!Z-eJ{ut~O6E(}fnx`$o9T{!cMgbqzh6&ktf;>Db_qx9f@tEDy)LbdNQ+cwq zG!PRubYFUWXJ&Ep+dUV$v>(oA({~3peSdsZIR}5qrnlG2F?zDK^XA6Z&!3<9==ae> z=ix;5O7Gm#h7-xYzh<}ov2o!+_Q{sH59c1m4`{vMw-;L1X2grPn>SzYBU(ScxA?}3 zTP|FD$<;n37QW5i&sDy=eyO=M*q!ORrS-m_Kb1YT<IlT=df4;IjrlLQ-G}0_+{dxG zRP50)F!I%znda=(&QF?Mmm%2y8gsgObzgl)$MwV6bgW+6C2XC2`PjP!<(=l`KH;;O pbAOZI>894x+uPXUd?(St5<l(xx<0<}>tgh4(S}CUZw8N_eg*~&k`w>{ literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_cont_print.png b/apps/fo/public/images/map/toolbar/btn_cont_print.png new file mode 100644 index 0000000000000000000000000000000000000000..82596b83dde3b544f18fe65638d86932645748fb GIT binary patch literal 1318 zcmbVMZD<>19KWV*)}|@RUT7P2_1O(uUwXN_yft?uHtAi{hBa-?g6k*k<?cyxw0D=@ zU6!<daP638ML{R%eEBd@_d#S6hX{(;Nt6l$2Mz=gkuv?DA4b6`gRuHs+f+Z4As*a4 z&+~tNzyJIH&Q48?b~^5JU>Me!9OKhyJ!HLYcJzJm?BPzdc+8P$^SG8X%YqKExTIwv zNGd`erlBA$%zpzT7}k7J&P<!rsc}}+6t7@mycMO0*ccWWsuTrr7MdUn^RgPnZ+-R! z4rD2cp9rR?RFQ)Pd2CUK#}_9u;^M5xNchm>AW~tG0tK1^s3>!)!B(R9mR=U^Eis9M zEr>ZA#kZZBPE7$$(;*0YLxf2C!(fo{(m^Kd3k(1sMTba=A?W}?(JaNV6b*JB99h$) z9Gm77JGRg%iWf|?$dY8aT=tgzUQN%FG{Z0?<s*GQ0wD-vK{bU6p&CaU8hB`kx?D76 zO$C-lA*+?lD2_bc4nZlVQoD*(V<%B4Wn@JtlC+m16~&5c3vHNb_>UWVqK(W#5t3<W zXeC`l^~fD<kWudLZO8&5Z`es)Mnw_kcug!RP&Jc$6h}8+NtRfN9u&gatVH-A9VBv8 zAV)B{07du&h7QqUI6LSIHT3Mo=a?Wx^E4l%DL+k*FyU|_&L_fto?|#98E$Zss$mMM z2phI#WP69p-IL35IuuMz&uH3QqYI`AnyDEDtq3^Is`?;!_=K!VTG@ESD${n<Jk;fr zP)g{U0=DwZ%6s_m-{RlqOaC{2Byx(hn&n^3(-5JKw6?pWfDXIE1XVOaIvSOki?6a6 z)|5!{@l551Y<+Wcs5#hlET8ZH^t|6a*_tic7B$;^$bD;scBl3~=)T;#-Whw#ReN^6 z=WA!}<*ASLSiSwVB{p`=RrAE^r%!dbZ1a)KxAb{%@D03YbKm}}x0~Pej5{;-ckJmS z0w;Sw=uBUeyX~Q?&QZ|Sy8d0P-XhJkxyk4H)}M~md#m{aa?hA@#C;`x@R@<NRd3<R z$KJmFNfca(*&nrS^aYYC=<1(YJqGTs)b_pp#5LRPzWdMdksDwA*y5}^hzGic?*RYZ zWoM+l_DigOxawJ|u<p|<7v782U6a36m)`%pqjtgfp-t*qTQ$K`_S)!6fj?{;-T0Ru z^j2Nmo$ga%hxBs^gj%w_g^iM@+TXn4z*jE+b^YBx+keGwuK(U~==u07DO*$bPiHQE ipI=*k;l?E!W^-Z#L}L8F&5t^)KUZ>Og1<C8v-~&69jmbb literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_cont_print_on.png b/apps/fo/public/images/map/toolbar/btn_cont_print_on.png new file mode 100644 index 0000000000000000000000000000000000000000..bb7f27334a41216292aeace62cff014e357992b9 GIT binary patch literal 1293 zcmbVMTWs4@7<MmP)6%NjTGn=D?9}5jq&dDMZelN4lg7;!Y3V{1X%QM|zMM3sjcshV zNlT@*)rQ)!O+`FRbV#eXNPxru33vdB!br6a#uH4McnakSAvSoK`cMeRZBuxtCWIyX zob#Xm`~UC1c_z_+q^V&~1BPKuv7<r~t*y@M+K#>#XZALsrNiz^+b8slofl1rg%w?b zAeIvcU=oVT=nFSt0K;lV)KuC|$B*%{o^y+ij=PXE5E{b*Jq1IQ2cZolIG}1l{NCpa zI8c=!ev*w-aU%k=>d`S1o*3&-$zy{ur{Fz@L7>1R1374mppYBVEWQxL*X;6W?}$kp ztf|<8L42K5I-UR#-GqR3cM~%0@dF>{rdiI<cn<=GqPt0oBWW)|(LBZR6b&{W9C<U9 z44)LD8@|vfh-Yov;7Kx{&%5&;w{8xQG{<oy#gGg`APvGA)oigqXx9FU1p!*JsT#Jb zYrwH6O8T%J#1Yf=5OPL5zG+yqHWGzWMixYaq}>#m%Q<naX<K#@{zGF+Z7VfuKr#s} zeb|&yJu>?%V3fNDJ8~2e8~(VdqN0dHf-Vo|pk~K}AdYU_imLDm?Gycyq!0|GSt3Ju zGX$6MQUoJ%bT=*gB_GpWv9lFE!uflnz1}cOQy!Y`<NW?;Scv*PLWGMTNpA%k(=1!m zWLWX7BHs~?rD%bn9*E^5CKPSmOzHYir3(^S-PWzFZh%O{sk#pwIH_uip0}QI%CsJ} z08MoSDp6C<fwesI>J}XSTm0*I<^Sf7M5IWkS^m{L6%p!4XS+EH=&(6VP(u@BqEUHs z;c*?qs)(2nP8EKXR?Fp{8n&usH$4Eps4AB0OPz^N4ovL)?%a52)iv$I{xHE`FMr*2 zEA&Wxu_|=1u6VV?fSOl6ynV)13bovLiJO1^{n^FWjM}f7@u^?yK0Pf<^GrKCYkpb% zHk`QAIz2qUn%H&AsFj`uhntGWL-mJhm(q>#;=+>M-s%15#?-E#gWzr#-qms)c<xS~ za((mS{m{7UW>f>apDew1Ikfulj9yo)3qMh=mD(P=vOKx+?V0PPhf>6`eM=X5K-<)* z`z_O*p>x}I+^b&h2hTMW%fG*MsU5g$BwzNI?_I^$!K>`#N?`7{fN-{>dG68Kj=819 zw&sslK5HyqnJ8@Axp;Y>_ua|!ACPy>lRHMXFCP-l{<Qa<XIlTf@WZugthx~!fA-QF T?mf3z=LZ$*>ld!|o}T&}$DFMw literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_cont_ruler.png b/apps/fo/public/images/map/toolbar/btn_cont_ruler.png new file mode 100644 index 0000000000000000000000000000000000000000..501e460a4d0f36061b18320b4e6306d110d79d02 GIT binary patch literal 1353 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;=WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2v2c=CaI?h>{3jAFJg2T)jk)8oi3#0-$aN1{?c|g2d$P)DnfH z)bz|eTc!8A_bVx6rr0WloBA5~7C5J7WO`H;r3P2|g(O#HCtIc{+1n}DR9FEG$W1Lt zRH(?!$t$+1uvG$^YXxM3g!Ppaz)DK8ZIvL7itr6kaLzAERWQ{v(@i!swoov))H5`- zv@kN!Q7|$vG}AY*)HgKIH88X?u(UETRDc2{plwAdX;wilZcw{`JX@uVl9B=|ef{$C za=mh6z5JqdeM3u2OML?)eIp}XpbFjM%Dj@q3f;V7Wta&rsl~}fnFS@8`FRQ;6BCp2 zOG|8(fG&l2A-BNS7jAG~F*KlnL8f1kSfFpHXP}>(3-T9Ob#X~hD#969RTqa;7NqJ2 zr55Lx79|7YBTX5m85nl>EdnV7y2i@CC=(bdi8(I$$)&lec_p4Mwn{)5y_C!ps}w`? zM2n=P6kVfKLsQ)}1Cume%QO=MU86)xLo>r<izIU+GnhHp^gCNvI=Yyc8JQXy7#kY8 zT3T4RIl8!67`r%IIs-+VV0u0Cic1pnl2c)JX9Dep>NUix*UGslHL)bWC?r2W2bKx~ zGV)9Ei!<^I6r7zwv2L!Q5uTZsl3!k|35q6&uU%4$GRsm^+=}vZ6~N(am5Id-#Q7hh zKZV@z(+4_AACy>-5)VuWm?A+;cvb*%;F&2k5150BfLZ0vpQ1np2F6TJ7srr_TWhYI z*JeqSIsS30b)C*9_JBE477JGwK0I>P_2l}=la*ZGIu;ffu%C*3<giX=iOe4hkF4zP zhZ>o;2Aw{5w13m>iu%`!)67?woe5t5?B&d#byf3bzR#QbymF#J`{P~fVv}zi6i(AV z6XDA37SN%UBVK!hXTwU}t5I%e0#68hGf<e?m(26{GLvxB8<*+>;o<AE4_z!fKf&4l z9&?NAqHCMp$fjNF4%@+4w!O(LHAPm}Zh<r}Bh&Q_YlPio?)SzV_+B1=rG15?knR6B zFST!HhV)vt^6dK1C}MSCMdjujd!oJvRb9)vByo5bYhSWdaYd-TTIrPFvzL=TE8q2g z6}fumaUM6_4V?Xoe|qK%mV1eD|M<E6#<8>dt<Nhi-U;@-=>D<a@lNKxhtd1LipF*H zGROQEouOGgXQ|Qa{H3NBJx&~E`n-Z$@wCyWvM1g;EB5bWYCF0yBR8#4_!q-(E?%QG f2mK9x>K<SS^b7ni_1ok>sBrUi^>bP0l+XkKb|K|3 literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_cont_ruler_on.png b/apps/fo/public/images/map/toolbar/btn_cont_ruler_on.png new file mode 100644 index 0000000000000000000000000000000000000000..676a81bcc59f2fbb3855cc73866dbee66b17836c GIT binary patch literal 1339 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;=WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2v2c=CaI?h>{3jAFJg2T)jk)8oi3#0-$aN1{?c|g2d$P)DnfH z)bz|eTc!8A_bVx6rr0WloBA5~7C5J7WO`H;r3P2|g(O#HCtIc{+1n}DR9FEG$W1Lt zRH(?!$t$+1uvG$^YXxM3g!Ppaz)DK8ZIvL7itr6kaLzAERWQ{v(@i!swoov))H5`- zv@kN!Q7|$vG}AY*)HgKIH88X?u(UETRDc2{plwAdX;wilZcw{`JX@uVl9B=|ef{$C za=mh6z5JqdeM3u2OML?)eIp}XpbFjM%Dj@q3f;V7Wta&rsl~}fnFS@8`FRQ;6BCp2 zOG|8(fG&l2A-BNS7jAG~F*KlnL8f1kSfFpHXP}>(3-T9Ob#X~hD#969RTqa;7NqJ2 zr55Lx79|7YBTX5m85nl>EdnV7y2i@CC=(bdi8(I$$)&lec_p4Mwn{)5y_C!ps}w`? zM2n=P6kVfKLsQ)}1Cume%QO=MU86)xLo>r<izIU+GnhHp^gCNvI=YycnVA|I7#kY8 zT3T4RIl8!67`r%IIs-+VV0u0Cic1pnl2c)JX9Dep>NUly*UGslHL)bWC?r2W2bKx~ zGV)9Ei!<^I6r7zwv2L!Q5uTZsl3!k|35q6&uU%4$GRsm^+=}vZ6~N(am5Id-#Q7hh zKZV@z(+4_AACy>-5)VuWm?A+;cvb*%;F&2k5150BfLWz0s;Q8Hfic?C#WAGf)|$&3 zy$?Hx9RIjvWzuR3D-TCOmg$RvUoNP3Q4hROf1rNB>}~}<rB|;ODZJ3y(G^u7z_she zf*`9M5sooh8BhP%{pHLod^xk(|5MS)>Yck|oSw%_Nb!Ct^N>MW&h*+;>DqY1LmcfH z3i-<Kg5q|DDRWuA2`UfF-}!0IOO<CEraub^c`kCymOHIf@79FkiUX3H<bt=&3BG#b zZ&}}hw%q=v=u=yz93^g>IlpjUd-`SHqE7YQ9Fy<0e+#S%Ja)!DJ2pvmY46UKY>^Lb zT51LhDk5~=UEI5Bo^Hl&-Gs|xUqv@ZJ+OKv8opswMZAvQ>$nB!ue-c6ZgH@GoN?fj z=>*U6lDb>>SKRow;I_Tc`HyREXfA)d_((M8_pb7!zvUZ`aBnPYnZ1qc-E!aRoELs! zhnF_B%ofdAsNWbBwm7xk%k}l<HvaQTk~)u%KC^2R-edj$+7ZLH{VWm;r&CW{?P5H2 Q9aNloy85}Sb4q9e07#175C8xG literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_cont_save.png b/apps/fo/public/images/map/toolbar/btn_cont_save.png new file mode 100644 index 0000000000000000000000000000000000000000..c057b93776b36b70313b5336874ed0afec64e62d GIT binary patch literal 1216 zcmbVMOKjXk7<RiPfrzC6A=L8H;P%jn`nfOLjmd88Y<49!M4J`a8}VZ{>n8RXd(w55 z(k2z9?E$GAsKPD1Re^HqrEq9zw*^Ec#0^Cps-Aj4l$WANaA2Hd1Ba+WSh8p4pYQwM zzt2yMk0tw`@24m#SuW{SvOXKXkN1-A2j^c(lH~v%t>a15z%3(yRKZ3j1ZCHlfmLYO z3vYh|hbSs>+^N-Zz4E$ZA(u5`3>&#VVN=x5aO4}-EX2TsGmfXy55Krh1IJeBsZ52h z_!?|FrFH-(+v7E>J!{D}J^UINiWH*2h1dX*JLiQ;q|%#u6|#@T91S)hcvhvioT^tQ zfQAAHGHjNygp>qwGAm?cNlYIBA}?e)Ugm@}!wU*8E4%=<ADUPT?1oa+i`%xyNu`?@ z`wGXkS}nGfVo@-|39>A6yvT_nLl8{3;9(<TyzpRGgAPM0aD40_55yV`6U}3lCZ2AE z;QE!yj$$v|P83NQ7a2Y$usr9waa^0|5Le+pZtRK<YYRT)sxU<Jfko=kIM^kV+&$V* z3?$wtZv+l0iZQ1nYu<$(F6$~yZdlu~6<f#|l4;tE2!#yO;L{C8ZlrleG-M$wSdy6& zvt2#A@il2w*Th^lBk(Cf7?mZdSkQ}7O4nqKNJhHcvKL~*vtZY@Lu_wzGmqpdS^y1< zf*L||-7c7DB8<W&@`0wsRnLLLQ;uh&RyY`!X)9_S2F`J47X##i%{(j4E<XIX__z4> z|IHsqoZ{kU`B(FFMWiF+?anBW!_F{4k4#WNMrCFBtB=T--7D*bTC`^V^x(k-YkGP) z(OJ*my_0`=qo>oiB%SFg-R&{o1nYff68zj}PSMG=Wamu&MB?1Hi_t4z=Z}K*-ur6) zubx$Z-&2Vnmo}arcx&vLqlwPg;>Ny#htsFqzxRE}uJ+#F|6%}A%O97Xe6<Mfd~&vy zxSsemccQ;uO7nZp4b#^yt}LBe`NIY$M{f8FX|<kw?Dh|}=5ODFo3|$~wSW1XKfAQ| zMkf#XWA{qJKuroJzC3c_z^TF$e-2!&n}zR+hp6Y8d*0dKDZPJj?S;Y1dr#h4r533K Z_3qWdOUK^3@@f1}DUXippN&kP{u{A?j0*q& literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_cont_save_on.png b/apps/fo/public/images/map/toolbar/btn_cont_save_on.png new file mode 100644 index 0000000000000000000000000000000000000000..bf8e6d6236a85eb6a22f755282a2a965201ea917 GIT binary patch literal 1202 zcmbVMPiPcZ7@tiWlj;Ve6p6ONb1YJe^XE-=lbJDVb~BUcLN^KPin$arJM%U>CNpoG zd2uH>)Tkg?P@97VJ+#_VM5%}%Jrql$xQ7UOXekJyqTYI`^&rGc(>F;r?IDObF!SE~ z-tYJQ|E4<Fzqe)WmbDDSv}E_`dAfcWz0GUr_jGk@3tcvo-XXFdmq^9%5tFfS5rM2@ zjG#O+tck;SQ5VC!cf>9Xk)hn@s)-%mh%kKUc$CdBUEQH)n4^e*A{w#X6#L@lEDLNa z#U4!N#GI$0vb}H8NBbxH3+CjgsaS0H9?%u4RDpwt0YYcY4b(8jF6ve3J`xKoScH(# z6uacqP;L-t*he7AcW@?bmqDk(!=xfhiCsVvVTT|p0!(lsR7FJ<Ay|G`YR$JwYF_VK zwna}VwoHhp3PPn);VbPt_D2M$D2gCTf+TSi!37g8F+$D_w%0Z2C@_87BQ|zHq|qqi zagt)Gr%NF?UM{zy*bSBwMN=k(h9^K?6dWgtYY`ogJo?X#Rnb9V!b3tH1$f*yX+28Y z>tvd{Hyet8)Ejlcw`oy~F&&%Z4suCWPqFldw`@zbV5cD$ixwv#nB+=gqQohsgvd#T z0z0577dxenx}MeenvxWu4wWPn+ac^#WVtV+_sQ+Lrf5{sQ|D&gfEccc>b7ladzmZ0 zk*jJxG6?ny7?0JvV6cn{4$9aAnif^P6MTBmb}d{9c1C4didsj$eFRy3K6b!jo>hAl zAKothCBF5p`4gy9Lewn(Yo5A@c4V|&83lS+87Ab?3G(Tv+#teFbj*Iw>X}0LusFZ4 zF#B=qi-zYH7Vb86e^;7=4b{i-c>HSmQLMHl{b+sdTD%sUdC~)Zjnz>4-W-#B+&G;X z`{?rNxO{zg>nQtjL3<^p@6X?PKk;?T^wHKozdr=d+}_qCoj6}Tmblei3t!C~dRhVh zoE(U)tFGC>yxjZAgN=#5*Ps11UK?m`<G;Gp^y9ISsqnMJ>vHR}=T`<(;TPxbq+`Ry zi&9(C`=M=q-L!Ifc+=de+3O9P&fePn+l>t$Of~*I)p#IwbLZ8DFEjUNnwmxC!M4}m U{IcV(Kcc@#wzpru)-!zkU$H`pp#T5? literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_cont_sketch.png b/apps/fo/public/images/map/toolbar/btn_cont_sketch.png new file mode 100644 index 0000000000000000000000000000000000000000..38a5f507f28bf136f1e37f4094f6331d3e13fafb GIT binary patch literal 15103 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 Jx~^sC{{X4+y>I{k literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_cont_sketch_on.png b/apps/fo/public/images/map/toolbar/btn_cont_sketch_on.png new file mode 100644 index 0000000000000000000000000000000000000000..79fb54e0317a2ac148d5c32b46b6cba4c8aecc13 GIT binary patch literal 14933 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 literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_cont_zoomin.png b/apps/fo/public/images/map/toolbar/btn_cont_zoomin.png new file mode 100644 index 0000000000000000000000000000000000000000..ac32fbab0e40672e44a693e84bcd96418fb29c4d GIT binary patch literal 1456 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;=WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2v2c=CaI?h>{3jAFJg2T)jk)8oi3#0-$aN1{?c|g2d$P)DnfH z)bz|eTc!8A_bVx6rr0WloBA5~7C5J7WO`H;r3P2|g(O#HCtIc{+1n}DR9FEG$W1Lt zRH(?!$t$+1uvG$^YXxM3g!Ppaz)DK8ZIvL7itr6kaLzAERWQ{v(@i!swoov))H5`- zv@kN!Q7|$vG}AY*)HgKIH88X?u(UETRDc2{plwAdX;wilZcw{`JX@uVl9B=|ef{$C za=mh6z5JqdeM3u2OML?)eIp}XpbFjM%Dj@q3f;V7Wta&rsl~}fnFS@8`FRQ;6BCp2 zOG|8(fG&l2A-BNS7jAG~F*KlnL8f1kSfFpHXP}>(3-T9Ob#X~hD#969RTqa;7NqJ2 zr55Lx79|7YBTX5m85nl>EdnV7y2i@CC=(bdi8(I$$)&lec_p4Mwn{)5y_C!ps}w`? zM2n=P6kVfKLsQ)}1Cume%QO=MU86)xLo>r<izIU+GnhHp^gEkdn3|dx8JZdz7#kY8 zT3T4RIl8!67`r%IIs-+VV0u0Cic1pnl2c)JX9Dep>NUWt*UGslHL)bWC?r2W2bKx~ zGV)9Ei!<^I6r7zwv2L!Q5uTZsl3!k|35q6&uU%4$GRsm^+=}vZ6~N(am5Id-#Q7hh zKZV@z(+4_AACy>-5)VuWm?A+;cvb*%;F&2k5150BfLSGky|Ijef$@T;i(^Q|tu<H9 zdxr!{9Q$}t#kb|;0fh}EifT=c+y_eo18>GJ=)R@VI74AaU{le>72KO!7fuWa>2}Ie z&Px+q>%DM+(9x+=_UA4-6LjP~_xS^FpWfm5(#mg~{_M{4d)0MMmjtbBSuGTERP@RN z1F?^M`X71hg$<{^zNI_ERa>n<_W8xe^)HTY$rD?%=fwBwj6=S6j>=#EE_kbudwt2~ zhdUgqH>Jh6SqaA9FJPW;xMI8K?*qv%9IxvoUfk6m#j}uW_C>=zZK*sgdOk^x^Y>X5 z%8376awXZsAnoRX#fFV$p6mazL?*D_+jXv0qmM=Ps$R+8H@mXz+phg=e{Iov$>aB4 zyXU6QZr*a3$p7b&-Zrbwn!kC8%MIG^uZv%~?*Hql>V*eOV~$H1Wu;$<EB|}$Q7?bZ zs+p^Jc>a{HZSZ+uKl_Z)o)3-N?CmprWqEX-OmavF+I_O@d=LK}H)X%aoP2LLt$54! z_=IEhorfPd(*u@!W^m|CRK8UvAJ`|n<IDQXX-@u@ZS4`4@-ul)Hf?*}z?7f;NBWVU z^lH()ZF4oAZ^_`^uqxoT<o+w$rK6>eGgruPotdUP@%jHkk2`@cIySj|5~^Nr*J`&x j@lL<P>blmlHyj2G@$%`K^J0^Cfyz)%S3j3^P6<r_QnMFU literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_cont_zoomin_on.png b/apps/fo/public/images/map/toolbar/btn_cont_zoomin_on.png new file mode 100644 index 0000000000000000000000000000000000000000..f258a965f60408424e573d9902e956cbd6e5518a GIT binary patch literal 1423 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;=WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2v2c=CaI?h>{3jAFJg2T)jk)8oi3#0-$aN1{?c|g2d$P)DnfH z)bz|eTc!8A_bVx6rr0WloBA5~7C5J7WO`H;r3P2|g(O#HCtIc{+1n}DR9FEG$W1Lt zRH(?!$t$+1uvG$^YXxM3g!Ppaz)DK8ZIvL7itr6kaLzAERWQ{v(@i!swoov))H5`- zv@kN!Q7|$vG}AY*)HgKIH88X?u(UETRDc2{plwAdX;wilZcw{`JX@uVl9B=|ef{$C za=mh6z5JqdeM3u2OML?)eIp}XpbFjM%Dj@q3f;V7Wta&rsl~}fnFS@8`FRQ;6BCp2 zOG|8(fG&l2A-BNS7jAG~F*KlnL8f1kSfFpHXP}>(3-T9Ob#X~hD#969RTqa;7NqJ2 zr55Lx79|7YBTX5m85nl>EdnV7y2i@CC=(bdi8(I$$)&lec_p4Mwn{)5y_C!ps}w`? zM2n=P6kVfKLsQ)}1Cume%QO=MU86)xLo>r<izIU+GnhHp^gEkdn3|dxnVK3J7#kY8 zT3T4RIl8!67`r%IIs-+VV0u0Cic1pnl2c)JX9Dep>NUZu*UGslHL)bWC?r2W2bKx~ zGV)9Ei!<^I6r7zwv2L!Q5uTZsl3!k|35q6&uU%4$GRsm^+=}vZ6~N(am5Id-#Q7hh zKZV@z(+4_AACy>-5)VuWm?A+;cvb*%;F&2k5150BfLVoUVPO~p1LJy67srr_TWhZD z)^`q+Iq=c@Rp=5q#g!7$hY~)pM+kUJO7Lt`>u8ywrRc-f%(~h@LRGEP)5)sipmO3T zsg4R4n^^(5p|7fcg!WCY)|ONMdFOWVuig9SRG)hvqdn6ns?CT+@KEii#j(k(cTa4u zd=}icD`Ty^aK!;3v%+pJlLfNpUmV?(dVR|q<BlYbn|#I^hfLxwCW}x0b+KP!)}_6D z%lJ8WSCoEy<azDvug1zb3a5Q6nu6P}e>u@sk@GKDxO1_u{P`5gznd5fXRCf&5c4i= z_Yte8uZ~kMwCgJ0=uOg{=>98D+0Qn7HUAEk9~U`n9F|_YKl!)lo?8_ntZ9e1A17X2 zHBtGoR;27XLE}eSPk-vK-_tFoY|vEQvQ&Or-I0!LmlHZ~_-?M%YIoXKcq4WHl||=u zX8YtM>z?J@sJ%S-jOE-ZQZ@;KmG@PG<@<RxUpXyr@v=Qv(4x1a_kj@4DWRALtaD!q zX)T>GslUal&pP7hK9zuzZmF5aQh0Y?s@)glD_Xc&Bv<d<27UF%k=@eAESMq;?Bn-~ yPMOITazFL&USFlgo8Nc+YnNQc^WcMT10w_1e61HT59Z$l6_K8<elF{r5}E-1#QI18 literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_cont_zoomout.png b/apps/fo/public/images/map/toolbar/btn_cont_zoomout.png new file mode 100644 index 0000000000000000000000000000000000000000..2ee0b5161a55edc8a023f2c3df15055abf8d3df0 GIT binary patch literal 1395 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;=WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2v2c=CaI?h>{3jAFJg2T)jk)8oi3#0-$aN1{?c|g2d$P)DnfH z)bz|eTc!8A_bVx6rr0WloBA5~7C5J7WO`H;r3P2|g(O#HCtIc{+1n}DR9FEG$W1Lt zRH(?!$t$+1uvG$^YXxM3g!Ppaz)DK8ZIvL7itr6kaLzAERWQ{v(@i!swoov))H5`- zv@kN!Q7|$vG}AY*)HgKIH88X?u(UETRDc2{plwAdX;wilZcw{`JX@uVl9B=|ef{$C za=mh6z5JqdeM3u2OML?)eIp}XpbFjM%Dj@q3f;V7Wta&rsl~}fnFS@8`FRQ;6BCp2 zOG|8(fG&l2A-BNS7jAG~F*KlnL8f1kSfFpHXP}>(3-T9Ob#X~hD#969RTqa;7NqJ2 zr55Lx79|7YBTX5m85nl>EdnV7y2i@CC=(bdi8(I$$)&lec_p4Mwn{)5y_C!ps}w`? zM2n=P6kVfKLsQ)}1Cume%QO=MU86)xLo>r<izIU+GnhHp^gCM^7&@9dx|kXo7#kY8 zT3T4RIl8!67`r%IIs-+VV0u0Cic1pnl2c)JX9Dep>UGAe*UGslHL)bWC?r2W2bKx~ zGV)9Ei!<^I6r7zwv2L!Q5uTZsl3!k|35q6&uU%4$GRsm^+=}vZ6~N(am5Id-#Q7hh zKZV@z(+4_AACy>-5)VuWm?A+;cvb*%;F&2k5150BfLUeghFoI?2FA&rE{-7;x7J)a ztL+jfar~pTk5kqXohucQ9zkMar)CKpi#HI<@!(vV=FG+2%$n?YLL|{KNqKhUiCKXn zT~~5W>}C}_^!>`>V=v=A9}1p7Yv#E>?<~*ne12n3-1>!~YEpsyNlPAc?T$DsG>@m- z>%zY64|(2lED{a<@PO&C#l-fR(`?^-wwQIX+i*`-^79L=c56-_UbdF$>Y1p3_J+h* z{uc)f)ly6uZ4J1cUvvtH#ZA^YD#G<q?A~FuI|tH_gxx*i*1JzrZ_TVPIzcOaZ(TC? zV11T+ykq^9|6N}k*yXl1D%Q;6$b1|(VOjnu%Q?3W+|fvXG3EdN84u-FJ&q}2-S+i> z>&=x-5{F|pO%k;Yn0ubNa`~i1JjEw6gO)!J;s4{n?6sj`3P<9rPd8e4=Y~x`EO;ug zt#-%6RlR2?B$s#CJX!E<`)xIi&36vytb4k>Vat=CzUBT*znA{cTYcN@>RKJ=yBbqJ zT~d4O=XCXC#k7sg71Qn1lJ4nz*!^y!%+Y5&UMu1^{V99=-c)I!@v7GUf-AB@oNVKn Zco=fBV?=8EXZ`~fgPyK_F6*2UngAUz``rKl literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_cont_zoomout_on.png b/apps/fo/public/images/map/toolbar/btn_cont_zoomout_on.png new file mode 100644 index 0000000000000000000000000000000000000000..58dcbfdae612b1145683f6741dac9b41edf52d0b GIT binary patch literal 1376 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;=WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2v2c=CaI?h>{3jAFJg2T)jk)8oi3#0-$aN1{?c|g2d$P)DnfH z)bz|eTc!8A_bVx6rr0WloBA5~7C5J7WO`H;r3P2|g(O#HCtIc{+1n}DR9FEG$W1Lt zRH(?!$t$+1uvG$^YXxM3g!Ppaz)DK8ZIvL7itr6kaLzAERWQ{v(@i!swoov))H5`- zv@kN!Q7|$vG}AY*)HgKIH88X?u(UETRDc2{plwAdX;wilZcw{`JX@uVl9B=|ef{$C za=mh6z5JqdeM3u2OML?)eIp}XpbFjM%Dj@q3f;V7Wta&rsl~}fnFS@8`FRQ;6BCp2 zOG|8(fG&l2A-BNS7jAG~F*KlnL8f1kSfFpHXP}>(3-T9Ob#X~hD#969RTqa;7NqJ2 zr55Lx79|7YBTX5m85nl>EdnV7y2i@CC=(bdi8(I$$)&lec_p4Mwn{)5y_C!ps}w`? zM2n=P6kVfKLsQ)}1Cume%QO=MU86)xLo>r<izIU+GnhHp^gCM^7&@9d8JZdz7#kY8 zT3T4RIl8!67`r%IIs-+VV0u0Cic1pnl2c)JX9Dep>NUWt*UGslHL)bWC?r2W2bKx~ zGV)9Ei!<^I6r7zwv2L!Q5uTZsl3!k|35q6&uU%4$GRsm^+=}vZ6~N(am5Id-#Q7hh zKZV@z(+4_AACy>-5)VuWm?A+;cvb*%;F&2k5150BfLY~7ZCD-y17m}yi(^Q|tu<G6 z>pKU^9Qe3c^P`V#l7g>JZ_7pb1V^3J1cQ?7CJ(J;UL2DTCLGk_aqIL<nlyng>4U_s zN*>b?mkW(sRu$FqFE5&Nr+Vkp={0$`Cg1=0^iFa8bB@!SS{6zcs(i?(J*Hb`*d;aF zGXB&P=WYqHi3iR43i`uJk~t!KlHG5#hSiE%`Yb+_$oe(np!BgfMP2qu6^`p~zs^t# z*l>D!znIPHT4A}I2V76n4n{7CiM!kx<004lYe#=B&uab&;`bi0u}fTFPdzBm=bEYb zymS^TbA^#m@FvEbB|Up&vc59fU*eGJ%-tW87;yIgwnN5WrvEr)>oKF(cFn%9-N)C< zgzc3ux_zu&_)T@jTn4?3?@EHKCL9!7Ri~k*-|u|&N~s^~QoWeROoAcOCwpfclD$-M zv?JPaCFki^lO`PhC{pdQifPl0Ik#q2ZfzIb{(7|p?~7pH=uUQ(t0zxnRT@V)h|GTW zHFVXEsLYUm-@Er87vhTe{o-|fMB+u2bN5*#7$%)p?)$@^c?wkKdAj<!taD0e0s!<u B<)#1t literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_edit_add.png b/apps/fo/public/images/map/toolbar/btn_edit_add.png new file mode 100644 index 0000000000000000000000000000000000000000..fe4f0993f16d0f824d9a01f0840dd75c7644652c GIT binary patch literal 1169 zcmbVMU1$_X9A7UQ#3XIeqDBywjkFD9Z)ZR5_9MBb@%GX?nv3Cb;ypUIJD04<?yS2L zZxf+Kv9W?JRHPL16ly8H1OzKcp|w>+K@ijjsXnNv_@Fd>^FfHS$z9rq;DZahGyj?Y z@Av=S6C=Z)cWm0RiD8(ILf$OV^~3nx*h;_Op4izzmrjzakWpMCbr>LKz{XX?7F;-n zN(kE12XCN0hG{wElq;lC95O8ICSk0Tj9j0h8K$p4@}V_>2wO#Cj+f#7`Rxymb?gkc zFI5CZKa0kl{7isGXNJqx%!H-eT>qzRUt~}M7ZJ!t?xYtQQHERQHRwJ*7C3fUg-m3) z6{jl25jKkh#HNyI-V$YvRrREp(ltrxVI?4@1)vL}!UNF&x&cJC@o>~yVAqV2IoPm8 zr3^Pth;Il&y<Sh&<s=Tq1X0&@0Z4)*@l=Bkr#%8A-V3{$3?>S#!10NLJvL^9RXjy9 z9QAZ11lKPXSBbr_ktmunA%eajCV}9(aa_yVAt|B%+*ngPEKmDLD4`Hf1s1JGt*Z&9 zxqG{zSdn^T><JuN6gX*OYsy6)DVQ0K-Xv|uHWWpYwW=iZvaG7S1{9gs(z?XUH4D}t zL~2^9HF?&;XF+-(ms3*%Sw$7aoUY~4sogRFCauk&V(Lw7!3zoWEY!5^P}>cx@>Z;o z4G<(aC}TX??1GVTOmH}keKwnotFE%2>~lOD*Te3(Oe;~FC~yuTdoaK*yPRjkS;Ggl zra)a4bzZS$!0Wc6@YNI*Z6Ij?LeY{Gm22Sbcg>$bof6_^`Cs!ik7!56+tpE^!s;*~ zk4{iPN2PdYF+s=de8C(jM}JpeFD>=Aq}H{i|NM3C;^D-(OP}==&g!?0X!^ZdVegjr zHk{pljoI6~?U%Oi+pS%<FE4@2P<y$xXZ>F<`hN#4k6%9DJal@tbD{E4?@j;G2ivs7 z)#Kg6$McuZ+|AF=^vI7EpM7;<`|Q8(kKX_K<db9b9Y2uk-+X)#KHQMHve>Q6Z#nt& zr&qg<{M^=c?#8v*2bC|s+d6j)^xgD3e?0odx_NLV-+Ff;!6e$5xl?i!o(T`cKZ!za K*j(7X|L7Y4DSLzf literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_edit_add_on.png b/apps/fo/public/images/map/toolbar/btn_edit_add_on.png new file mode 100644 index 0000000000000000000000000000000000000000..37a8362987b46888424750223931ff9dcabfd876 GIT binary patch literal 1168 zcmbVMTWB0r7@n|gX)cSP0UN7$nD|g7bD!P0kTu!PY?_5`8a4~rhX_48b0!%!GiNe$ z(%nQUSfjKLf`}l9l#0;yNvwrZkzz3|rD*Y?`k+Wl``!zEPHE31yU~Zx2M1=(`Oo>k z@4wHf>8V56zSsH~hRK#E?J8Xd(|7M4`u+6O8(F#xky4$^V2`w5jF_T}8wivGIFG6b zx+_aJ(I~@Yj`_7ZsaFo04i0#j>hSF#qG*O09cxF>X(9p|Xx<MC?4zH4W`XY(*x6h~ ztV9-C@F!PeG_yKYb5@&<;j&}zg3-1~2?9hQXa|d7VzvwHCa+2N>9N3qO%>8Cuv<>m zE7QQjF#<V0&pDE!1I^&2oT1C=2#`f7FNlU9shlX8qG5^>=sYa77Q3EVwI@2Zs8nDV z2#HKVXti2=OW|=mFGz-A2%;>=GDkJIWF;i9&4tNum%&Df6Z;YIaR^dI*ucxAz*0}Q zLI|QtWt%umI*Fnw6WTBmBwiGPAdPENJ0Vr{uNymRC$*Ib300Kf<=CP1@P@l!n!6Vp zN)@R$=8@Q^MS+Vpc9sJalCoW3=?(AtuBocBqBmrPQxr|(bWv3}J#WaI;yKWR5NUbY z>+<Y`w?s`Z+NxHxR85jfhF;3&4l1H()7ng^w$a6w!-T-lL0#KEwcWwyUx+oW7(s&L z8pey=E|^}x1SbnP0+y9lT>}SZ{m{j&<n6RfTT$C6_KzWVBE|vO%(Ln5;DhF=(9k4< zQ(Z;m3|CdTMvjWEDC;7Gk|V1c+rhj4H-7?kN=TdKKh4uUq8*uTw?}~r+rxxHIzcfV zmEVrvI!(vy`?6iEwf}BxJbN~l$@TP~eEiOpHU44mwdBM4=ab3l%+ixf;gtu6^}){? z`!cl$bC>&<4lq3vY<A<N+w0fH(bcs<@AotLr-v>M?LWTf&yQ}8|FAyL9GQ99yF7QY z|Mi~x>u;U2Mz4PL&*V3&Bj3LN%IxBsXD{^+-R!mYt6$zz_Wt#%aDM2MBgKz1(uEJc z_yYj<O!mhM8()v#DcyK1uA`%U{O+}128IXDzqgy&wU4>}YyQ@WQuA*5k0_U>?C%a9 GJ@FiJba;LM literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_edit_del.png b/apps/fo/public/images/map/toolbar/btn_edit_del.png new file mode 100644 index 0000000000000000000000000000000000000000..3bb372ab9ab05574c7ee2f65e5686429a25c7a91 GIT binary patch literal 1160 zcmbVMO>EOv9QPVjP}gb*RZxb8-dt2ZgyYY|vDHvYoV4k1i9)0nsgw3%zqF>cpJ%@k zx7r~f4pd^Ia6r>`X(tYF;jkkd3PhT=!{EY!kJF@yohEjeG$fF^=Qinfs5s1${oen* z|L^zz_EKqlq^IlSE{0)xilauEuD$WQtCN1eUizemF8fJ-lAOggQilOzhHYF$py<MB zR7TKV`0{5o$S{cuPGyoznx}OOyGa=9BqP_SXoeXaihO9zA_A&t+VQgN>-%dgaO^BQ zkun9-&!HJ-bTL3@7so5s;;g0F?9d4?80nP2MFfJ#o%2FH%CZ~0I^D;|JPS5d$ZVF~ zbZXKpfgBDHNF~#pCCV9~YDqDrWhCV|kOVQ!3mPvfoFM9grVAoyJuI~r*fqUu6k4{Z zlx1fK@pYcB*Xzl;oW#L2FKU{`3lc9$9M#~$1&_dp^TPf%gMmUTaD3um55$bHiswm| zrJinv;QFSyMeK#GMA4M-5%hU6De$fv$F-pyk}~?&jcv8V%7TyhG79m0V9|Qi`rBZd zyZ0N46{$D+nZTh%fpZ47=3V5GqLF3kP11I3T~Q=CQ<Y>+mQ|I@2#U;Q(wfA{H4D}t zL~2^9wRyI~=Y(`#lGVa+PEkcMuVwP-)G1jI3|gClVrXq_(F+OmEY!B`P}?nR{=HZ| z7a&M*P{DYv-36r?OmH}ZeUQt=Rae203CFW>Jv<thX)|gA1<nOz7Xs{pjXdklHa@5| z1!}6Oaf&SqoMtNuS4~mT7Nm>-p=e2p%C_+K|IHsyo#NwW`A_q-k7!56+pSTc!qzY$ zk4{iPM`bNKaEFfB?V>SUiC$FSt*;LyQXhPH@4*Z6W%lCJDRA@9%HP`V!#m$Dcq4o5 zN8c~^HTzc1zuH4Sy#cT8=ze$Ym+C<0u|%PCi)sF`YuPnd&y6&Gbv`rqNsm6i(%W2L z>K^*dx0!oauh-z{PbW*y4*uAj1_RGQVz%R}&TkKY_Yi|sVQ{Q*=7)>v9dG{nsQLS- w*68c*;Q!qJ&852yCh9t7i(?1QcQlv;Q+gt;UY>e<IsP{k^W(<dQ(s*A2heMB&j0`b literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_edit_del_on.png b/apps/fo/public/images/map/toolbar/btn_edit_del_on.png new file mode 100644 index 0000000000000000000000000000000000000000..89e558739561b2806db18bef9a567f34244756cc GIT binary patch literal 1158 zcmbVMPiPcZ7#}Ncqe)QO3W?DAob(W_v-9T9?(7WNtec&UF1Rsl7Tg{Rc{}qq8IqYd z&b(wd!Glo|MO5seYAM=N@E|I9GE!R7P{^UD_R<K&Q`<{1AVLm;zDagt4<UyR%)Ix# z_x*m~|G6?ebi8xVfju0@brw#TCANMNy=^h}y>{i(PPTN@e1(pX8m*%Mb6J~IF(|lb z43{vnXU;6+K91Wt?UXCDQaou`#Eqj!C*E*<hUU1wOv6Xk1g4;h#~d%szkK#14;(wq zpH38E(a+&==frG)M`nl0*6f6(+kB=U^fe4d;9`nE!=3a(qmky<c@4IYjzu1<tI&xw zzu{D+I1F+mz#tJ%3YMg#fTqW#gr1Vsqd<mIQiQrFsREP?s2flM&4*{!0=s6E%)zED zCZ+jtN_|5V>-BoPuEa?&CQ7=li%=G2SzsDMIO9>&5WKLb#bDyl3LKw0!~+o{s*)+1 z=9#A(A-I0AxJm4V%|x-3i4Ek7QXGn|8^yJ*9nunh@5YweVR^>KVhM+2DzI2RYCSD5 z%iZ>dB1PtnaVl_FQP8AGtSJ|Jv|y%rb`!T9+fY?mNmXS<P!vrQQczWdR8p4(rDmZT zLRd@6wHD7-_#D(ySyLUz=2T6R@_H(tObjRxnyfa1s;RfI1uvw?vvA9{!)!OP*=?~# zF2IPApiIbQs|$w52_@k;@j)&ZRb2zUryb8G_3&_1rj4jg95~b19t?;J*7IyQTlk>W zRHSQ?E~vHw1>IIvp_*W#4doO>NU~&A<C}Q<|K?9*PKi;o{HJ+ZN30{G?dB*jVRM+U z$0jIXqq29ZE1KK+f|)HhR;q8_zRm1R>}bEddgO<TNB`Qr6wXz?KKJL}$G+=WdX7GL zzVN#1_T%2qe}S?4-#)E;bvb{i4SobyGs&xWy6$(3#y*={Sv&aat~I!@@bmA}hkAmp z74XO4$u;Rk>C_XrwCnm$i?I*y&E2*ybUfI-+WpTrld(s07Z+E1cl0mER`$L4Ez@!D z<2yHQzIxSuHa7qL7l6Av(Eg=)X?}V?w{MiY`mbEQaciwV`ZE;rL*~PQ(ev*BDED^b literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_edit_next.png b/apps/fo/public/images/map/toolbar/btn_edit_next.png new file mode 100644 index 0000000000000000000000000000000000000000..df4913c9011ad2d2444d0f997baa68357fd2e5ff GIT binary patch literal 1209 zcmbVMU1%Id9N*+>kk-ROqSzB*+$c>;_j_;mcF8rD+}@d!Ts*Fa4Wg}cyK}kiWp~!y zN$!&RQjrT4ltz$>FCtdaJ{0U@1r;npKolP=TA`o_3XLBDUy6k~o7_boLLXe%nfcHD zf4~3to~_J2k=&cw%P>r`G;LMsJ`%t84$<}1vyUX{c7PP-$T8d?Z5SeE(!q5EN*<g? zRRo>o7uL}@!z7m6+8miH&zLs$co^&O9WS70h8dse1ki3F0_teq^|S0BAAiaM*U7TS z(`B(7<WbX|UJ22$mD!rT(y|SQoj3}{J0>OY5P_iME%=ey$+BC#COya30t>cONGr>3 zJ2h9XfIJQnNb?$JOG*al1}~+JjI163vM6bSXb6(ZiIOQArYM2l!%}OZ(=e-6v1f}) zS++??U<yLJ-R9d0kHdLEG7LiyWkHrXs=-CeK7k$1k4F0p7K-f94Ty_<5HrF$UL;wT zdb%Bg7nI98#D3IE6iu1Xfq@|LqTqRPTwB@^siJ?~*i}2KEeA-bq6jaBHmyfvv=64a zySt%Sk$Pi36}q%2aKXa%qKAA^va&4w!aJ^Gs;aDH>axNqimr1RQB}B%X2_h<uwes2 zq-%1c&$AmoFKPwKpikyiU6Kk$rl6j8KjZHlU8^syyBBG9){-?mF__psVsv1UF* zkl?U}@j|}~Dospq)WiYE=i{pDVC=Z-JGdPkip#VewS_`=2|2|OdtfWirn`#|dP9YV zE*YHaC?aP#s>;>VRCGi+BSI+IvZ}K^yz_taCs3z^xLN+wJpC)$k@0b76sWK>OvtAb z6w*;4UtN2fj@kDmYqHk4UcY_k&O{<TFr0W};M=70=+i%5FaPlMz=tPu8^asF-0G%y zXHPu>HxlZzFQ<mCBsSCF+G^_XlWS*k_>;lvYq=L6IQ8p^h3@Mkho-wHhU(9O8>{}< z`bYPvf2Gfb-PFaz)xXblUx8QU%AfnsU4DG@y=G!_325(^Oy{wKHzz;$bT!Pa{k$i6 z@~2_#EqMB!weX%(-?c8YbUpe3JpWB{bUoLc`F-_^jY4JS-G_@8&$p-S5$DZ)mu`P) tUAURM_0Y)agPRA6OGobiZSX<x8PnP~>+XMMa4i0rlnS%frK#s%`Uk>Gh@k)g literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_edit_next_on.png b/apps/fo/public/images/map/toolbar/btn_edit_next_on.png new file mode 100644 index 0000000000000000000000000000000000000000..4e5540b55aa8b04368d7faec600a7f4ea749959b GIT binary patch literal 1205 zcmbVMPiP!f7@uumsY$l2q#n|$3=<12Iy?V&c7|-z&CDiQ$;M^7ko6MscIIs|O=jLW z^OBiFP}4)%3Ldmdd+5PXiXbSYhay;7ArZ_)yi|jFDtJ>01rekW-z2-yL+HVQnfJc; zzTfZrKUb?$<C)%5y%a@d$`fXdtS6KAXqtRKxcX9tEQ7ezz!y;qM<9Sy(MC;3mt8Oi zYY^BgZ*9Y2it1T*>J8keOzIYLvmnvQ#;#A$6g4~&`@mX&m~O&3$15<8zka~bj$L4; zl?q?+4LI*itOoGn>QvoYU9dEp897f6$2uW!AqI5pE_$IJ7nnU>o$Qlij-mHd@Iryv zcdAjT(gq43tz>hoB}jQ%)v|)3<wf~5TI7Ws$7`G*v%H}5n$8P!=V6Goz;5X^bF5>F zNCjpdV_)aED2lR?ltsZDCuo|+@ggUREYV=Y6%T`$^}?Ypg9$?`aD40_k4_jt6D{Ea zLp<FN!SySZ17a`iB#NYri-FGxS)Oy<B(6Q}5ZB<pZXBu|)>nMU)nJI00*ln6HPi)@ z+&$Y+qDZ{a-v}I16tHL_YsrNkE}I30++=OX)@50g@=Z}<B}rA;JTFUZKBtMS)UrSe z0I24~R+r~6yuqsmujPtGLskW$q~%LFWmMvMlhkHRHnlFc?1dP37VO$~i0uwmdnQ&l z0the)>If}%yP!IcFbe09Pa8&3b(KCl?RYkd!gEQP_M<jo;4DLXEI=;3muKBM#0Rw{ z15Fh)R<<Rc)ofX2n+g$aUd;0V2$m?TOb2iO-~4gJDK2T2|1?kch;(GKJs1Td91Iim z$OHvsRBjC1e2$FS!?Ibd$3Hip?(UBCD5-&-Pf`yv_L^|-b?*7v+sE4PrZ$eBcu>6l z>yKZI-{~7%+j+4a^=uqf?)`pj>!<g2sP<pf#@XBH`$wAN^!?tgzrX4~qts@v%%q#u zPyZ;XAKz@eliB*dYAmhABX`!nOTT>N(XRPuy1IGc!s&MO!x`{P@mgAF^tZXuKi8P; zfgx~>GS@#$J$dp1y?pt~t8dPv2k#!gv;*<xgi`H4bxW^4)^D92`}}$|YMr!i^xb_r s`F`Kv`u1<HoZtMWcYG$*cVd?MXfk*1vu`imPJSfi(v<n-=<MZx0E$V3E&u=k literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_edit_prev.png b/apps/fo/public/images/map/toolbar/btn_edit_prev.png new file mode 100644 index 0000000000000000000000000000000000000000..e94bf6d420a6c32aa61255d73906344f344afcdb GIT binary patch literal 1172 zcmbVMO=uKX9G|eYrq;B<EYwJguM?^bb#~r-?0k{!ChqL&7B>y+q6zJxZ)V<R$7JSB zXI|V*3jL50^&s^kNTEojJt##)JV=#V+FW`m9t6dcc+g{yDirLSWH<E?JUB4(-v7P- z@Av<nlT(xX2Da?j!g1U{b-!I_Yc_rRUuEA@C*K)h%P=iZ(}Sc*+bG7|ghw0<ssWnC zb&R~l&;P<>9G5xjH>T-y?SSQyAcs<&TqlSan&ZZbod~&em;wjS`eA|p=lV?^_+EiO zoUg%JRKhKP|5A((E=@Mvr8(F1_~M6PtYa~P08<1y!F-rlodUngYq5QLEb?Ggh0YcD zHK(R)Q=mj*4DvZma3#e6x|x&mrXj0)fD9!~gr+E|0+cLhT2KPrhiBGeuW8loO4k;X z3Ve&w$P&eNyPaz*ITFu`l4+VEltoz<n1+xnh7@&#Fd6AF*f?=xKcYSfLCT06vOo(w z^K>nQAga~YiNmCuD3&s@gCbGNK`{u@xK_0jTF3vpv7vU-Sd6e(#|c@8T~?3gNDs_% z_hLh-BJ;-jIQCgl(7a9Dg#d@NY8QBRlk<GfQdL<o99a<*Mb`xbs)}G}rYtB;7c~*W zx+XV!JR9LlP%ASAWum0&l2kU0vX<YgKxnhtR8-sSVXI+6QRw2HZJ*ihV&xZNtx}8; zC2@n0`Cb=HwFo6ii$tJQN~^Ae_YeD_N7~6~TBfzAZ5;bYu~&&n09NyC`5XA4H&tZn zk}0U30tM4kRl&(K(Sx!95t3Y4)%h;od)fSn%qcN#mgkzMcf>j}-L8)U6V`_bhirmk zHY$8;*G)ENSF83!qjS&s_t~>zCf_%dIny_hxf9;|d+Q$!X|Q$r?bE-$vGQnC8$5FN zOK@n@gU8w76W-ZvgXdmxidP0!oU>nCKKE$fm90PBhS|&ow7nl5+oq{ApB}Gp=KcO# z@h3-i%~!H-@rzHn!4K*W@U_>!`F>~L=w|TSn=22;Zw$3wE0$-z+p+9?`|i)n&Z+F4 z<?y^AjtnntKC!9#(eWq0|LE?X8Nd3&nWsB1Za40~r;UHz$Nl-$4F8KUbS?c)RLhh0 JrM;gW`wzE}aex2- literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_edit_prev_on.png b/apps/fo/public/images/map/toolbar/btn_edit_prev_on.png new file mode 100644 index 0000000000000000000000000000000000000000..8645dedfa10645815637c3a7f51a8c454fb7df52 GIT binary patch literal 1176 zcmbVMO=uKX9G|!~3F=Z&!4Hr=#zLbwJ8wRAXJ^P{NoF=?#ZAJxU=AMocIIs|&Ca}W z<|VsHPpLU5rHIhd_GU|I3x!g95I@>@iO?c~0imVfMMS)aMi6=^rf-sL^bkBaF!SF3 zz5nm`|DN-s!^hIw4s7E%E?pY3D{S49yxpDb``P(}X}0XA#W8x4)M*n%nCo{*4TF-8 z#&HEBcjnBWxR>Kn(_VFqj+IXs4)HT6(aE&@kfAxQx6lfaGl?mv;c+i8`KLE-^1yRV z{#3RM%b|rQyrJ0$pPU`8I<u3G?(&5`(AzQ?fsZKyEx!@OM$6<^c@4Htjzu1<s?bT3 zUvp}#JPIrlVUW$_1V>WxK+`i)R?o}oQ6NJpCqiA6Q~^o`)D0+s^@nHHBDZc-?7?+g zOfvZiN<%{wo6TmXsbokrE=szti%=G2SzsDMJQGmV5`y?po59Ah6L}%^NB|N>R3lT= z<e8^yA^2gryg?kq>xp716I&=0r3@5(KZ$EqJEj%<%8gC6<LXR^#R`teROGOF)DN}6 zEO&1<lqfQ9jFHG=ML`XlI8#0jXvsEtc9U^E*HBei$=75>P!vrQ@=#TTd`_1IrS70Q zLRibm^)}CDcnfM4)N{FhOVuQ)sOO8h?0^EH&1y5K+IkyX3Sx=^2e)l|%r?X3`)#%O zMyz2)7*P^c32C&uV03~|5>Jp2SXNSX4fLGy0+%%7!%3OeqPB75O=EX3B0gBnv*B&x zgH~6Ou1UI}x(XC@S5<{tmWeKu^AI7)kyVXf$GdNvKan{lCe89%^R$mxM<&~iQDDNx zFyVkrP{c;%+VqzJ8?&n=yT97{r}p2<N+Ff)*q!>KWBa*hM}D6lNh_bf{B&gLN??9_ zx~FULuepDFv%l?-8-<-eZCU>KczS;S_wOuzF!%R`U8$vX-1XqX!vjMX(c{iaW8bfH zm%h8)_0hiWuTslh;N{5seJ7sG-#Hh6o~7&Dvf1<AL)`J>K<$@wZg1a~+A*;3?u+Nc z;L#7Ncy`CsrNz+(8oKz+RetOJyXAX-+=kXu?lLId+S_4eOUDam7Zy9aA@}uG?Zvf~ Rg;esdC>4k8p9ent<bMjeddUC) literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_edit_save.png b/apps/fo/public/images/map/toolbar/btn_edit_save.png new file mode 100644 index 0000000000000000000000000000000000000000..5f01dd55c16bf4837227f089e670f02f76760330 GIT binary patch literal 1180 zcmbVMO=uid9G_)LEcp<vqD@qMOj?Z4nR)ZEJ3C{xA-j__3vLp(3)w@_zMXlS9g>+h znR&@ha%+)xgY}@G*Lo3p66;B@Xh21*7e(lyNC`c(;6>1bO9`xRlHKSb^x(kEd;j<T zzu*6Rc9s^-j}DCwaU3^Vnzt%!eLi_l46^V0JFkqgWsJ_&=mpZCEfivI#vyeKN*-Fl z6^xv%^&jyR$E7#jYK_*)Z<;poM3m@=u@^8j$4yPg0kT&y1$DgQ`g#73ufE}d>*V?6 zOc|DgB5u0#+abQNy->BcS8c=Lr_X_@*klAArU=B|nje{Qo<HC<**-azcyORXSM&U# zQ?>FED3TC^jF=T{S<M065ao=KQ?#={fpS)Yh9qkOluc-uPzJq+XVyZeVOFfUo-HQj z`6i`-DM_tXOKhnk30EZ9FboMQlA;JqLx{F~iekZ!Ci)B(j_lA4s7rj1Frqrypn0Bo zdKiKil*>oNe$-18OPLg-K$1l$d0rCNfp$bI_+K}U)sCuL0hTH_A{(L2>d~0!gIVsL zY$#D=-k6J_%Zh^5EMjkX*rz2c&$AoRaUE0B6g5{@R6$jBUC2RA6>?ca5!8l_8VF%M zt2FvN$Ki`mSM|c2GE>xaS)Mg=v)N2Rh0tQPnbRzzk1hETMZS&uwq0hshn1g*HH#re zl!R46*7{wr)FhNdO%i}&F{!!^CYN2`A+6~3q)dlVTR3z#u`?GE4;<v#bdT{tZ)nKS zWkb*$6$*x<X+k~2L<cH4h>&b6n$Gv|&i~Dy#GI0nX8BL^^p99aCflP?V8YQbVV_M< z$VTP0lgk}8X17b$Of|k&-|u#()0xzB>5o#w*Kck9y1584FSgI@{QUPodojKK&gVBC zy>L-HeHT8nm#Uu!_ebdbu$V?y<$|0Ze|7Ay)cQd6>+$AI=~L7hYrk>%%a`v+r@!Cr zHaqac-$o|A!u88Hg0@<J>)ZF9{i()vKbgPQ8QE{2*}v48Fb4npVB&|uyV9v!-#y+t zQM@zs)Y-ksod>4|&s}@?sB2vv`=T?v_V&We#~?K|@W6>jo_>7tC9um~Y{B1eUfKO6 P`CpV~7p%_;m#+K+a+G{1 literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_edit_save_on.png b/apps/fo/public/images/map/toolbar/btn_edit_save_on.png new file mode 100644 index 0000000000000000000000000000000000000000..b035687d6f910df7610a77f62ca19b4fed5e856c GIT binary patch literal 1190 zcmbVMU1%Id9N%l&GffNzTks-EmOao`y1TO<cl$xEG1*Pbp_hj1l?D{rx!t*BO?GG9 zo%A*bg;s(k&{8T$6cnk5Zwm26!3Q52l?a7WeJI6;7*O#^u?i}MIGfx>A3`5o*q!;$ z{C~gy_byLOKG)atcn`xcedP(eO4q~b+nuG~E6Y#z(Pe;)O_P(jL7Ff^%!rHYh%NhY z22~Ms7hhRNLk!b(&Z|w6>B<YHgM9&}Izr-y6wNS0!$}C8IYihxn(=}X_seIWbFAl< zxYLCSsDu`p^(I;oI@y}6IjuRzaJk{*>`-D-0v{2`CjNX7n@Ne=<~8X)Jr+53TZPP( zxE-gaD^sk6Bg7VjBJW6w&T57r6%1WgkFhe4iXt#XN#%iL0>cCn+kQA|Epi)X)gEu# zqEd;QB_uROvDs`2O+~=bj3^m~Ap%*HWu9vA@nS$=!Uu7_!(gM>iM)__IABvoSjP*b z#8FRoLh!>%WtTXJ+litn6B8JUk^n^CPvhFwj!6~$>&Bkiacwa~Vim=BA#!Lv8u<>G z=I+6UQbp>Gc_Q*?QQ*9dodq8Sq->WsdLy`=YpSZO=yh4)6-Co{9jFSg7Y&(L8V+ng zh_s^I=<w`?w}37cC0iM>R85k`41KIv7*znUX>G<;+vs4+K}=xappI>i+HPaz2VzYt zLXhC7hVgu-3#Mi<!SO5(S<6bRuCYf>dx49a@zJzQJ5k#x^3EZ5Ji<P^ooCbA!w0RQ zLPL`bUUe0~8?LJI^#T=LAnO1^$&po!YvbMjn?I2{C8o{tpXTWt(T+^FyQ4sb-C;rj zouG)0idB8*2|8w9mhF*Ra<_heYiqcxkU7-#MyB`j_orIxhbC?wsF%6l&u2EjdG@<c zK70}P3XeTHm+StOS<Uz3toi<dm5bm;?)saVD_1Z7b>Y)}&z$K~zg>9`>~Gyu`kVXS z`eEw&X!YUyS6_Q1zkc(=?Wfjqe;&M~=U;ywzMM$)f!>Y5!$0@GdvS1eX)xF2{E;`Z zzg^3JHM%6`R@eUC=(fJ@dFa^2k>$-?_V}eAf7)7G8UP<$`{K;mdr{BF`wwm$?SJ}) g6W&_6!(_6|=G)qd+b^A0(mzLeY|{Q{^z5tu01BFZ^#A|> literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_edit_slt.png b/apps/fo/public/images/map/toolbar/btn_edit_slt.png new file mode 100644 index 0000000000000000000000000000000000000000..aaf2bbd08f4f62a2763eb461660e9a74eed16ee0 GIT binary patch literal 1288 zcmbVMZ)h837{8?2cGI}hb{pF|eS6i}YA^REmt5{_)~5NhhAlOufrf$7H+OH^qq)26 z?z*I9j7~>Q9pZ+rh#$m#6F&$MnXpn^r5_xkPOyTCI4b%@VLB;HoYeQ)r23)kg9mr- z`@HY-d!FC(@8(m($2_|a?j{JrlNgGo@!IaZ&5ii`%KTvuUJlr?tUY4n?GiK*5mt;G z0tpR{qcnob^r;)Dk02UOtC_5wO`ecsL-RsM$6MBl7)=m;{pBK*Cy@<uXk67p<n6_e zNT4bqa@3z>lEny`P={trG%_=sk!L1lQ6c+}g1)kZ4QR-QpsW>iODc!RO}i4_JI6E$ zHdXA&5V=Jvn@oX-VItu71}K^J1%V)XS-%+M_+G#<Y=CA&n&l~ml^9WCSWtUN?9Ej2 zQaT#1`NC3&oUrYpMAM~G$y@Sy4Rf4kMNy;~j^;QDYf#p-Zo@LATU~VvQDn)cTC`O| z2aZLUGp6hiiJ5MNpcRwJZNs`%OB7BSU4})P^)j@kIdN@jTXq`#OJhfED>Ge0bQ)R4 zlqutS<h$x%oV)uwauhKe=~+|7MS+E=Ax~*Yw-eD2iEq4$sz^M~`GPslNBMk$Km{4z zM+E~SNBQzH%tMHT0GF@Z*$E$E0^wLpV8an!VA+@$j0OCIK8A_n+Qj*&SjQ%G%Z9p) z>b_O%yM|@%i<KfKg0^9145Lu*g4Bdz8`gwT1d)hSbpdpbs=8v7tRAOKTTw@msh&nk z+%z<>nP*AefrF6ep(wB-#VbCB5*41Oa(*l-3>Rb|WMz&Q$QoYxzxksvDcWh4|1?ki z2zR8j-5v!jY!4IC@dTN8R1QrMBtf{k6VY&{{B7>u#zudG-}O)>yQuyJ0czO$jC<v3 zD)8mn^4Yh>9%;+mY`oDL?^yV;^~2?2=U4mUcH;5<?5&oKS64qR^R4b<H=p}_5O$0O z&+qEFxMze~sGdJuy~SKR-n0I`$GiX0<=1+LUT%-4hFwPr@BY+&q;-{cucg64rvj?g zGY2Y*vv)gNZa1wdVBhup+n!78lDo1IUKfeqJHT1j$}h9Q=E^sT^*eI!QP`9l1%U^1 z&%bf*u}gP;h9B5--m4FMcAXw55G$7l?#=D$Dg1W%sZVl~vv;3-{clfYdbTXK{L%H& z6)Mv<GcR9={o2rCym;-zp2`;kON)n;?yl++fs-dajk&gWgg>v$oqPEE<NDX%xmTJl je*DAUgYBz?tC2YKbgcQpsW+FLe^Vkh9DQ$a?1g^-F`A~F literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_edit_slt_on.png b/apps/fo/public/images/map/toolbar/btn_edit_slt_on.png new file mode 100644 index 0000000000000000000000000000000000000000..02d035a74ffb56e485da4562d604ed7a0f1c54bf GIT binary patch literal 1274 zcmbVMTWs4@7<L*~O1D7AO2?`odG5;wb9|3u)6k@GLo!IIvPjE-PIK&&*0i=$+il!D zpfU}XAz<264J44*0|TiKXqjMKM;S{cZV!9lfgwO6(%wMhA^}4c<+x1>57i#9WS{e& z^MC*U{Wl*Q8GbO(+1rUANFbe(vT*J8-i~(oeg4=z0l4gNhVsrnv*?s%3m|dTEC4jE z%VQu5WOa7xGtiG9{uwQock-EsMa9%ZvZoVr^%6uQNdJIal9dVIpan3d8By%|2a6c0 zsZne{mmxEy1Q^#+6$|XE4Cj=}gd(WezyoN%D?$T0aAefgCk<P4qu8ol5$?TX0z+3- zoQWv5Mk=2fK@+A0P%ae46^e<Vybz)|AwsizP@1H|1St>{i<6W{3L;6N%?E?tEVU?R zrDW3=l%m+U<CH{#D3{BjG7~bbF@h2Vfgovurg5l&+p~rvySQQZwJb=$RxGXLXr_UB z7UhCD?L;xibS(tEl*z0cHtc4iV9E$rE)i6SBy`=2YgOBJvfy7D8*1CR*%BbKz&58X z1=ge3*8;=b-Q1C<2-%2_SQ;#fJSmyVv<?g>Ek!YS6H+x*WLcVt6lex#7@o%?B+KBD zut4KXQIU(X4EQizY}wfepCEaLA54bh36`g*At5pp<^~y(lwfU=tR%FsX~TA8Ljf({ z8uZ=7ayP|_2@A-MY2{3FvegA6<ECTU<7Np>B)qEg=&t>mp_*lTw^ydMs3l-&GeAvR zrjD-WS=2V*z!zCr;3)xTRffa`m1Xe)2St^nBcv=-3eECZ6R-Z?{1K28;Wf*Dnx}OH zJJQ>(j{+3dhY1*Pf-E>HQ*XWTHG=qh(^5R=ep6UpSsCzizRlI2@4evMow^cRdI727 z^O=Q+f7|@|__-rnk6wGXu9J^<y#4gn(L1jcgN>D1WykU4;MI=zzc{e#IscZU<jzgM z$_q>Msk41O!DM;&nS<vqUi+laJ-O+?iNZrarFQo0X=`NBQy0(7eU<-cOMNu9+*SR< zKSg(KKEzyp=F^uB`sypE{|e5zw|6Zfjp<nMmimvcRc=r{ub%bS?(2HFjUvAM_;_me zH}X+2vHh{b#jD%VFw)qIK6&X#clgh}cd0clw!H20zuW8mu@8gQ8z(MZ?pe6)LcO+x z{qC#26CZv3*814#@4pMs^WVO5uDfcs{W6NqJk{GyJNSF;hOgmI{cycA@az+Fh#yh7 W`|ZUSm+tWXM(Lqp>CM4IhyMZe52yhE literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_edit_snap.png b/apps/fo/public/images/map/toolbar/btn_edit_snap.png new file mode 100644 index 0000000000000000000000000000000000000000..fc91d430447fdb7d0632691591cb7ed3cb506a02 GIT binary patch literal 1185 zcmbVMU1%Id9N*-$*t9VPl_m{=b^BmS-S55I+a=e_<@RC^y!5yn<fwv~+nvj8ligW& zC%H{TX@ZpmDcA=gf>fWi2m$GX6<X^d`qU5VgJPwq_!N*TLMVZBHn~gt5c<%C-I@Q) z|M&ZU?@Dp(weGGXT@*!i=T90Xvc4F-&+Q}M^D6`0Wa-1X3LZx_+yFkLG8U>rI`4of zSc1TsfBPpmL{YIhyIjGQ!t1(;91cV}T<CZNO;JPX&;#Z)#B>!-*=~yY=gL)vwyhL1 z5ibY@FAMAT$ps&dFN~GVg=tf>nDhyHDAWmo12LdOXT}ZmFvV>1>SP}s^9;SMf~Ql= zj#HIFk<KC?(s3@qnxdSfRgDwlT2fM8r6oa3@PfvR3M+`Zpy`50w;qOA^R1d*GDcgr zh?HXL7<)R;HyRDDA#=!|;zdo<ctPSNi6t6rFz;dzvTks+&0xU5^lcB@$fYAjP(`yi z#Sl+-LU6o7VVBqqT8Sbl<3r%_A}8>U6UDWy9pDmt<i?)bL3!STd<h0<);CE#YDe2( zlDj7xiWG@A`YGQgMFBGgGG`s=;=GY!$PH)NmaZt0oUBSRE6b|NCIv-ilL<{?<(dg< z06;Y%)!ICJ;j@A&t0TEwCab8TnA4KEM0`XR1cTIOR57$RHtz-)xF&4dwu$W))_5XT z&-xHx<d+eeX?H=fjxY-9$fL8_sOl;`IAOaMY6QokGVMfdK;NE&)~JshdOOd$y@wBK zO#zxJYOG?(0;^ey!dBx%v;-+B03e!@qB1SK^|blpiBo*kERQu$`-pU8wA~#ABJ2(m zbjbwyWK@3ZUA;`k?7O^?DTlvSH@CLZv3SP|v5z}`?zS?2U%LDCz$eE$o4MijSo2JA zt$+C2{mZX(-0xq#KAAqXzK>a)q%R(5Zr1;JQ2ex~nWxo5f5MNzmutNr9NhT)%+mh8 z!LH_iXIC#Q->bg=#Y^8$O>%eUdN-c^|Dtf{K<1aLH{U#c_Qr5pd9P3D{JrD;JA+rA zFP!f=5sTm4_;4+pO&ob^;IqZ``evhY&^T=NU)Rq4_}9|Jz&DFqD|eR1@80Xl{%~R9 dTIVyp)W5Zt-@Se7jdRgYBcB^Hz8aZadI*!Age3p~ literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/btn_edit_snap_on.png b/apps/fo/public/images/map/toolbar/btn_edit_snap_on.png new file mode 100644 index 0000000000000000000000000000000000000000..f856d8fbe60ad8b33078264059e53896c5767730 GIT binary patch literal 1185 zcmbVMPiPcZ7@u_8HPr-GDzpkM(}}bxI6H6t?9R?Kn`E=I(M5L~)};nYgKuWuW`|_v zO=jL^C#e>yP_VU!BI41i;6boOFH$^6MFcPE!4%peN(#0ILA(jtrf-tnw1?oK12gY^ z?|r}D_kWH}RCo7p-m#fsnEvt}qej<l@!OlE-*1k+-A|Y8q%=wP;|6KN05Js{n}{vD za2nMRv=`=Xp&^Dz%scf-GFjQDTi8v*SSKC1K1DOk&`9J%YX%Y4MAMF!=bl`>#<7l_ z=MH2lpyC%%)7i5ap#6*0y0tiCX*M@9%nn65C2$deY~;>*p&sSARbHL$<70tiS5?SN zo?CNjvNFLIae&xNI?G$4oMTljEoQWwr0ilPAZ7)i38KOSQ3sk1M7HyA)LLLS^qMi= zu|=gk*CfQ(1)<$;r`vKG2h)P6X_^2eL6Uf?!G{YTff4V816>9Kg;wDB#K9gLGeQ%$ zNS>pfu7%+GmC8D?7j_awQzk^v7sNCWTsMwuRXZd#^sgHmYKQd&9|<)S;#OeMdNc;Q zV4Ay^8;TXFH~L3`LyH1u4Q#bs<dL$G=jct^c5GcyBsphFGB3-j%IAP0^SP`h@p8k0 z4G58%l^R{1jqpXF7J-&66^e=~iX|;q%4Wu701R52amCQO*s>QA=vk<1+o85QSmUKw zy%-=!a8Sp1w%Y|0O-yju#6DXr##L9@!2^zG<97H#T&A_C4HP)@$Q}={%dX~GcQ)`r zZ75JvMU7W%8St8|D7=}Wq79@RfKap~Mddnp`~T)opiT*Kv;3!dx<|Al<L&w=P+@(T zkVhvdpri6b`9qP8*-vGoP>+5!U#zT*Br-j3Bu@4$_1lF<(aEW?M_(~>TT{=OOFQb1 zlPUbla(VPc^1T1am3QV7-;RRRo!89ImAS)%w>K^CWT*BXKUMhh;!X1{>EY1}ufJ!1 zH<-GUFvqzgUvIteao_1Lew_FXK78}uXV*t}y^2=GLZ@dq@z>pF=x%Sc>Bf^Yk98$8 z{H*WZ=<mYK<)vSmhgye{m(M+Y0L9d&$KBpPws9x6Ott<@{{4P!pxQb*(zkv0RL_>w aL1wA??%|6+-#;7wG|Hu_@%`ArBmV$!4Sq`i literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/close_icon.png b/apps/fo/public/images/map/toolbar/close_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..e8e76d5d7965dcc6a3f329e47961a1245dd7b4d1 GIT binary patch literal 313 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjoCO|{#S9GG!XV7ZFl!D-1!HlL zyA#8@b22Z19F}xPUq=Rpjs4tz5?O)#bDl1aAr*{oryS&MHsEpfy;a@FImzeJ#7&GZ zSwhVh%}!}fX}+@VL6B>&tVO{C&xt(0zOg4W7Zh2n*~-_?t~h1+*0TNILp|pd&r?xb za&(S*n|T<M-N}@mlQP1WCQK`GU^>2Jr^WG<;*a%elO9c<rLgqNyWjJi?E8|<c@EEQ zW9a8sv`NsvW<GJ7>&8~E(xp4xwz?iMdVYV~gQq;+yOVm1bC!N_RIOIh+c%ptU1YYe zO0k|<=FJONmwYkbEB1wR`O$|$dmA`)WyF>n96tH*2ZL~TVN=sn*Qr3CF?hQAxvX<a GXaWFaxp%<; literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/ico_gis_sprite.png b/apps/fo/public/images/map/toolbar/ico_gis_sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..0ee4b5985cd59564af938697a2ecffdfaeb325bc GIT binary patch literal 7858 zcmbVxXIPWl(r6HrqBK!JY6R&*=n$j`gx-4x1B4Di2#^4wNmF`P6r={E3rJB27*U!O zL+>imdlwM6aqqMDJ<mDkp8Gvt{=D<9HEqqBnRjOLSYKC-l7fi>002;Gs6z}1PkjJ@ zsEO<f0m46ga7cLELa3M{jNnd)0H_ZPpy&v<hXFM_q0TTv7}OE<up1@|01*4T8k-}` zb+lz1;GROz-#9`@Pj3P>03fS?^oBaP!w^7wn6s;w9LLtXHV&Yxqa25sgpRO|w=&Gd zRXxxLW)!Gv>=5Yg0Cwb1kO#^lWe5yBVF)M?>FMF+D}$8d_=B$u0sg%V;sE}Ef^e7P z_){r!9etoO+y@4f5Rw#h5D}9GN`Zw$B*4<5;&*|f!XlC&VK7KUTu@j<Mi?w3ECT$; zkAoo1$I(f~5Tg1IS%fz^4i^N%TLuIQ2nY}g5EFv?ID<sMU@%Bn6eKDtNWc*EMR_5h zNI@@O&c8T7V7?AMuHFb&xEJs@N2opA4<W}v(DctEczWyT{LR?Q_aBBLm<)u3dV@rS zgh8I3zt8mtwlBgE_J7s*kJ!G(C~p|Z5atW_^Kl^DhZE;t#01;@cR{}q3EIf$`M44; z1?mBTJNS9Rybu}?IS#^(kfW=kjJ<@gh`qS9xS+kGxV@mbqqw-Bw1lLvAPj5|1v@x8 zg25sVfARTG^oqh#ic%7)U~y$Bu!x9?qN0kbva*yUSWHZuu%ImU7p;buF9Pc20Q*a} zD?#=@Xr=!vt&Fk{42ppJ7{lQne|dqv3mgIWb%A>Wm6d<rx)hMt%+<>g9^lLO`<nhd zH3a74>JM{N^?`c=|FE-+>wnPUe|G*q=^g*K_5%@=0{wQDe{!C`mIxmC8~i&I2rqvJ z6U>VcK|X{~K_XwZ0su^S4Tz#Ka&kR~6nWExzEdwStT^%pnGWCeGFpU+3eAck2lM?K z`r2d?I9!By@!ePsbslvZ8a~>)O;^Z(m-uODZ7jnQ!hj$1$S;v=GLZ*e1Z+mCAs?eW zXXyqmPWz?yHmAFTj$3`FT6~?Ry=Gf9sw&FOs^9LDB6#SD9mB3A6V);T{{TJ$Zv6)C zUg`P+$WYH6&20)Ed0SFr06IMi{Wc*uI{YwQ_r<Sp`9!_s)0q!41~aE_RwkWL01-y3 zQ}X@zM7^I{L>R0gwN$x`>b|K61+X209kkjUNV2eWYz<YVPM^A2{@vwQDYV}O=fzby zzxYDc6gS|!09S56K1km!lZ6ti>}d-RMc#WhDstVb$t6`_)=JB3b91<QK<tJ+1{DIz zuCe9$wbDO|mitxCl7u7ZFM9vKA4KH-A18_<AQAuz0>#^0>5eSr;J)5c8auryg)-)2 zWRTHw9=6u`uEc7rP^q%+wVi{5o#N7v)=lYJkAoAdmjfENvCq-y;N|n^+fD-0bHK=k zt!bSJFu0bS`7z~f>~;&jSkquFGby`r=wwHY&wqlyr>8#^+8#~C5vYwIZ0J9@uTtly zUloLDW^_~2OnRIce15CUq%L|whIdR(tmDafk{UGklkjgPJ)f)hzS5j5?sZzrvwqpL ze30-$ea$Fi$hrSn<s%<7f8m%Eo>(LW<FD6{$JyB?Wks|gUBx}rn?Mr#Se(225r<t~ zP7qeoigZCbG4SL`2Or(a`Z|l|_&Myg-wSX`f6wOv6|Fge^Sy^v(>Zjm{TZD78S@5D z|HT9T-EhAxX#d-1&R;FK4k#>su8&UbVsoWTJZv{nN9(Up_uBMX$^UXJ)JBI{FefYs zhv80h>6k+|GOl&-FKBL4@vxSxJ$qIZik+Tj_CJ0nNy<R({qs5|OK9O<!=l{CjBbv+ zmXt)KRGqKS?2UKTv6vU|jk!jNCbEk;=X=<q3pQD$BPqB0q*PohFO#y*TFKwQ_eh$X zo57@cVP>WtqbH{(%aeENiBLhPn=HNEeZ`Mrl7_0ysy@YKp)Ys1s}e(|zn@U<APzKT z{8oS7$v8X^l=hbsh`Zjf$)V7;yRVI8JpPGfCe^2;7l<;sc5VA8csV@UsZHhA#ugQ8 zVZBycK`W5zr-~LSy*t3Z=I64)b4XfWK~IK&QKPPB*UVY}EWd)n%k#9FM<M6O&esKF z0}*TXJMH!xyz$$!z;%zgH}AT*!*=7{$7sIC9g&Oj+ffliE*MUG&c<(+f5xQ|hw-)r zFNjhyU+1#3N&`9110!<#Bi=^G96xF7ZTu1Xx<$frEu3sCVQ<?TG`D{q{m~SHwZ=KW z8?>%URXp|~?AV;MEzCA4vgUeNc-Z{t6$}mnqk@7AsyCsZv>l9P5uDTk)D+v*<{maI z40*4o21|p%9m*HJ%Ya?PQBly=D+9vD(LSPt_6u=EPgWh*#C8OuYZ_im^hssRynTPh zoz)V?31n}UfPm__&;A~$?S>U~r@)Cxo)7F|G5zuW;xI?52jbQI^BfTrRdY2}j(kx5 zxD3G&`z^29oqzibmbn;GnHYP9Y30x&e=G?GHy2@qqpupJRUd{Zck}3VWBbK7Zdz!n z*LU~#<R^N*^qw^Ia$KUS>~j)WvC#a@2+-s_*C-zBl0M<VC8tH+X)w@j=J2G~)W<0k zUpb(UXh=P<&^!c~J2s?>)un5fh^fE?COEaag&62q1pAHO_Wr}uuO<KO@-8j1HfO}6 zw}PYPlAjCzQ?mH&^R<+~2yUIvTH_>8wJ1McL`97W!y!B81sFsv#WYcQeFIf4|AtD? z%wwkPe6~IiA*eit>x=qGF+@z#Nb!M_Rh3MP^6@T>r1iKlG*pbjwk}yzJm@}UnVC*p z-1&oG&yzbl6gtSQOU1==PX>>?0}8`giCw3~-Wz`!n@Q%jRt%pKT<3w#8>7siN#t7e zlCkyPiKI~*43f&8tW~=(S(pB>)p}P=o3}`C7Uq+yfnTe0E~afvQ2BIGJTJtPn9QI% z|BdF*;fkND{T4ssYs_3_pn|*Xb|{4|J9O*nT7Hid`4pE&b`2x+;)bc2c|i?ndP#%7 zczd<;SeDJFJQW3ebgLO}g~ery^NDc8r0+UY!q!b~G0yTYc_o)#`PWdRgT4p2Nl01* zy2VAqD0kX>aM66osHo~4I~*ImsU71kBv*fs(m?+*i0Nn(MP6M~<-9c1VWMF0&P-Q- zrVLvTl+Sp3etIY8CtvTj!Ox`cCRC*xinYLNGqxv%-Y+?wt9m_C$0wPXI))f?N&n2` zy2P=^59r>^)sy&9-sJ90aL>#<Ju3Hn=$CM1{QkHZ?o%0x&6LSEGDF0Op?mylR58<K z5JWp(N*9|H9do&xu*ouHTdG-%-u#vI;rZ#8_}Enh-+VL_5JPbfVrd#E_NFJ6p8ocF zQ;krWtqxQjZX@7PSQDt)9_PWXZr5Uwq=|ZGbZVxjzxU;$P((mTe~afApFxH3q?90N zZG>zWb6}sqa*A)QKWJOo@9LV*3~DY`T(o}{NtY}uXE4rzFWB}oxh`pjdQmm+=Gmh5 z{D<XX2+;sr{c@z%TJ|9P+424-QoeeRDXyO0How3JD81}+C5e@XZ?SF3DutOjCFt%p zi!mK@qHVf2=>kGAWjSvBO)_Fe=9`r!5e`IEOeR`F3x+~V^cE#1^R)$Fvotej`cD^1 z&8Sh3T7|AJ@1{I))CI=XMvYk9($tQ+o+Pq-sbE`{kls-ygOTik%lX~*d+?!0bLgX- z-r&J})?WPg$}#In;*x7D(%YCY?!FOumwh7`7bMFIr<Em?u~_D#5*rYYtGcEiL)NV6 zD|s)LH#Tj8&hx2yoZ?5WE3{@W)fvDE4~uD^E`?u9h8@L`t3KX()~@rfpPrkhk3&a0 z76h4xqw8JHbIo(|+cT;TgU=4e_WSQ`4Yr{6O0AoHgqFf%zjx}mr0nVsjmWx8HF%1< z3<6~W_jzrayx%`$GmpHap%vf)x@*js%NZd|a%Yl--v3E`(^I=BzdM4<)512`;AfIv z)9OJ-o5eqVIBIHXr77&5o}L=D1|BTu25sgatc@8(QQRydm2??w7Y^Ir<HJRhDf82W z<o&F!0ja+`mbu?x`XFTmpIKkTqP#x^Z~Ic961RMIG*_~|?!j+_xhCN;p3D~V6N<VB z4x4U-za(M4aRai2Jry!3Gw!ZYEQ+e(ESh=7z-l3dXX_AE9Z$mbm-*<uNs^_V-e4Dr z)RSRiI~lF15w>jh;gWD0j<vV9Uw#h9=4aW3JS#J;)FiM;SwNvsKB0Zt68m4&*bPc_ za~$Q=g1+wIGRc*lG>d8iOu)6Ni}($LQl5;Z9HYKlG>vKg3TH<wL|a383dLr2=#1dt z;N^ocyOQl~Zwsv32!G&wf|OU>7sb8HKfZo_KtWEPPp$APnS+zl^<;l#xYDZedYkiO zQ0WtcpBAqzIM-X;vUx`G`Fr+Sw9D9y&}^#Ka@$pzmtw<<vbNKywRW*wt$A-zdrnMZ zPVvDZT~BTb+yU}RNMu+xdg(}cO+S&ZG%BGIv}({!Y%11r&u?2Ac$ozdN&cL3FH6RM z-Q|coK3>bwR#z;XRL+`gmgq9$PI#YAkKR@0;ub`FYb*R<b)?pUidCi_z=rtIl`{1e zng{rLOU!97oS2lNhfwe8I&>yx*itklE)(0)WU5+L_*$j;483M=yxOVr%wgmOsPBh) ztnja|@v`MahgYP17q!dGUvua@mrS@$M|ZX7TgqED<X58O=SM{vX)bG{m9^L^G3Wj+ zA3Hm{V<{FQ8l&rwT#kJ2wAEf&;|n!664j;G+4YPol?VZ6Dq?E9L$5$h%sOR_Y626! zZtxB%HQQa%E66)13KQBLWbs6o`+miNuzB=?mN&GmgtzxshGMF0-l^^_4V0W5tlcZ3 z9uA=8Jr{8`IB{M!1)``IP<<m0A(B9{vzvIO2$7MM;*<B+t08yK3|0uV;=w<?3DwOF zlX6p?Lsx=Ti!NWKSEp94^PI!BR-|QQsAy&0P3dDdVy%F%1+9z3VWr&xO5102ZYL2> zT_GC^oa>|`ohD{OS;CiTi5Aa{71R?+$cjr!jAE!*y@lSmk0o;J<!W0sc%+=MAa=g1 zoE%QUU6=ZEu77_-Ezf%jIcqB9!DHRTue3;yyhIDFe^EN1X-y(o|A_OhCQ%N_?dZ7W zE8o6`FTUD(IO)FsJr0D=S8hCFVq;?)uCNdb+-zPd^_*%jRj}$e3`733Y+1c3VoYh8 zXPJ`u+E`^o!=$&NTvces$Jf`jEBUq$&B{a_kIpkul?Wv|xsYE?FYtL(nLf))cU!$5 zP=|qWSmW|1wA{8)yYQ~=-QC^PM=BeWZ(MPa<d+F+gM<1pEhQ@GyylSdCf=&=LgC<A zYDD*1_~L_=Fpn0~pJPpVZY5XC19E<*VhzxFbsb+UrXznh5r5ah|F8Zd)NdmDRU~Nz zaFN>J6`2r)=|W&G+4n0u!!h?F;^VuF--evYaNW5xNQh*<M{&usfE5%+Ec5zwbDfT& z>gXp@4(<~!C|%^`Qc*|^rW764qPIajYlU-4qo0A(-gggSP}LU4GuS>n}R6c+D95 zV8mCErr7Ur-J+QqNhXvO8=L&)OchX}V`&YH=uMFoQ$yX_JSmH5fSb$^bDYwe+bWx1 zcU64aok)V*oCY(=1=e2^A{Fkq!l64jG?eDQH7mFVY>`q>unXkDMbLU%G<w<G%C{^x z6^ywQtS`|ESTG@*@4F*tE8O3~3?g6Cv6Kd3M>UFOYVJL%|G5HD1IYTXGg2}N-w$MM zaT~9Jin_4uL=>tf@NcUsC@5sh1vOk->g(=Kc|8>SS?wvPr9mT&n~G@sY5jP+XiuHI zLCp4v8XfX&GJ8xg@flQQnMXlCcTx$UUCYx>$D^x1heh*=iKQ)me#WUBbh|}0H<n6| zVRzntV^XD9Gb6Q{7AbGvL3T^4$$!IgCFPJUDkUTGo;kHhIH`mbvEJcGkzA1`gQ(<b zD*dar$ywr0KX>N&I60M7i&wXSBpD3RC0Iro<hJRiL%C_C%V>p#s3CjGuf(UHKATLv zr-&%Vld|!S&H}!SDH8HQ8coG5<X4n_wQVcQC7RGPKWHdJLtn?*VcDXlQ?_@3hM3x( zXJyNlXAtrF<eT!(r#hON1*N5>m#W<->tA_PMMa6WRx1;bRIV%$a<U-t0INhwhzcbe z67W8t?6@FF`Fg?1Scp!>H^yCc|J2OLJw8{B7^*K_DVz&mAO75iuFkf;^T008Cx472 zQerqXh<51WTp6ooN1q=r4P$heZ;ik^WN9>puMR_kE3<nZP>n0H&SA2T@8f;cHOo() z;-|g$fA0grwYiYo*;2a^N9!pA%6Xmaq1KBx3T>^eUwpoaA~18EZh9zMHb)jlBbu=d zz?!Z~060<>G1*5ew?fsmS*jMJ>8l|Xlr<0xe)yG<>qW>$_!B@ZgbA`)QdFe=DEVpZ z4U5l|3D%FFmSr&6Sn+y$QE=ngB$G28)7&=<`$x%40P#slSz9sWV&``4kV#@y_d630 zQa$$#`@g@bc(XM3<~9~!h>tyc2d<qPedqscVTesy^ChVC&zkU`1M__3$I2>uP5)Q1 z_3(d-*-THZ<}l|tH1GrWn+-$bC_=?0z3~zq>fzap-t1$y?kA>w991(X)04}!79q@9 z;8QHO%${^?(5ESnuSpU$YkC^CXLs{Z)b+N<vy&{HN!DKH6#uoKvL)h#p5SCmfq$r` zO3}EdGpE*P7j}H_!&dR<^<c{;kqjsJ&u6>4aGA?MtkSgiyYd<?96kBHs>Iv-l;2un z`_*JRh8($-dQ)}@Z9v9FnFeciW=Y0Ny8_r0e);sOWwxfegx!->8g)=WwYJV$I%df^ z2Q%IBJX-48V+yuh7qMXywpZx%+v}9goYjmQ=t7);7V;7OnK}rhU<aVa$@g4|bMRE^ z{n8a`EZIU0xro+3G#{~^N$>n7!q^lVQqLb}<oAhjf~O#qnT;N@MLsZ9b42mYt82Td z6+Tj8BerUAaTs2^?(p!MpZ?gS{1?kGy%hhrqvO>B7kut+7-kA0vGiqiJlLeM&;T$c ztDhL$I>YB5m&wd9!xifUF;3HI+-WUd?(1@^y{5!E9L2+Q+4~(6qp<p&@>+GV1CC)y z3reBtSH7%eNp`Q4>2k?4A9Zx!sGK-N;V%*cTdiDSrH|gjl&T+~g!GCoNCZ;+-2m_F zi*xy{pqSkAmg2xNay{cE8RMCfmjz=AO}r(7M<zQNF!z9&XP>SgMVUs+xZtEomzX3H zCd#t8*gi!JS2qsl(dPGzy%II_6Mdzhj^%u_=N;{l`6!p7=!<=Q!bCcM;a*T<8E+39 zAKfAFhuR;(s{O<%#Ii<xdssux9c>s!sfXG}6O$UQ=dXStmqg!D(u1<K--Y|!v1Po7 z6E}*IIw~Y|VlJbd3cbGZx$1gGoI=+<*~|*PYc=XvF)hA@W$vXlxTZEIz9;Av+rT?N z;QRff^%07f`~2^B-hbl4aDR%bsQ2w?&v(WZB?da#42DEQ^mjj#s;vRj*?<p|apd36 zDr}vhd{UN3D8kv3FDB&{{>VYH1aE~q_4+Y`V7fo_SYk2SXxQB&<!O%B+6bc+AX~RW zM2clf`Cajc=j=8`tTCdz^KUn_5J5T)_>uO9niDd<+b_7nP9WD<oI|=ZqtQX_b)6$m zake8LBiv)6dvnK#HYoH-iyt8*yc5%Vc_zmTsS$57$o{2&2HbjYgH4|g;`XL<`uC~Q z+suj+D63RUgK<;0LeN+CHH>JMF`?EddPuh@Pnb`7+=5UXpt$$~d`(}PrS1|+gV&_z z7IK4?WCOmwQK3~e&MUdjah<P8cY!!SGxc4k=0&Fs!+~4qf?gtoiFe`+HEwVAKZlzC zF8u%d88;*=s=xDe*Ndv9o=?dnjL&tuP>XBw20hQDv;oWa-bZBrX?Xfy<z!k+Y+Q-w zN+4>PV$*DATgCy-qR;}Lr*2;C#K&J_lJsDlX?pmfS;t&_rt>4WrTJB8I1V4VLBA-l zejAF8s`REWEmTXwe@b9pI9wemH_lhO>^59VyYS=3;A1)-m(E01NjZ)Ws{kz`s_mt# z%qOHK7d#ayHNoyD_uYx_?(Oa_Z#2$jZa*<fV3KfI!59BnTy#Rxg-nsmUW1NgjE&Iv z&lcIDp*9JJEm2n)=-byu${8wc-epR9PD0#AEArdh+am%A^<E+R^zhacDaDq%kfZ_5 zCn}1fnhDgv5D6>CSho)H&BsRutdEOK*21o$0t4}>Tw1)MqN$fIUFz!X)skGOudkn4 zt+s2M-If=&^jsoCs!^~$zq?*gV;5OWrghW5M?LKAQdCTg5uvYv-@8IxK`6+NkB?K@ z+S=CX%8g&yOSg}@F*_`p$JVKhE5}fEdzzb%vvy{J>^83tJ=Ju(FTM4|C|$s;s;kn~ zZplr6R(wFS093&ZwB>a}e0(U8R}?#Ml5i<@kvuj_$R-tSXMo$0N1t?ISQr?bOG!8R zhZ)Wd?2a>1*ch3Z_#1b2c0P^{B@w!n@onykBlLV^RusL6VN7;BRz&p@;iK;UemU@D z-}U#1HwhbvCX~Q&+Oi(e5$PCH&M%m4$R4_TlG<ehBE!v%Y5yQh-4SMp4Mu6|>18d* z$fm2QsolGrmo@(R^if8aJ(QEA-MWy-J|PbL;GqC5a`x-{M+?DUyu+MEae`6#o!Fui zS>!C6)$_v2W}g#FX+A!UK=u|IG}~9Gjz_ul#9$Q2`HZXM&w>6w4Y~eX5b&#-s*IR> zyB|&BGAWdis>U83>q%An19mOQl*PX1JVq?4i7Xl!{3brxq#UjJy7{%WI2xuX<f^2j zcM<kgvT<5!s*jb0lM}a2wz$S8BX(Kj;Ho-02mpyaJ;LcyOhGK4Fw~lwrety!tW}78 zJv&*e9&QT_eG(g+M{wJo8z2(nz87Gl#n@#E3JTFG^5<P@<5%#h?s@$<DvBwgisu?~ zMIo&)@s{an>uec6{$dQKXYBN7t0Z4J#&8Iu!zUv0I*$!E9k{>z?FKcZ!LUvVre6D4 z9F+h>1ivMiQ^>p~EHy0+E})#6urkC<6G=5tFWH5s4<nmO5JsK7dnRLn!)a(Wh!~U2 zpRLyoc=_S6*nr`k!$VAW8c(kyb76@{tY(h;?n$jMNk$T_Q?`OkWPQ4sa#X2t<Pm+m z6Rfvq%)r3l$G2|=`iY3Kw|;9(3JC@e_I>vv<pkDAp>@WgQpxqga~b`N(#giL9y%+x zH#fzhI1&mfDon0iP|vy0?c0jc#|`kgS@7Qd%O#DI?B!P|ZBEm{I$?G0S(!bTsz2oA zmxr94;9tn3&?{Nup?IILqj!_5dA>{i#)Q&*1%3N=qRvbmjHxck+Wc@|R1L6i(p#U3 zK{@cnq>p(NnzET=GQ^3Aw7^9z952Ut!>&eB)@;9ElsI_UL=UpPOIIbB^5&M-=q2ll zOs7obgBF861`Y8h;RlaN<#)R{O<NfVNuC$W_NOcT{cq793Gc$~qzym}Xw;gB1q21F Q0|-A26<tV`(u0Wq17l)A{Qv*} literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/icon-viewclose.png b/apps/fo/public/images/map/toolbar/icon-viewclose.png new file mode 100644 index 0000000000000000000000000000000000000000..d93ce9c05f9dbcb69d1987e3b601ffbb9fecaea9 GIT binary patch literal 2895 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 literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/img_base_map.png b/apps/fo/public/images/map/toolbar/img_base_map.png new file mode 100644 index 0000000000000000000000000000000000000000..7f96fcf5e98fee63a2e89b39189059f7d38d82ca GIT binary patch literal 4537 zcmaJ_c{o&U|2LGaWGmT?38@S-V+><ohLR;DYnCxH7|epP%a*N3B4w|T$}VJWh$&@k zkuCcg36(8Ezv+3Np5Ob&d%fqn&bjaVd%mB~cfYQ4of~GR=eanAIhmN4xC}3#EEuag z<CbA(W;{>!lZF|K5JlgHa+%~x2|)Ycm~^lt7aY)#fOf-K;LzA0?{_!`f+ZYpX+yCw zF;>Np2=eIPI`V-8G6T&Z)Cwe{F`hUI&;{p)Cu)G!8k<2tJXQl_tz-f*A?xAX@fU)9 zaF>HkEiu8K7$g>?r3q9IRAmqla1=B!kl;o1RSnbt{l%-w*#8zQfPjCgP&_q2e>-Jk zVg}SB`QU&`@(3^n3ReOuBjuq8MK}^E2ZTYODhd!41*jqzicp0^RADgSKNpB$%?InM zYJoEN#}?zH0dl8M$f^no0RaK>0gCb@A2$Uk5{XoRz!YFGFhc|E8$_g_1HnY!Q-2sx zIA4qpo=m}$h``^BXcv+nMFYg}^zRS|WD}EriHW}dB#MzTg+Me}0V)qsAP|1X^_R9U z#RB*LZv0nmU&|mePQe1_OY-x<FzVrY>JONayZ>$Iw<5zE)k{8jMp4jSC=$kxfFn{2 zQ5qn|8+j}qs|rK7!f`McI2aAZ!NAHGI0TGVgy6tPoU)>lD^^iO5eomq^WX3&C1nUg zR~fEkfKq`%^^v-I2D-WsC<Ja`pn`%Rb^l-uiM|vx5rg|<8_%%)4_5JiVpa8gaA*q2 z$C5<y`qKqw?j#Dy*PTQL>gfSxt?@)GDZuy4?+X1LFbd~`_s3xkd`JY~Uny3_{}=O0 z2pkgb0>^@J2uA!692^Q(!MY;AP$ea#G7N)&LzOU~fAHA<NZsEp%8)QZAph}16^CH3 zD7w0UU2$+ESOp2kfYC@S46FplK$TsPSY=ln5~RRzQQ>#j{6`o45iwfx_x9hJU>yFP zDjbn9N<NI4Ijfw`$C%?@LzIqX;75ur-g?xAFAWPG{5&4P;e3I;U*lT$-mh@T<ZfqY z9L1R#z&09~hO>37?ke4ulDzQdwB&Hg=4#^=zvaOM6`_f>e6y)?c&YHh;C8{yF|S<9 z<I-P;QtzARqZ6K|7)-mXXs(6#apg>g4YM(3<Q`5WR;DTFMxem{@v3$iLs(AN&wVOk zsQ<2}QOd@_sP$uz(2E$6L*}%e0gr2be%Jl_r80X?j+Q>bpKWd!|1v}!A}SSJ)c+XA zwtM#%Z?r?jd$3!rR_CWSDNZi>XVIL%1J?Uewi=p9YI8GJ6qv2h<IUz~&06_(oYyF5 zP{6lDcgr{wWN7hZAaw7b&arW?kJvc67I5N9*Q#N^Gr#5L*~m+IOLIZ>>Fz~&%dGMZ ztDkvRwX(Nd*QMo+S}&FFBc2W{w@laf!*7_-i-wjHmYBI&*~W=Krw;@~k9dJgFV;B> zNsr~FFZ?{c5z5Vc+M(pFPpKozDxqS1f1s@mYz2^`x>t-$O~0Iok)n?}AL;P)i(@~A z_zAH*u`=79WtZQt@mWrwOeJuy7<dLJIZt1V1<2mB^@NK=Jm0dWkK~OIXF%fcjLwJ? z#_OmSaq8Ztb@6}{k6iCsJkL&8%Uj8-_2>4YxZEFRT)S5D{b-ecXlUZC*Jya)u7d1& zGFhb8=tNDp_nCK~CwLXni%~YTlqaCucup*Ec(P<{p6{er@iE#kYuQrlVd|Z(!;@#f z?ThsCOyX$j_Rr(`*WQ}9tW;;+E%8DE2TeXjOPc1ns|1%=)f}y?W!<G8;PkuWTW%)2 zMxE_TdIbi{uzL$KE32?lnrcdf<DE*A?>-}@x9o3hpz3T5gk!_rH$QZcez&am-69B_ z1=ois&xV3|@H{j8hE^@#))#pb@;+GFzIyCYvpd}uV>4ZSvuRbVSmp+@|L9^?g?KB= zrx4AYpVS1A&$nW6A0mu_RFmGXU%w{P&P+<BNbEu~x>8l-nSU&wwD+73zA!d{zx^D< z$##j`FkQHiqf#jGQ%&anwBCcf2Nte?Z!6=3Qu86MD;Md;$IId6lIDrrY*KGR8-|Jg zd6v(VMUwChH0AHliFOP7`$JMQ(;ejeHyi=x@f+poX+~6`vo)FHOB*QO`26Xw=E}#% zKlH&JyT|ii^e^QK*v~1k?80L_WO|lnp2&hy&FJ{Du{c@d)`|hVsZ3kT_Tfh^NJ6Mk z-8V6H_E7#+srf#yk<I@8^%1W-Z_G1OGZ(JtRZBy^*IBWY<N~d>?AJzX%cY)K=%=PF zQQm*4Za9C~<-#<g*yk=F)qF{5XPBQCR$~zvPs~897r*77X`D8e$#<UB%d#uYEqp2x zo&%#2=z{78%JX%X0k+YJPV!bQ4)CPVM~AYj?ayn=UF<;D8lWHAOTOpLejgac70~z+ z^!ci&qC>~G3$`whLSC4@l~#6m!@;P;gliS1FDs288cFxKl99ybu6jbBSYvufXM#BR zqYytt?&;rFYwdDu`S7{AunMOG)!-Bj$uj*U*r;0=Is4u{Q5(R6byKy^&dr(Ovxnf~ z9Trvj&p+<;$`vn(v3kUG-`Wgi$fxBL9wv0@k&bODCMc>wlO}rqt#FrjiY4=88`VDN z7%?O`_-#}syGVFG-fr;2`&x|d7*RqJb`<KJc(7)(5EdSBRW~%*PG7unl`nqus_5a$ z5?(%gpbRZ|vu)|{Y1d|Maq6{YxTki;Jrv|?0K4=HTI8b;F|i!fjps)${9q3d*4ulf z+y_r|xoby_qd5eV0YdF+67iKFA-0a!<MZ=w$17Wq0x<(VyL+=7KBiG!y9NRZta`d1 zCFNhNX!9b^$qoSMifyn26$q)Kt#RTT(kezHqQs@PcW5?$c0ZDKXL^-YWNq@-PHJ@w zPgOTxds(BwBH>BQT3+S@aS0>aO4K&OSR+7gW@A1`T{u9^BxOBCcMi%=3*X=AaV>to zlueHOxK>+R>-2~ti2%6x=(<ityH$^TZ}#!I4fn*G8x`c*kb)~<FQ%Nty<6y+g&i*d zZ_h_hJ_U!h4Hn5ad|8{qpJQ9~k46fn{MuQ+RrEPVP4sqb)l$JI!Tja^m&1bB=QLpY zhi1g=x=RVjF%O?Z56O)j7LR;PS+z&j2J<CYj#G*56|hF<kg%|_B}6+H$LZ1ZcD9Na zqbvAw(nmzp_0s_F+J0s+XTa9i{>_>~p~EE-TGUflMB6)g5`x<32RCimMpg#*R?sKE zs?+64fUSy^>RWjzO-)Um$(e!F$+oR}E!y<--c06J)#meJsY{?_z^f&^#DPG(<YD#( zLe`kI+`{Voz~fzh7g)ej@yyiy?5Qzf-o=&7QwH{NbwxLW*&k7KuPBpyTvs^q#+Io1 z*+w$qqF;hC4ctCGczFG3MSJ^NgXuJD)WlMZVf>wb`pCxXN|W6FWrw|;*~90L!e&*( zLYt4I7Ay?!FiAE+A&)2Zj|mrw3uMgkxSCs$IjW({E6h&CCKJv*4NRhmMV4QAx~;ZQ z<^{qhXjSV}RKTvHOi!0Vl}Dy7U%gQPBIMCS{uu{Bu`<nxIX)@!Gjw6gbb6n)o+M|v zsuT0e>`S>1s_Yi()47jC*Nv|N+Fe&po%H7B$?u6Vk8V0{RQE0W)@{>gxv-Pm9!s1z zjGJ0KH6^u;p+h2TYt6s(_O#;ZsHWPwD6>!yIy4F~Qn+)h60HK(O@u=A5`&1a96b+U zlG(e?sD-jt2zahd#>TrY57i6(#5;4f6n%pydBp4OWUDxHW!}?JBWa8cBDcOTZSe_j z{I8od?bO+LLa|lx<&zPOKfY}^+r)ybry`kZ9Z6F{XhFG!1cUt85Kg!Jjx^a0PWI>Q z<gt$V5IyYz(<k-W3g*ZL{P_5U-6HF2vusy^m9#Ho<U&&2C0yBw3e?pp!5P)H>bEyv zO^K)6BDG07Ip2HX(PWy8NU!rBeVN2cv%gf)exhARLI6E?GJ$u@<rVZkAgOWiDOZ^K zseHM9gz*YNW^UVCgLN!rUN%L4ffOP5OU{k%+NiT)$)ip>fC(#q?v}iXK01~1PLQn7 z#%Esa(eREg!EsABak{!LCr)VN8tg&2(p__X<$ml0G1fZ;@0m#zvd9RTS2J{q8&tkt zn0UcZ?i_^F2IqG%C!aJb3K*S>uTPuq$bEBW>}pzuAyu5`NOF^ALFSvjB}&sIL9o5t z&c64Zmaf_dEHW-jBB?;SJ|yi<H9P}bC#@=ULpPu%O3*jSm&STNG$_qhNOL^`6WR~u z@|QvDet{V0^1H++>!*W{ejUN11U0$aN1k1<1xys6rlTz?;m4Zuk)tP<pIh*qHwqXp z2{0L*+44YyKSNHbWOOY+oD95kDeS~%jiQ?+m_#GzZz#BtNpW83h0f%oBQ{0L1N&jz zmm9cVh>)(0G`DtNMqEp~AD+**Q)#-p;4yuh)`|c?;TIj{UlO;Y{XPb&iuD2KhQ~Vg z4n|2uR`ZilcY=dMi`3-KMOWt)y>iVd@Y!CB7PI1UiHuh8q)&X*ihjS@C1IuobkVGm zw3-W0+D>?}z0Q;EhLmd~)?OdDlav%3i^F7Ro95!x{k;~oU8#$526G0SgWMKe+iW<j zZDs6!56}7cQ%k1K>n;dDkf-`SW@1a&Yqz5?{Q>WN--stD$>Hp<E&d>OkM17lZcz?1 zo{?{meoOLE&z3JPY3;X0Q&iPjTXRy1@|Ye1#>bM!F5f#>$Eg($kCV1Mn^sI0d6trM z1Krbmp8mn;w8~?1JK2So7X9*UhY*p8-ihkbIZ`=}^+pw~$8V}Q{uE~gyOMVfUR;00 zQY-y~soowYRbQ(3wAoj4YPNT}yIcOuxxNRcR=!|*qP@`AC`+P6cR^(Hjm!1nI<bjC z04MR=VJ)n@GbRzDr)gNKtTDu5o7<@;SfiVh63gT1(dgHDYcX&`w^091P<Q=m2i)`J zgdx?@U*^#DG7*n@^G~h7@BLHN8@!&{lp9qMb+7uebFMN$i;lh42n<dZ=~8v!N@`On zY`7C-tgp#&>Kr8QzTDl99=XYB7*R~I8OIM-^;O*GT4C+6b9aSK4Ku!cUQ*z@AG2Q% z`RCl*T^|MWx@;snCJ7osbExhEMX2~|Hr1Q$#aUmlu*1~(w%PceRS)82aIwJ~J9AEq z$;G37scG}AYO5-uP__2frmCOc=jkG}9i?wMRt0NrXQ>JwZ1k1TB1o42!}v<shkbK4 zxQoWDx2`=9*_xHt>)e&rS}#qFNnr`^T2DXbv81h)(fO&=|CHA2ymevJ(&)Yu$<*fg z`j(vDcMQk${?1vt-(F;rEkY~3lP5ot2`cq#cQ-Sd-=t=|5VM=0DX9DS(ll4##p9xi zG&rRt)a_I%d$>f;f{{(LU4AaxrcybKmN75OcVCRR$^S?8cFJv*_IvYWzr0ldIQBVm zp=0!FxXc}%p^09H;JrGLh0E4y21jfi(S-_r)@6j0B@F-S>dsEclW|oPh5aRW{y?9` zn$xiV%NC|1U-vq@&;5ver;zEdSytG*C<nSyHRL6xlttt9yM5m+Oh&Ji1!RsB=<;>4 zQ6n!k`_80)1Y|`6GH)}R!1!pBf$IKpiN+~~9=U6$EUc}S8_dBi5qyi@Sr00X_gO{# zTwUqW<6J&*Ol=`wo<0tub8ct86PA$ub-IP=*PKr2vB--(zkj9}>YJj<be*IA56zr4 A6aWAK literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/img_network_map.png b/apps/fo/public/images/map/toolbar/img_network_map.png new file mode 100644 index 0000000000000000000000000000000000000000..df80af6dc4df8e61246befe6d6a23d2ac0fc3472 GIT binary patch literal 4974 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 literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/img_road_map.png b/apps/fo/public/images/map/toolbar/img_road_map.png new file mode 100644 index 0000000000000000000000000000000000000000..02d015d12f020530a3a2efc222e0f7918c15a6aa GIT binary patch literal 6079 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 GLH`5!q(X53 literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/img_settle_map.png b/apps/fo/public/images/map/toolbar/img_settle_map.png new file mode 100644 index 0000000000000000000000000000000000000000..1a93f50e8596c02600e6a18cf8a101c3155858e3 GIT binary patch literal 7264 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 literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/loading.gif b/apps/fo/public/images/map/toolbar/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..7c3683bb49dd2f261c1d3898c69136c8781a7643 GIT binary patch literal 184974 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%0As<TK03zw6Qhm}TDq_QW9wZn5kI*V~U$ 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 literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/map_pin.png b/apps/fo/public/images/map/toolbar/map_pin.png new file mode 100644 index 0000000000000000000000000000000000000000..b6cc2f6aabbb4b374e65c571ff8fd91f3039d883 GIT binary patch literal 2362 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%0DVE(CFH!U*CsHGu|^nL4A zM(evLzg_y>)1AhiHw*oIBaHogJ1IFnwH{?2IfZ`|7iS+SI@-GyZGG;`%NZHJ{;Ete zceZwaH!w1<?8TcqcY9bu;ewx!9<ABWOT9Og`qkXIIfNz#va73W@&!vHYYI0{erI<` z>%YobcVOmo8sn0SIw?f*EI-GmH!u948<+lWe36)Pa?SC>zS($j&%o<szX<DMcHiRi z=Ge2gak<>8)hleH+OkDd8(ZLdDhH{H<Ntm8m)zdOpgCAh!r-Zz8j@Q<=j2ci_U+i| z3YYt|lAAp}*nw9A11To&y<Tu~a`ukL+d}cV>XehQxNvhxWK^iWM1LBAL}-W8uSqtV Rco_a>IDuj8YX5|7{{e=c*p>hQ literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/toggle_off.png b/apps/fo/public/images/map/toolbar/toggle_off.png new file mode 100644 index 0000000000000000000000000000000000000000..d5dea9f6764543a8a2025d215fe00361460e3da5 GIT binary patch literal 1591 zcmeAS@N?(olHy`uVBq!ia0vp^azJdv!3HF~<FelaDajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_cg49seoArU1JzCKpT`MG+DAT@dwxdlMo3=B5*6$OdO*{LN8 zNvY|XdA3ULckfqH$V{<S3ODsN@GWpo&B*kqDoPEm@(W3>%1*XSQL?vFu&J;D8jzb> zlBiITo0C^;Rbi_HHrEQs1_|pcDS(xfWZNo192Makpx~Tel&WB=XQrEMXkw~hZmDNz zW^7_<siR<IU}&LlV4-hltZQgyWny4uWTXHEN<iC+Qqrt~T-=~`0eQAc86_nJR{Hwo z<>h+i#(Mch>H3D2mX`VkM*2oZx<D1W#g%y_i50qe#mX=fTvCgZi!uvJGV}8kKqe+8 z<(HP&Dgj*z@j`9^+}ONgXfOc-Our(rK;KZ$0OTc@LSJ9}N^^7Js*6j4QW5UOYH)E# zWkITbP-=00X;CsT;?k5sRuxz|7o{ea<QIkH=jXseF(4zqB)>Q#zd*s+85C-k3ciWS znRy^FupVDuE6=>*lEl2^R8JRMC7>yKnVBh8#!jYg=9Z2o#x54lhK8<|PA0~NmTm^d zCT4EV#)hsYFugAM$)&lec_lEtDG0r$IQ4>(Lv8`kW|!2W%(B!Jx1#)91+cfRGI6`b z2&Z{ay(zfeVvJL-KF~4xpvXmvY?u%*1%a6GqzmN06Mt$RFvS-EleWdf@=pv5Ov^o8 z978H@J&D+#E#fFrw|O@Q+d<!lLLP~Q3o^HGWIg<^(A3+pK!H6_AevRzXK_bsuZEbI zm}AT9rW?zI)_o9Aej&K_h;f{V@Mggycfa4cDPKOhu<ZM_GifaM-!}g>{d~6i^V!=w z`yG>b+NPD;bp;;$x-8x2#T?J?t9Tq(JuIJZwB$0F8s2Nc?EF&l^u0nA2Ja869w=#W zIcV@CFzC6>VZ606`q1A^C955rSN3x7om+lhJF&*^NdJ$zKi!jE8#+EFKY44ADgV7^ z53ibs<Bn(fKh~ygw!Hnaq;A=QngfpK9#q_q-mbv0;`-~r-FNqims(2xba_&(B;Q{X z{={1OzGB)XCf>B$W)<_;-{pM|IVJ7RurVa2&|z|6L0a^>3+ZO}BX0$=Y;#zys<LrO zhOVgLS0?`7DM4LNnU;#rP_12ct$wedu=d*Tre{COtM0C_>zR?3kj62i$2BLbZ|1@f z<4Y1BH%jY2ILluD`=n|0CdRYu>l0UQUpP7X>4D3<;_v3nY%2aP{_yXo{z(<4lV6{( z6VID_k3aqWzNUBX_0`-bF0L%JD7?}9cze9ql3i?J`Z{&3KhJU5>@`~39KHCh!@T`} z*{;viIe2Gj^M>ov+7W(I!FS)SJM?s?p3SZZo>g<NUXOnN;9)ECg&7i;ql~<R|Gs&( zuzr8atlu6JR(8x>*fG;DEd2I)X=U+0=_}3L^b-44`uw~&CrhYReCe&==WTMTx-B6= zF0!h|zm5Bvu8S8+v<WD!Th`>QVWG9?y0UA*g}VLx_pe`<_da0sLZD*jf7Pi18rDKP zId?vp5~nzQMuvj9An*N$;)-qA``&LqcmB+sp12>X4QxTD*q=<kYIB!K`kAYqwuypg zee_fj!~DLR9dV`V4qd8SGc6@2_ugEQbTa;3ZBgr|`%F9xHI9{=cQ>1S1r_C<u6{1- HoD!M<M2TN! literal 0 HcmV?d00001 diff --git a/apps/fo/public/images/map/toolbar/toggle_on.png b/apps/fo/public/images/map/toolbar/toggle_on.png new file mode 100644 index 0000000000000000000000000000000000000000..9cb573875641bac3e949b4c21802a1e18c6fa8b6 GIT binary patch literal 1612 zcmeAS@N?(olHy`uVBq!ia0vp^azJdv!3HF~<FelaDajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_cg49seoArU1JzCKpT`MG+DAT@dwxdlMo3=B5*6$OdO*{LN8 zNvY|XdA3ULckfqH$V{<S3ODsN@GWpo&B*kqDoPEm@(W3>%1*XSQL?vFu&J;D8jzb> zlBiITo0C^;Rbi_HHrEQs1_|pcDS(xfWZNo192Makpx~Tel&WB=XQrEMXkw~hZmDNz zW^7_<siR<IU}&LlV4-hltZQgyWny4uWTXHEN<iC+Qqrt~T-=~`0eQAc86_nJR{Hwo z<>h+i#(Mch>H3D2mX`VkM*2oZx<D1W#g%y_i50qe#mX=fTvCgZi!uvJGV}8kKqe+8 z<(HP&Dgj*z@j`9^+}ONgXfOc-Our(rK;KZ$0OTc@LSJ9}N^^7Js*6j4QW5UOYH)E# zWkITbP-=00X;CsT;?k5sRuxz|7o{ea<QIkH=jXseF(4zqB)>Q#zd*s+85C-k3ciWS znRy^FupVDuE6=>*lEl2^R8JRMC7>yKnVBh8#!jYg=9Z2I#x54lhK8<|PA0~NmTm^d zCT4EV#)hsYFugAM$)&lec_lEtDG0rWIQ4>(Lv8`kW|!2W%(B!Jx1#)91+cfRGO@VD z#mLme#Le6kXr2>xw?Oo!U~vmnuNh9g`as9%gCZ9xvSC8N6a-?zlP-`0PyDHQz!YBu zOxjF&k{=itnD%(OIEGZ*dK0lf|FVNfU3#>~AAwcuv%GYsE^uIVb>iu;XEI|`QR84y zbZhG~ICw$SC6Q6_paZ+wKgMZ10*ZkGttAdkK|w9ICh!FOwmtW}xY%}X^6Yt&8RI^s zJkQzxe&6qp^FAAP^g5oubndgn*PnY|N(DC=uU+fG?$a=(Nbihs!^}Mzk6C!OX6x)c zewjh$Xm``<1uGa9UTWkmm|Dp6!mE7Bw>1yV8ryCeYgtsp?_b;UD29ix@kfX95%+fu zp4O+f{ir;&L)Rtdb(vN1)vT{>i!c6AbzIEHt~pou;PxCxfeX`@s;;{Jy1e4V-aE&4 zynpzv`2Nva>+iX*JggE9#$0bb^+MyvzWT6r(*BHvKG{c^y~P@hk4pw7sePWyW4-DC zUxdlE?w3+!C)74``RtwHBb{XHc$0P7g=K%^^^#TV(%x;iKJK#fy>4<JJAcfQc{f<o zzN|NtyC$>QsNsH1*5Q}Y>(}VMj&V(TSj?_>ZeMHlbiVJ$x9;3A>vZgjbLS4f<(^zn zQd7>BoYr1=<jbGCl`|~M1^V7gZ?rmDD>;8wC2zW4$b%<}_rICF<Ns6hOTwo5W|R2) zIv%seH}bbR`Pcaz{PLJTAU;Aihe>k%n}+uA<qvKx{(d3i48!)=xk}HzXS+Z6b@^zI z>)iQ<%1WE2?zA(TU67EJ6twTb+T#Cff9%TXmwEdvD|+>=f^~9HkuqY*35Qo5cdovf z{Gq;&{p%~|$SnS;U!2Z|JUqJM+mw?Mrn)UYK`pVzK5p{+*R%N1Q$xPP0s@7hTzU(m z1bE)O^$<)HaLQiF`gZ<Xb*T+}x0vJdYVV)0@@!r5BJShVOTr7M%vsc}Av9&ed;wRD zb7gBUzdaYb?rNUaQ~p%-3ksViu6uS<?1n+_&UF`F?0Oug>gqE)dD`V}HD99~O(Ra# rU0T7ra?X6}Qmv0v3u^sj&&0#9{^6vi&$~|dfy#GJS3j3^P6<r_lI3q4 literal 0 HcmV?d00001 diff --git a/apps/fo/public/mainDashBoard.xlsx b/apps/fo/public/mainDashBoard.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..9557d13d24f8e70f7c658624d7b94552283710fa GIT binary patch literal 13783 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 literal 0 HcmV?d00001 diff --git a/apps/fo/public/next.svg b/apps/fo/public/next.svg new file mode 100644 index 000000000..5174b28c5 --- /dev/null +++ b/apps/fo/public/next.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg> \ No newline at end of file diff --git a/apps/fo/public/vercel.svg b/apps/fo/public/vercel.svg new file mode 100644 index 000000000..770539603 --- /dev/null +++ b/apps/fo/public/vercel.svg @@ -0,0 +1 @@ +<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg> \ No newline at end of file diff --git a/apps/fo/public/window.svg b/apps/fo/public/window.svg new file mode 100644 index 000000000..b2b2a44f6 --- /dev/null +++ b/apps/fo/public/window.svg @@ -0,0 +1 @@ +<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg> \ No newline at end of file diff --git a/apps/fo/tailwind.config.ts b/apps/fo/tailwind.config.ts new file mode 100644 index 000000000..33ac9204f --- /dev/null +++ b/apps/fo/tailwind.config.ts @@ -0,0 +1,12 @@ +import type { Config } from "tailwindcss"; +import presetConfig from "../../tailwind.config.preset"; + +export default { + presets: [presetConfig], + darkMode: ["class", "[data-mode='dark']"], + content: [ + "./app/**/*.{js,ts,jsx,tsx,mdx}", + "../../packages/common/business_components/src/ui/**/*.{js,ts,jsx,tsx,mdx}", + "../../packages/common/components/src/ui/**/*.{js,ts,jsx,tsx,mdx}", + ], +} satisfies Config; \ No newline at end of file diff --git a/apps/fo/tsconfig.json b/apps/fo/tsconfig.json new file mode 100644 index 000000000..493584782 --- /dev/null +++ b/apps/fo/tsconfig.json @@ -0,0 +1,54 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "noImplicitAny": false, + "baseUrl": ".", + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "verbatimModuleSyntax": true, + "strictNullChecks": true, + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./*"], + "@common/components/*": ["../../packages/common/components/src/*"], + "@common/components": ["../../packages/common/components/src/index"], + "@common/business_components/*": [ + "../../packages/common/business_components/src/*" + ], + "@common/business_components": [ + "../../packages/common/business_components/src/index" + ], + "@common/network": ["../../packages/common/network"] + } + }, + "include": [ + ".eslintrc.*", + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + "**/*.mts", + "**/*.js", + "**/*.cjs", + "**/*.mjs", + "**/*.jsx", + "**/*.json", + ".next/types/**/*.ts" + ], + "exclude": ["**/node_modules", "**/.*/*"] +}