Compare commits
24 Commits
f04fc5f575
...
mantine
| Author | SHA1 | Date | |
|---|---|---|---|
| 32ff36a12c | |||
| 416086059a | |||
| 37bfa912a0 | |||
| 145827ab6d | |||
| 1f9a3a8e03 | |||
| 6015218d59 | |||
| 442255ebaf | |||
| 3bcea3f1ac | |||
| ada3b63b8d | |||
| 0ca6c136e3 | |||
| ec622da773 | |||
| 300921751a | |||
| 4cc3a919ed | |||
| 349d7449f0 | |||
| 8438e05301 | |||
| 85bafea7c8 | |||
| c08f839b70 | |||
| 0788a401ca | |||
| e6b3dc05d3 | |||
| 2bf657e8ed | |||
| 59fded5cab | |||
| 242ed1aee2 | |||
| 75d6420d6b | |||
| 7e8d1f50c8 |
20
.env.example
20
.env.example
@ -1,10 +1,14 @@
|
|||||||
REDIS_HOST=redis_db
|
REDIS_HOST=
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=
|
||||||
REDIS_PASSWORD=
|
REDIS_PASSWORD=
|
||||||
POSTGRES_HOST=localhost
|
|
||||||
POSTGRES_DB=ems
|
POSTGRES_HOST=
|
||||||
POSTGRES_USER=ems
|
POSTGRES_DB=
|
||||||
|
POSTGRES_USER=
|
||||||
POSTGRES_PASSWORD=
|
POSTGRES_PASSWORD=
|
||||||
POSTGRES_PORT=5432
|
POSTGRES_PORT=
|
||||||
EMS_PORT=5000
|
|
||||||
MONITOR_PORT=1234
|
CLIENT_PORT=
|
||||||
|
EMS_PORT=
|
||||||
|
|
||||||
|
MONITOR_PORT=
|
||||||
6
.gitignore
vendored
6
.gitignore
vendored
@ -3,4 +3,8 @@
|
|||||||
__pycache__
|
__pycache__
|
||||||
.env
|
.env
|
||||||
redis_data
|
redis_data
|
||||||
psql_data
|
psql_data
|
||||||
|
postgis_db
|
||||||
|
tools/import_bounds/*/*.geojson
|
||||||
|
tools/import_bounds/*/*.md
|
||||||
|
storage
|
||||||
@ -1,14 +1,9 @@
|
|||||||
# API авторизации
|
|
||||||
VITE_API_AUTH_URL=
|
VITE_API_AUTH_URL=
|
||||||
|
|
||||||
# API info
|
|
||||||
VITE_API_INFO_URL=
|
VITE_API_INFO_URL=
|
||||||
|
|
||||||
# API fuel
|
|
||||||
VITE_API_FUEL_URL=
|
VITE_API_FUEL_URL=
|
||||||
|
|
||||||
# API servers
|
|
||||||
VITE_API_SERVERS_URL=
|
VITE_API_SERVERS_URL=
|
||||||
|
|
||||||
# API EMS
|
VITE_API_EMS_URL=
|
||||||
VITE_API_EMS_URL=
|
VITE_API_MONITOR_URL=
|
||||||
|
|
||||||
|
VITE_API_NEST_URL=
|
||||||
1
client/.gitignore
vendored
1
client/.gitignore
vendored
@ -11,6 +11,7 @@ node_modules
|
|||||||
dist
|
dist
|
||||||
dist-ssr
|
dist-ssr
|
||||||
*.local
|
*.local
|
||||||
|
stats.html
|
||||||
|
|
||||||
# Editor directories and files
|
# Editor directories and files
|
||||||
.vscode/*
|
.vscode/*
|
||||||
|
|||||||
486
client/package-lock.json
generated
486
client/package-lock.json
generated
@ -9,8 +9,10 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"-": "^0.0.1",
|
"-": "^0.0.1",
|
||||||
|
"@dnd-kit/core": "^6.3.1",
|
||||||
"@fontsource/inter": "^5.0.19",
|
"@fontsource/inter": "^5.0.19",
|
||||||
"@fontsource/open-sans": "^5.0.28",
|
"@fontsource/open-sans": "^5.0.28",
|
||||||
|
"@hello-pangea/dnd": "^17.0.0",
|
||||||
"@js-preview/docx": "^1.6.2",
|
"@js-preview/docx": "^1.6.2",
|
||||||
"@js-preview/excel": "^1.7.8",
|
"@js-preview/excel": "^1.7.8",
|
||||||
"@js-preview/pdf": "^2.0.2",
|
"@js-preview/pdf": "^2.0.2",
|
||||||
@ -29,17 +31,22 @@
|
|||||||
"@mantine/tiptap": "^7.13.0",
|
"@mantine/tiptap": "^7.13.0",
|
||||||
"@tabler/icons-react": "^3.17.0",
|
"@tabler/icons-react": "^3.17.0",
|
||||||
"@tanstack/react-table": "^8.20.5",
|
"@tanstack/react-table": "^8.20.5",
|
||||||
|
"@techstark/opencv-js": "^4.10.0-release.1",
|
||||||
"@tiptap/extension-link": "^2.7.3",
|
"@tiptap/extension-link": "^2.7.3",
|
||||||
"@tiptap/react": "^2.7.3",
|
"@tiptap/react": "^2.7.3",
|
||||||
"@tiptap/starter-kit": "^2.7.3",
|
"@tiptap/starter-kit": "^2.7.3",
|
||||||
"@types/ol-ext": "npm:@siedlerchr/types-ol-ext@^3.5.0",
|
"@types/ol-ext": "npm:@siedlerchr/types-ol-ext@^3.5.0",
|
||||||
"@uidotdev/usehooks": "^2.4.1",
|
"@uidotdev/usehooks": "^2.4.1",
|
||||||
|
"ag-grid-react": "^33.3.2",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
|
"docx-templates": "^4.13.0",
|
||||||
"embla-carousel-react": "^8.3.0",
|
"embla-carousel-react": "^8.3.0",
|
||||||
"file-type": "^19.0.0",
|
"file-type": "^19.0.0",
|
||||||
|
"html2canvas": "^1.4.1",
|
||||||
|
"jspdf": "^2.5.2",
|
||||||
"ol": "^10.0.0",
|
"ol": "^10.0.0",
|
||||||
"ol-ext": "^4.0.23",
|
"ol-ext": "^4.0.23",
|
||||||
"proj4": "^2.12.0",
|
"proj4": "^2.12.0",
|
||||||
@ -65,6 +72,7 @@
|
|||||||
"postcss": "^8.4.47",
|
"postcss": "^8.4.47",
|
||||||
"postcss-preset-mantine": "^1.17.0",
|
"postcss-preset-mantine": "^1.17.0",
|
||||||
"postcss-simple-vars": "^7.0.1",
|
"postcss-simple-vars": "^7.0.1",
|
||||||
|
"rollup-plugin-visualizer": "^5.12.0",
|
||||||
"sass-embedded": "^1.79.5",
|
"sass-embedded": "^1.79.5",
|
||||||
"serve": "^14.2.3",
|
"serve": "^14.2.3",
|
||||||
"tailwindcss": "^3.4.4",
|
"tailwindcss": "^3.4.4",
|
||||||
@ -1863,9 +1871,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@babel/runtime": {
|
"node_modules/@babel/runtime": {
|
||||||
"version": "7.24.7",
|
"version": "7.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz",
|
||||||
"integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==",
|
"integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"regenerator-runtime": "^0.14.0"
|
"regenerator-runtime": "^0.14.0"
|
||||||
},
|
},
|
||||||
@ -1937,6 +1945,42 @@
|
|||||||
"integrity": "sha512-+imAQkHf7U/Rwvu0wk1XWgsP3WnpCWmK7B48f0XqSNzgk64+grljTKC7pnO/xBiEMUziF7vKRfbBnOQhg126qQ==",
|
"integrity": "sha512-+imAQkHf7U/Rwvu0wk1XWgsP3WnpCWmK7B48f0XqSNzgk64+grljTKC7pnO/xBiEMUziF7vKRfbBnOQhg126qQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@dnd-kit/accessibility": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@dnd-kit/core": {
|
||||||
|
"version": "6.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz",
|
||||||
|
"integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@dnd-kit/accessibility": "^3.1.1",
|
||||||
|
"@dnd-kit/utilities": "^3.2.2",
|
||||||
|
"tslib": "^2.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8.0",
|
||||||
|
"react-dom": ">=16.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@dnd-kit/utilities": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz",
|
||||||
|
"integrity": "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@esbuild/aix-ppc64": {
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
"version": "0.21.5",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
||||||
@ -2441,6 +2485,24 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@fontsource/open-sans/-/open-sans-5.0.28.tgz",
|
"resolved": "https://registry.npmjs.org/@fontsource/open-sans/-/open-sans-5.0.28.tgz",
|
||||||
"integrity": "sha512-hBvJHY76pJT/JynGUB5EXWhnzjYfLdcMn655J5p1v9lTT9HdQSy+keq2KPVXO2Htlg998BBa3p6u/jlrZ6w0kg=="
|
"integrity": "sha512-hBvJHY76pJT/JynGUB5EXWhnzjYfLdcMn655J5p1v9lTT9HdQSy+keq2KPVXO2Htlg998BBa3p6u/jlrZ6w0kg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@hello-pangea/dnd": {
|
||||||
|
"version": "17.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@hello-pangea/dnd/-/dnd-17.0.0.tgz",
|
||||||
|
"integrity": "sha512-LDDPOix/5N0j5QZxubiW9T0M0+1PR0rTDWeZF5pu1Tz91UQnuVK4qQ/EjY83Qm2QeX0eM8qDXANfDh3VVqtR4Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.25.6",
|
||||||
|
"css-box-model": "^1.2.1",
|
||||||
|
"memoize-one": "^6.0.0",
|
||||||
|
"raf-schd": "^4.0.3",
|
||||||
|
"react-redux": "^9.1.2",
|
||||||
|
"redux": "^5.0.1",
|
||||||
|
"use-memo-one": "^1.1.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^18.0.0",
|
||||||
|
"react-dom": "^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@humanwhocodes/config-array": {
|
"node_modules/@humanwhocodes/config-array": {
|
||||||
"version": "0.11.14",
|
"version": "0.11.14",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
||||||
@ -3467,6 +3529,11 @@
|
|||||||
"url": "https://github.com/sponsors/tannerlinsley"
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@techstark/opencv-js": {
|
||||||
|
"version": "4.10.0-release.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@techstark/opencv-js/-/opencv-js-4.10.0-release.1.tgz",
|
||||||
|
"integrity": "sha512-S4XELidRiQeA0q1s9VQLo540wCxUo24r1O4C+LqZ6llX+sPCXvZCPv3Ice8dEIr0uavyZ8YZeKXSBdDgMXSXjw=="
|
||||||
|
},
|
||||||
"node_modules/@tiptap/core": {
|
"node_modules/@tiptap/core": {
|
||||||
"version": "2.7.3",
|
"version": "2.7.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.7.3.tgz",
|
||||||
@ -3939,8 +4006,7 @@
|
|||||||
"version": "3.4.3",
|
"version": "3.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz",
|
||||||
"integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
|
"integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
|
||||||
"optional": true,
|
"optional": true
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/react": {
|
"node_modules/@types/react": {
|
||||||
"version": "18.3.3",
|
"version": "18.3.3",
|
||||||
@ -4233,6 +4299,35 @@
|
|||||||
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ag-charts-types": {
|
||||||
|
"version": "11.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ag-charts-types/-/ag-charts-types-11.3.2.tgz",
|
||||||
|
"integrity": "sha512-trPGqgGYiTeLgtf9nLuztDYOPOFOLbqHn1g2D99phf7QowcwdX0TPx0wfWG8Hm90LjB8IH+G2s3AZe2vrdAtMQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/ag-grid-community": {
|
||||||
|
"version": "33.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ag-grid-community/-/ag-grid-community-33.3.2.tgz",
|
||||||
|
"integrity": "sha512-9bx0e/+ykOyLvUxHqmdy0cRVANH6JAtv0yZdnBZEXYYqBAwN+G5a4NY+2I1KvoOCYzbk8SnStG7y4hCdVAAWOQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ag-charts-types": "11.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ag-grid-react": {
|
||||||
|
"version": "33.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ag-grid-react/-/ag-grid-react-33.3.2.tgz",
|
||||||
|
"integrity": "sha512-5bv4JIJvGov23sduIUIyQTqpa/qhoQrRkQm5pFOQb7RMwusfx6xBPrkLwIIlCJiQ8g0OOinxWzZ2kQ2Zml6tLw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ag-grid-community": "33.3.2",
|
||||||
|
"prop-types": "^15.8.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
|
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ajv": {
|
"node_modules/ajv": {
|
||||||
"version": "6.12.6",
|
"version": "6.12.6",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||||
@ -4453,7 +4548,6 @@
|
|||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
|
||||||
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
|
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"atob": "bin/atob.js"
|
"atob": "bin/atob.js"
|
||||||
},
|
},
|
||||||
@ -4580,8 +4674,6 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
||||||
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
||||||
"optional": true,
|
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6.0"
|
"node": ">= 0.6.0"
|
||||||
}
|
}
|
||||||
@ -4859,7 +4951,6 @@
|
|||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
|
||||||
"integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==",
|
"integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"btoa": "bin/btoa.js"
|
"btoa": "bin/btoa.js"
|
||||||
},
|
},
|
||||||
@ -5008,7 +5099,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz",
|
||||||
"integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==",
|
"integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.12.5",
|
"@babel/runtime": "^7.12.5",
|
||||||
"@types/raf": "^3.4.0",
|
"@types/raf": "^3.4.0",
|
||||||
@ -5027,8 +5117,7 @@
|
|||||||
"version": "0.13.11",
|
"version": "0.13.11",
|
||||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
|
||||||
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
|
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
|
||||||
"optional": true,
|
"optional": true
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/chalk": {
|
"node_modules/chalk": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
@ -5141,6 +5230,57 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cliui": {
|
||||||
|
"version": "8.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||||
|
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"string-width": "^4.2.0",
|
||||||
|
"strip-ansi": "^6.0.1",
|
||||||
|
"wrap-ansi": "^7.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cliui/node_modules/emoji-regex": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/cliui/node_modules/string-width": {
|
||||||
|
"version": "4.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||||
|
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"emoji-regex": "^8.0.0",
|
||||||
|
"is-fullwidth-code-point": "^3.0.0",
|
||||||
|
"strip-ansi": "^6.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cliui/node_modules/wrap-ansi": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": "^4.0.0",
|
||||||
|
"string-width": "^4.1.0",
|
||||||
|
"strip-ansi": "^6.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/clsx": {
|
"node_modules/clsx": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||||
@ -5316,7 +5456,6 @@
|
|||||||
"integrity": "sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw==",
|
"integrity": "sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
"url": "https://opencollective.com/core-js"
|
"url": "https://opencollective.com/core-js"
|
||||||
@ -5338,8 +5477,7 @@
|
|||||||
"node_modules/core-util-is": {
|
"node_modules/core-util-is": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/create-ecdh": {
|
"node_modules/create-ecdh": {
|
||||||
"version": "4.0.4",
|
"version": "4.0.4",
|
||||||
@ -5440,12 +5578,18 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/css-box-model": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==",
|
||||||
|
"dependencies": {
|
||||||
|
"tiny-invariant": "^1.0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/css-line-break": {
|
"node_modules/css-line-break": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
|
||||||
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
|
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
|
||||||
"optional": true,
|
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"utrie": "^1.0.2"
|
"utrie": "^1.0.2"
|
||||||
}
|
}
|
||||||
@ -5696,6 +5840,15 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/define-lazy-prop": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/define-properties": {
|
"node_modules/define-properties": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
|
||||||
@ -5789,6 +5942,18 @@
|
|||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/docx-templates": {
|
||||||
|
"version": "4.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/docx-templates/-/docx-templates-4.13.0.tgz",
|
||||||
|
"integrity": "sha512-tTmR3WhROYctuyVReQ+PfCU3zprmC45/VuSVzn8EjovzpRkXYUdXiDatB9M8pasj0V+wuuOyY8bcSHvlQ2GNag==",
|
||||||
|
"dependencies": {
|
||||||
|
"jszip": "^3.10.1",
|
||||||
|
"sax": "1.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dom-helpers": {
|
"node_modules/dom-helpers": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
|
||||||
@ -5814,8 +5979,7 @@
|
|||||||
"version": "2.5.6",
|
"version": "2.5.6",
|
||||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.6.tgz",
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.6.tgz",
|
||||||
"integrity": "sha512-zUTaUBO8pY4+iJMPE1B9XlO2tXVYIcEA4SNGtvDELzTSCQO7RzH+j7S180BmhmJId78lqGU2z19vgVx2Sxs/PQ==",
|
"integrity": "sha512-zUTaUBO8pY4+iJMPE1B9XlO2tXVYIcEA4SNGtvDELzTSCQO7RzH+j7S180BmhmJId78lqGU2z19vgVx2Sxs/PQ==",
|
||||||
"optional": true,
|
"optional": true
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/earcut": {
|
"node_modules/earcut": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
@ -6414,10 +6578,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fflate": {
|
"node_modules/fflate": {
|
||||||
"version": "0.4.8",
|
"version": "0.8.2",
|
||||||
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz",
|
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
|
||||||
"integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==",
|
"integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/file-entry-cache": {
|
"node_modules/file-entry-cache": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
@ -6688,6 +6851,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
|
||||||
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug=="
|
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug=="
|
||||||
},
|
},
|
||||||
|
"node_modules/get-caller-file": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "6.* || 8.* || >= 10.*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/get-intrinsic": {
|
"node_modules/get-intrinsic": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
|
||||||
@ -7007,8 +7179,7 @@
|
|||||||
"version": "1.4.1",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
|
||||||
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
|
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
|
||||||
"optional": true,
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"css-line-break": "^2.1.0",
|
"css-line-break": "^2.1.0",
|
||||||
"text-segmentation": "^1.0.3"
|
"text-segmentation": "^1.0.3"
|
||||||
@ -7066,6 +7237,11 @@
|
|||||||
"node": ">= 4"
|
"node": ">= 4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/immediate": {
|
||||||
|
"version": "3.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
||||||
|
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
|
||||||
|
},
|
||||||
"node_modules/immutable": {
|
"node_modules/immutable": {
|
||||||
"version": "4.3.7",
|
"version": "4.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz",
|
||||||
@ -7734,23 +7910,66 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jspdf": {
|
"node_modules/jspdf": {
|
||||||
"version": "2.5.1",
|
"version": "2.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.2.tgz",
|
||||||
"integrity": "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==",
|
"integrity": "sha512-myeX9c+p7znDWPk0eTrujCzNjT+CXdXyk7YmJq5nD5V7uLLKmSXnlQ/Jn/kuo3X09Op70Apm0rQSnFWyGK8uEQ==",
|
||||||
"peer": true,
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.14.0",
|
"@babel/runtime": "^7.23.2",
|
||||||
"atob": "^2.1.2",
|
"atob": "^2.1.2",
|
||||||
"btoa": "^1.2.1",
|
"btoa": "^1.2.1",
|
||||||
"fflate": "^0.4.8"
|
"fflate": "^0.8.1"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"canvg": "^3.0.6",
|
"canvg": "^3.0.6",
|
||||||
"core-js": "^3.6.0",
|
"core-js": "^3.6.0",
|
||||||
"dompurify": "^2.2.0",
|
"dompurify": "^2.5.4",
|
||||||
"html2canvas": "^1.0.0-rc.5"
|
"html2canvas": "^1.0.0-rc.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jszip": {
|
||||||
|
"version": "3.10.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
|
||||||
|
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
|
||||||
|
"dependencies": {
|
||||||
|
"lie": "~3.3.0",
|
||||||
|
"pako": "~1.0.2",
|
||||||
|
"readable-stream": "~2.3.6",
|
||||||
|
"setimmediate": "^1.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jszip/node_modules/isarray": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
|
||||||
|
},
|
||||||
|
"node_modules/jszip/node_modules/readable-stream": {
|
||||||
|
"version": "2.3.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||||
|
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||||
|
"dependencies": {
|
||||||
|
"core-util-is": "~1.0.0",
|
||||||
|
"inherits": "~2.0.3",
|
||||||
|
"isarray": "~1.0.0",
|
||||||
|
"process-nextick-args": "~2.0.0",
|
||||||
|
"safe-buffer": "~5.1.1",
|
||||||
|
"string_decoder": "~1.1.1",
|
||||||
|
"util-deprecate": "~1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jszip/node_modules/safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||||
|
},
|
||||||
|
"node_modules/jszip/node_modules/string_decoder": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "~5.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/keyv": {
|
"node_modules/keyv": {
|
||||||
"version": "4.5.4",
|
"version": "4.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||||
@ -7795,6 +8014,14 @@
|
|||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lie": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
|
||||||
|
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"immediate": "~3.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lilconfig": {
|
"node_modules/lilconfig": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
|
||||||
@ -7922,6 +8149,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
|
||||||
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="
|
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="
|
||||||
},
|
},
|
||||||
|
"node_modules/memoize-one": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
|
||||||
|
},
|
||||||
"node_modules/merge-stream": {
|
"node_modules/merge-stream": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||||
@ -8325,6 +8557,23 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/open": {
|
||||||
|
"version": "8.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
|
||||||
|
"integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"define-lazy-prop": "^2.0.0",
|
||||||
|
"is-docker": "^2.1.1",
|
||||||
|
"is-wsl": "^2.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/optionator": {
|
"node_modules/optionator": {
|
||||||
"version": "0.9.4",
|
"version": "0.9.4",
|
||||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
||||||
@ -8386,8 +8635,7 @@
|
|||||||
"node_modules/pako": {
|
"node_modules/pako": {
|
||||||
"version": "1.0.11",
|
"version": "1.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||||
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
|
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/parent-module": {
|
"node_modules/parent-module": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
@ -8542,8 +8790,7 @@
|
|||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||||
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
|
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
|
||||||
"optional": true,
|
"optional": true
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
@ -8832,8 +9079,7 @@
|
|||||||
"node_modules/process-nextick-args": {
|
"node_modules/process-nextick-args": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
|
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/proj4": {
|
"node_modules/proj4": {
|
||||||
"version": "2.12.0",
|
"version": "2.12.0",
|
||||||
@ -9147,11 +9393,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
|
||||||
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
|
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"performance-now": "^2.1.0"
|
"performance-now": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/raf-schd": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ=="
|
||||||
|
},
|
||||||
"node_modules/randombytes": {
|
"node_modules/randombytes": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||||
@ -9273,6 +9523,36 @@
|
|||||||
"react-dom": "^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
|
"react-dom": "^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-redux": {
|
||||||
|
"version": "9.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
|
||||||
|
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/use-sync-external-store": "^0.0.6",
|
||||||
|
"use-sync-external-store": "^1.4.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "^18.2.25 || ^19",
|
||||||
|
"react": "^18.0 || ^19",
|
||||||
|
"redux": "^5.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"redux": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-redux/node_modules/use-sync-external-store": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-remove-scroll": {
|
"node_modules/react-remove-scroll": {
|
||||||
"version": "2.6.0",
|
"version": "2.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.0.tgz",
|
||||||
@ -9499,6 +9779,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/redux": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="
|
||||||
|
},
|
||||||
"node_modules/regenerate": {
|
"node_modules/regenerate": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
|
||||||
@ -9609,6 +9894,15 @@
|
|||||||
"jsesc": "bin/jsesc"
|
"jsesc": "bin/jsesc"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/require-directory": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/require-from-string": {
|
"node_modules/require-from-string": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||||
@ -9667,7 +9961,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
|
||||||
"integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
|
"integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.8.15"
|
"node": ">= 0.8.15"
|
||||||
}
|
}
|
||||||
@ -9733,6 +10026,32 @@
|
|||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/rollup-plugin-visualizer": {
|
||||||
|
"version": "5.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.12.0.tgz",
|
||||||
|
"integrity": "sha512-8/NU9jXcHRs7Nnj07PF2o4gjxmm9lXIrZ8r175bT9dK8qoLlvKTwRMArRCMgpMGlq8CTLugRvEmyMeMXIU2pNQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"open": "^8.4.0",
|
||||||
|
"picomatch": "^2.3.1",
|
||||||
|
"source-map": "^0.7.4",
|
||||||
|
"yargs": "^17.5.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"rollup-plugin-visualizer": "dist/bin/cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"rollup": "2.x || 3.x || 4.x"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"rollup": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/rope-sequence": {
|
"node_modules/rope-sequence": {
|
||||||
"version": "1.3.4",
|
"version": "1.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz",
|
||||||
@ -10202,6 +10521,11 @@
|
|||||||
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sax": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA=="
|
||||||
|
},
|
||||||
"node_modules/scheduler": {
|
"node_modules/scheduler": {
|
||||||
"version": "0.23.2",
|
"version": "0.23.2",
|
||||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
||||||
@ -10384,8 +10708,7 @@
|
|||||||
"node_modules/setimmediate": {
|
"node_modules/setimmediate": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||||
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
|
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/sha.js": {
|
"node_modules/sha.js": {
|
||||||
"version": "2.4.11",
|
"version": "2.4.11",
|
||||||
@ -10466,6 +10789,15 @@
|
|||||||
"integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==",
|
"integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/source-map": {
|
||||||
|
"version": "0.7.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
|
||||||
|
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/source-map-js": {
|
"node_modules/source-map-js": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||||
@ -10505,7 +10837,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
|
||||||
"integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
|
"integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.1.14"
|
"node": ">=0.1.14"
|
||||||
}
|
}
|
||||||
@ -10854,7 +11185,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
|
||||||
"integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
|
"integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.0.0"
|
"node": ">=12.0.0"
|
||||||
}
|
}
|
||||||
@ -10980,8 +11310,6 @@
|
|||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
||||||
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
|
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
|
||||||
"optional": true,
|
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"utrie": "^1.0.2"
|
"utrie": "^1.0.2"
|
||||||
}
|
}
|
||||||
@ -11443,6 +11771,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/use-memo-one": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/use-sidecar": {
|
"node_modules/use-sidecar": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz",
|
||||||
@ -11494,8 +11830,6 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
|
||||||
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
|
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
|
||||||
"optional": true,
|
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"base64-arraybuffer": "^1.0.2"
|
"base64-arraybuffer": "^1.0.2"
|
||||||
}
|
}
|
||||||
@ -12213,6 +12547,15 @@
|
|||||||
"node": ">=0.4"
|
"node": ">=0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/y18n": {
|
||||||
|
"version": "5.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||||
|
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/yallist": {
|
"node_modules/yallist": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||||
@ -12231,6 +12574,53 @@
|
|||||||
"node": ">= 14"
|
"node": ">= 14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/yargs": {
|
||||||
|
"version": "17.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||||
|
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"cliui": "^8.0.1",
|
||||||
|
"escalade": "^3.1.1",
|
||||||
|
"get-caller-file": "^2.0.5",
|
||||||
|
"require-directory": "^2.1.1",
|
||||||
|
"string-width": "^4.2.3",
|
||||||
|
"y18n": "^5.0.5",
|
||||||
|
"yargs-parser": "^21.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/yargs-parser": {
|
||||||
|
"version": "21.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||||
|
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/yargs/node_modules/emoji-regex": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/yargs/node_modules/string-width": {
|
||||||
|
"version": "4.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||||
|
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"emoji-regex": "^8.0.0",
|
||||||
|
"is-fullwidth-code-point": "^3.0.0",
|
||||||
|
"strip-ansi": "^6.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/yocto-queue": {
|
"node_modules/yocto-queue": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||||
|
|||||||
@ -12,8 +12,10 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"-": "^0.0.1",
|
"-": "^0.0.1",
|
||||||
|
"@dnd-kit/core": "^6.3.1",
|
||||||
"@fontsource/inter": "^5.0.19",
|
"@fontsource/inter": "^5.0.19",
|
||||||
"@fontsource/open-sans": "^5.0.28",
|
"@fontsource/open-sans": "^5.0.28",
|
||||||
|
"@hello-pangea/dnd": "^17.0.0",
|
||||||
"@js-preview/docx": "^1.6.2",
|
"@js-preview/docx": "^1.6.2",
|
||||||
"@js-preview/excel": "^1.7.8",
|
"@js-preview/excel": "^1.7.8",
|
||||||
"@js-preview/pdf": "^2.0.2",
|
"@js-preview/pdf": "^2.0.2",
|
||||||
@ -32,17 +34,22 @@
|
|||||||
"@mantine/tiptap": "^7.13.0",
|
"@mantine/tiptap": "^7.13.0",
|
||||||
"@tabler/icons-react": "^3.17.0",
|
"@tabler/icons-react": "^3.17.0",
|
||||||
"@tanstack/react-table": "^8.20.5",
|
"@tanstack/react-table": "^8.20.5",
|
||||||
|
"@techstark/opencv-js": "^4.10.0-release.1",
|
||||||
"@tiptap/extension-link": "^2.7.3",
|
"@tiptap/extension-link": "^2.7.3",
|
||||||
"@tiptap/react": "^2.7.3",
|
"@tiptap/react": "^2.7.3",
|
||||||
"@tiptap/starter-kit": "^2.7.3",
|
"@tiptap/starter-kit": "^2.7.3",
|
||||||
"@types/ol-ext": "npm:@siedlerchr/types-ol-ext@^3.5.0",
|
"@types/ol-ext": "npm:@siedlerchr/types-ol-ext@^3.5.0",
|
||||||
"@uidotdev/usehooks": "^2.4.1",
|
"@uidotdev/usehooks": "^2.4.1",
|
||||||
|
"ag-grid-react": "^33.3.2",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
|
"docx-templates": "^4.13.0",
|
||||||
"embla-carousel-react": "^8.3.0",
|
"embla-carousel-react": "^8.3.0",
|
||||||
"file-type": "^19.0.0",
|
"file-type": "^19.0.0",
|
||||||
|
"html2canvas": "^1.4.1",
|
||||||
|
"jspdf": "^2.5.2",
|
||||||
"ol": "^10.0.0",
|
"ol": "^10.0.0",
|
||||||
"ol-ext": "^4.0.23",
|
"ol-ext": "^4.0.23",
|
||||||
"proj4": "^2.12.0",
|
"proj4": "^2.12.0",
|
||||||
@ -68,6 +75,7 @@
|
|||||||
"postcss": "^8.4.47",
|
"postcss": "^8.4.47",
|
||||||
"postcss-preset-mantine": "^1.17.0",
|
"postcss-preset-mantine": "^1.17.0",
|
||||||
"postcss-simple-vars": "^7.0.1",
|
"postcss-simple-vars": "^7.0.1",
|
||||||
|
"rollup-plugin-visualizer": "^5.12.0",
|
||||||
"sass-embedded": "^1.79.5",
|
"sass-embedded": "^1.79.5",
|
||||||
"serve": "^14.2.3",
|
"serve": "^14.2.3",
|
||||||
"tailwindcss": "^3.4.4",
|
"tailwindcss": "^3.4.4",
|
||||||
|
|||||||
BIN
client/public/template.docx
Normal file
BIN
client/public/template.docx
Normal file
Binary file not shown.
BIN
client/public/template_1.docx
Normal file
BIN
client/public/template_1.docx
Normal file
Binary file not shown.
BIN
client/public/template_table.docx
Normal file
BIN
client/public/template_table.docx
Normal file
Binary file not shown.
BIN
client/public/template_table_1.docx
Normal file
BIN
client/public/template_table_1.docx
Normal file
Binary file not shown.
BIN
client/public/test.png
Normal file
BIN
client/public/test.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 MiB |
@ -5,47 +5,48 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 5px;
|
width: 5px;
|
||||||
background: #27bbff;
|
background: var(--mantine-color-anchor);
|
||||||
cursor: col-resize;
|
cursor: col-resize;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
touch-action: none;
|
touch-action: none;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
|
transition: opacity .2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.resize_handler:hover {
|
.resize_handler:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tr {
|
// .tr {
|
||||||
display: flex;
|
// display: flex;
|
||||||
//width: 100%;
|
// //width: 100%;
|
||||||
//max-width: 100%;
|
// //max-width: 100%;
|
||||||
width: fit-content;
|
// width: fit-content;
|
||||||
}
|
// }
|
||||||
|
|
||||||
.th {
|
.th {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.th,
|
// .th,
|
||||||
.td {
|
// .td {
|
||||||
display: flex;
|
// display: flex;
|
||||||
width: auto;
|
// width: auto;
|
||||||
}
|
// }
|
||||||
|
|
||||||
.thead {
|
// .thead {
|
||||||
display: flex;
|
// display: flex;
|
||||||
width: 100%;
|
// width: 100%;
|
||||||
}
|
// }
|
||||||
|
|
||||||
.table {
|
// .table {
|
||||||
display: flex;
|
// display: flex;
|
||||||
flex-direction: column;
|
// flex-direction: column;
|
||||||
width: 100%;
|
// width: 100%;
|
||||||
}
|
// }
|
||||||
|
|
||||||
.tbody {
|
// .tbody {
|
||||||
display: flex;
|
// display: flex;
|
||||||
flex-direction: column;
|
// flex-direction: column;
|
||||||
width: 100%;
|
// width: 100%;
|
||||||
}
|
// }
|
||||||
@ -1,111 +1,205 @@
|
|||||||
import { Input, Table } from '@mantine/core';
|
import { Badge, Button, Flex, Input, Modal, ScrollAreaAutosize, Select, Stack, Table, TextInput } from '@mantine/core';
|
||||||
import { ColumnDef, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table';
|
import { Cell, ColumnDef, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table';
|
||||||
import { useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import styles from './CustomTable.module.scss'
|
import styles from './CustomTable.module.scss'
|
||||||
|
import { useRoles } from '../hooks/swrHooks';
|
||||||
|
import { IRole } from '../interfaces/role';
|
||||||
|
import { IconPlus } from '@tabler/icons-react';
|
||||||
|
import { CreateField } from '../interfaces/create';
|
||||||
|
import { AxiosResponse } from 'axios';
|
||||||
|
import FormFields from './FormFields';
|
||||||
|
import { useDisclosure } from '@mantine/hooks';
|
||||||
|
|
||||||
// Sample data
|
type CustomTableProps<T> = {
|
||||||
|
data: T[];
|
||||||
type DataType = {
|
columns: ColumnDef<T>[];
|
||||||
id: number,
|
createFields?: CreateField[];
|
||||||
name: string,
|
submitHandler?: (data: T) => Promise<AxiosResponse>
|
||||||
age: number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define columns
|
const CustomTable = <T extends object>({
|
||||||
const columns: ColumnDef<DataType>[] = [
|
data: initialData,
|
||||||
{
|
columns,
|
||||||
accessorKey: 'name',
|
createFields,
|
||||||
header: 'Name',
|
submitHandler
|
||||||
cell: (info) => info.getValue(),
|
}: CustomTableProps<T>) => {
|
||||||
maxSize: Number.MAX_SAFE_INTEGER,
|
const [data, setData] = useState<T[]>(initialData);
|
||||||
},
|
const [searchText, setSearchText] = useState('');
|
||||||
{
|
|
||||||
accessorKey: 'age',
|
|
||||||
header: 'Age',
|
|
||||||
cell: (info) => info.getValue(),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const CustomTable = () => {
|
|
||||||
const [data, setData] = useState<DataType[]>([
|
|
||||||
{ id: 1, name: 'John Doe', age: 25 },
|
|
||||||
{ id: 2, name: 'Jane Smith', age: 30 },
|
|
||||||
{ id: 3, name: 'Sam Green', age: 22 },
|
|
||||||
]);
|
|
||||||
const [editingCell, setEditingCell] = useState<{ rowIndex: string | number | null, columnId: string | number | null }>({ rowIndex: null, columnId: null });
|
const [editingCell, setEditingCell] = useState<{ rowIndex: string | number | null, columnId: string | number | null }>({ rowIndex: null, columnId: null });
|
||||||
|
|
||||||
const tableColumns = useMemo<ColumnDef<typeof data[0]>[]>(() => columns, []);
|
const tableColumns = useMemo(() => columns, [columns]);
|
||||||
|
|
||||||
|
// Function to handle cell edit
|
||||||
|
const handleEditCell = (
|
||||||
|
rowIndex: number,
|
||||||
|
columnId: keyof T,
|
||||||
|
value: T[keyof T]
|
||||||
|
) => {
|
||||||
|
const updatedData = [...data];
|
||||||
|
updatedData[rowIndex][columnId] = value;
|
||||||
|
setData(updatedData);
|
||||||
|
//setEditingCell({ rowIndex: null, columnId: null });
|
||||||
|
};
|
||||||
|
|
||||||
|
const filteredData = useMemo(() => {
|
||||||
|
if (!searchText) return data;
|
||||||
|
|
||||||
|
return data.filter((row) =>
|
||||||
|
Object.values(row).some((value) =>
|
||||||
|
value?.toString().toLowerCase().includes(searchText.toLowerCase())
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}, [data, searchText])
|
||||||
|
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data,
|
data: filteredData,
|
||||||
columns: tableColumns,
|
columns: tableColumns,
|
||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
columnResizeMode: "onChange",
|
columnResizeMode: "onChange",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Function to handle cell edit
|
const [opened, { open, close }] = useDisclosure(false);
|
||||||
const handleEditCell = (
|
|
||||||
rowIndex: number,
|
|
||||||
columnId: keyof DataType,
|
|
||||||
value: DataType[keyof DataType]
|
|
||||||
) => {
|
|
||||||
const updatedData = [...data];
|
|
||||||
(updatedData[rowIndex][columnId] as DataType[keyof DataType]) = value;
|
|
||||||
setData(updatedData);
|
|
||||||
//setEditingCell({ rowIndex: null, columnId: null });
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Table striped withColumnBorders highlightOnHover className={styles.table}>
|
<Stack h='100%'>
|
||||||
<Table.Thead className={styles.thead}>
|
{createFields && submitHandler &&
|
||||||
{table.getHeaderGroups().map(headerGroup => (
|
<Modal opened={opened} onClose={close} title="Добавление объекта" centered>
|
||||||
<Table.Tr key={headerGroup.id} className={styles.tr}>
|
<FormFields
|
||||||
{headerGroup.headers.map((header) => (
|
fields={createFields}
|
||||||
<Table.Th key={header.id} className={styles.th} w={header.getSize()}>
|
submitHandler={submitHandler}
|
||||||
{flexRender(header.column.columnDef.header, header.getContext())}
|
/>
|
||||||
<div
|
</Modal>
|
||||||
className={styles.resize_handler}
|
}
|
||||||
onMouseDown={header.getResizeHandler()} //for desktop
|
|
||||||
onTouchStart={header.getResizeHandler()}
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</Table.Th>
|
|
||||||
))}
|
|
||||||
</Table.Tr>
|
|
||||||
))}
|
|
||||||
</Table.Thead>
|
|
||||||
<Table.Tbody className={styles.tbody}>
|
|
||||||
{table.getRowModel().rows.map((row, rowIndex) => (
|
|
||||||
<Table.Tr key={row.id} className={styles.tr}>
|
|
||||||
{row.getVisibleCells().map(cell => {
|
|
||||||
const isEditing = editingCell.rowIndex === rowIndex && editingCell.columnId === cell.column.id;
|
|
||||||
|
|
||||||
return (
|
<Flex w='100%' gap='sm'>
|
||||||
<Table.Td
|
<TextInput
|
||||||
key={cell.id}
|
placeholder="Поиск"
|
||||||
onDoubleClick={() => setEditingCell({ rowIndex, columnId: cell.column.id })}
|
value={searchText}
|
||||||
style={{ width: cell.column.getSize() }}
|
onChange={(e) => setSearchText(e.target.value)}
|
||||||
className={styles.td}
|
w='100%'
|
||||||
>
|
/>
|
||||||
{isEditing ? (
|
{createFields && submitHandler &&
|
||||||
<Input
|
<Button
|
||||||
type='text'
|
leftSection={<IconPlus />}
|
||||||
value={data[rowIndex][cell.column.id as keyof DataType]}
|
onClick={open}
|
||||||
onChange={(e) => handleEditCell(rowIndex, (cell.column.id as keyof DataType), e.target.value)}
|
style={{ flexShrink: 0 }}
|
||||||
onBlur={() => setEditingCell({ rowIndex: null, columnId: null })}
|
>
|
||||||
autoFocus
|
Добавить
|
||||||
/>
|
</Button>
|
||||||
) : (
|
}
|
||||||
flexRender(cell.column.columnDef.cell, cell.getContext())
|
</Flex>
|
||||||
)}
|
|
||||||
</Table.Td>
|
<ScrollAreaAutosize offsetScrollbars style={{ borderRadius: '4px' }}>
|
||||||
);
|
<Table stickyHeader striped withColumnBorders highlightOnHover className={styles.table}>
|
||||||
})}
|
<Table.Thead className={styles.thead}>
|
||||||
</Table.Tr>
|
{table.getHeaderGroups().map(headerGroup => (
|
||||||
))}
|
<Table.Tr key={headerGroup.id} className={styles.tr}>
|
||||||
</Table.Tbody>
|
{headerGroup.headers.map((header) => (
|
||||||
</Table>
|
<Table.Th key={header.id} className={styles.th} w={header.getSize()}>
|
||||||
|
{flexRender(header.column.columnDef.header, header.getContext())}
|
||||||
|
<div
|
||||||
|
className={styles.resize_handler}
|
||||||
|
onMouseDown={header.getResizeHandler()} //for desktop
|
||||||
|
onTouchStart={header.getResizeHandler()}
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</Table.Th>
|
||||||
|
))}
|
||||||
|
</Table.Tr>
|
||||||
|
))}
|
||||||
|
</Table.Thead>
|
||||||
|
<Table.Tbody className={styles.tbody}>
|
||||||
|
{table.getRowModel().rows.map((row, rowIndex) => (
|
||||||
|
<Table.Tr key={row.id} className={styles.tr}>
|
||||||
|
{row.getVisibleCells().map(cell => {
|
||||||
|
const isEditing = editingCell.rowIndex === rowIndex && editingCell.columnId === cell.column.id;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Table.Td
|
||||||
|
key={cell.id}
|
||||||
|
onDoubleClick={() => setEditingCell({ rowIndex, columnId: cell.column.id })}
|
||||||
|
style={{ width: cell.column.getSize() }}
|
||||||
|
className={styles.td}
|
||||||
|
>
|
||||||
|
{isEditing ? (
|
||||||
|
<Input
|
||||||
|
type='text'
|
||||||
|
value={(data[rowIndex][cell.column.id as keyof T] as string)}
|
||||||
|
onChange={(e) => handleEditCell(rowIndex, (cell.column.id as keyof T), e.target.value as T[keyof T])}
|
||||||
|
onBlur={() => setEditingCell({ rowIndex: null, columnId: null })}
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<CellDisplay cell={cell} />
|
||||||
|
)}
|
||||||
|
</Table.Td>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Table.Tr>
|
||||||
|
))}
|
||||||
|
</Table.Tbody>
|
||||||
|
</Table>
|
||||||
|
</ScrollAreaAutosize>
|
||||||
|
</Stack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type CellDisplayProps<T> = {
|
||||||
|
cell: Cell<T, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CellDisplay = <T extends object>({
|
||||||
|
cell
|
||||||
|
}: CellDisplayProps<T>) => {
|
||||||
|
const { roles } = useRoles()
|
||||||
|
|
||||||
|
const [roleOptions, setRoleOptions] = useState<{ label: string, value: string }[]>()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (Array.isArray(roles)) {
|
||||||
|
setRoleOptions(roles.map((role: IRole) => ({ label: role.name, value: role.id.toString() })))
|
||||||
|
}
|
||||||
|
}, [roles])
|
||||||
|
|
||||||
|
switch (cell.column.id) {
|
||||||
|
case 'activity':
|
||||||
|
return (
|
||||||
|
cell.getValue() ? (
|
||||||
|
<Badge fullWidth variant="light">
|
||||||
|
Активен
|
||||||
|
</Badge>
|
||||||
|
) : (
|
||||||
|
<Badge color="gray" fullWidth variant="light">
|
||||||
|
Отключен
|
||||||
|
</Badge>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
case 'is_active':
|
||||||
|
return (
|
||||||
|
cell.getValue() ? (
|
||||||
|
<Badge fullWidth variant="light">
|
||||||
|
Активен
|
||||||
|
</Badge>
|
||||||
|
) : (
|
||||||
|
<Badge color="gray" fullWidth variant="light">
|
||||||
|
Отключен
|
||||||
|
</Badge>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
case 'role_id':
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
data={roleOptions}
|
||||||
|
value={Number(cell.getValue()).toString()}
|
||||||
|
variant="unstyled"
|
||||||
|
allowDeselect={false}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
return (
|
||||||
|
flexRender(cell.column.columnDef.cell, cell.getContext())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default CustomTable;
|
export default CustomTable;
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { useStorages } from '../hooks/swrHooks'
|
|||||||
import { Loader, Table } from '@mantine/core'
|
import { Loader, Table } from '@mantine/core'
|
||||||
|
|
||||||
export default function ServerStorage() {
|
export default function ServerStorage() {
|
||||||
const [selectedOption, setSelectedOption] = useState<IRegion | null>(null)
|
const [selectedOption] = useState<IRegion | null>(null)
|
||||||
|
|
||||||
const { storages, isLoading: serversLoading } = useStorages(selectedOption?.id, 0, 10)
|
const { storages, isLoading: serversLoading } = useStorages(selectedOption?.id, 0, 10)
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +1,18 @@
|
|||||||
import { useState } from 'react'
|
import { useMemo, useState } from 'react'
|
||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
import { fetcher } from '../../http/axiosInstance'
|
import { fetcher } from '../../http/axiosInstance'
|
||||||
import { BASE_URL } from '../../constants'
|
import { BASE_URL } from '../../constants'
|
||||||
import { Accordion, NavLink, Text } from '@mantine/core';
|
import { NavLink, Stack, Text } from '@mantine/core';
|
||||||
import { setCurrentObjectId, useObjectsStore } from '../../store/objects';
|
|
||||||
import { IconChevronDown } from '@tabler/icons-react';
|
import { IconChevronDown } from '@tabler/icons-react';
|
||||||
import { setSelectedObjectType } from '../../store/map';
|
import { setSelectedObjectType } from '../../store/map';
|
||||||
|
import { setCurrentObjectId, useObjectsStore } from '../../store/objects';
|
||||||
|
|
||||||
const ObjectTree = () => {
|
const ObjectTree = ({
|
||||||
const { selectedDistrict, selectedYear } = useObjectsStore()
|
map_id
|
||||||
|
}: {
|
||||||
|
map_id: string,
|
||||||
|
}) => {
|
||||||
|
const { selectedYear, selectedDistrict } = useObjectsStore().id[map_id]
|
||||||
const [existingCount, setExistingCount] = useState(0)
|
const [existingCount, setExistingCount] = useState(0)
|
||||||
const [planningCount, setPlanningCount] = useState(0)
|
const [planningCount, setPlanningCount] = useState(0)
|
||||||
|
|
||||||
@ -49,10 +52,10 @@ const ObjectTree = () => {
|
|||||||
|
|
||||||
if (selectedDistrict) {
|
if (selectedDistrict) {
|
||||||
return (
|
return (
|
||||||
<Accordion multiple chevronPosition='left'>
|
<Stack gap={0}>
|
||||||
<TypeTree label='Существующие' value={'existing'} count={existingCount} objectList={existingObjectsList} planning={0} />
|
<TypeTree map_id={map_id} label='Существующие' value={'existing'} count={existingCount} objectList={existingObjectsList} planning={0} />
|
||||||
<TypeTree label='Планируемые' value={'planning'} count={planningCount} objectList={planningObjectsList} planning={1} />
|
<TypeTree map_id={map_id} label='Планируемые' value={'planning'} count={planningCount} objectList={planningObjectsList} planning={1} />
|
||||||
</Accordion>
|
</Stack>
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
@ -69,19 +72,21 @@ interface TypeTreeProps {
|
|||||||
count: number;
|
count: number;
|
||||||
objectList: unknown;
|
objectList: unknown;
|
||||||
planning: number;
|
planning: number;
|
||||||
|
map_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TypeTree = ({
|
const TypeTree = ({
|
||||||
label,
|
label,
|
||||||
objectList,
|
objectList,
|
||||||
count,
|
count,
|
||||||
planning
|
planning,
|
||||||
|
map_id
|
||||||
}: TypeTreeProps) => {
|
}: TypeTreeProps) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavLink p={0} label={`${label} ${count ? `(${count})` : ''}`}>
|
<NavLink px='xs' py={0} label={`${label} ${count ? `(${count})` : ''}`}>
|
||||||
{Array.isArray(objectList) && objectList.map(list => (
|
{Array.isArray(objectList) && objectList.map(list => (
|
||||||
<ObjectList key={list.id} label={list.name} id={list.id} planning={planning} count={list.count} />
|
<ObjectList map_id={map_id} key={list.id} label={list.name} id={list.id} planning={planning} count={list.count} />
|
||||||
))}
|
))}
|
||||||
</NavLink>
|
</NavLink>
|
||||||
)
|
)
|
||||||
@ -92,34 +97,46 @@ interface IObjectList {
|
|||||||
id: number;
|
id: number;
|
||||||
planning: number;
|
planning: number;
|
||||||
count: number;
|
count: number;
|
||||||
|
map_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ObjectList = ({
|
const ObjectList = ({
|
||||||
label,
|
label,
|
||||||
id,
|
id,
|
||||||
planning,
|
planning,
|
||||||
count
|
count,
|
||||||
|
map_id
|
||||||
}: IObjectList) => {
|
}: IObjectList) => {
|
||||||
const { selectedDistrict, selectedYear } = useObjectsStore()
|
const { selectedDistrict, selectedYear } = useObjectsStore().id[map_id]
|
||||||
|
|
||||||
const { data } = useSWR(
|
const { data } = useSWR(
|
||||||
selectedDistrict && selectedYear ? `/general/objects/list?type=${id}&city_id=${selectedDistrict}&year=${selectedYear}&planning=${planning}` : null,
|
selectedDistrict && selectedYear ? `/general/objects/list?type=${id}&city_id=${selectedDistrict}&year=${selectedYear}&planning=${planning}` : null,
|
||||||
(url) => fetcher(url, BASE_URL.ems),
|
(url) => fetcher(url, BASE_URL.ems),
|
||||||
{
|
{
|
||||||
revalidateOnFocus: false,
|
revalidateOnFocus: false,
|
||||||
revalidateIfStale: false
|
revalidateIfStale: false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const navLinks = useMemo(() => (
|
||||||
|
Array.isArray(data) ? data.map((type) => (
|
||||||
|
<NavLink key={type.object_id} label={type.caption ? type.caption : 'Без названия'} px='xs' py={0} onClick={() => setCurrentObjectId(map_id, type.object_id)} />
|
||||||
|
)) : null
|
||||||
|
), [data, map_id]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavLink onClick={() => {
|
<NavLink onClick={() => setSelectedObjectType(map_id, id)} rightSection={<IconChevronDown size={14} />} px='xs' py={0} label={`${label} ${count ? `(${count})` : ''}`}>
|
||||||
setSelectedObjectType(id)
|
{navLinks}
|
||||||
}} rightSection={<IconChevronDown size={14} />} p={0} label={`${label} ${count ? `(${count})` : ''}`}>
|
|
||||||
{Array.isArray(data) && data.map((type) => (
|
|
||||||
<NavLink key={type.object_id} label={type.caption ? type.caption : 'Без названия'} p={0} onClick={() => setCurrentObjectId(type.object_id)} />
|
|
||||||
))}
|
|
||||||
</NavLink>
|
</NavLink>
|
||||||
)
|
);
|
||||||
|
|
||||||
|
// return (
|
||||||
|
// <NavLink onClick={() => { setSelectedObjectType(map_id, id) }} rightSection={<IconChevronDown size={14} />} p={0} label={`${label} ${count ? `(${count})` : ''}`}>
|
||||||
|
// {Array.isArray(data) && data.map((type) => (
|
||||||
|
// <NavLink key={type.object_id} label={type.caption ? type.caption : 'Без названия'} p={0} onClick={() => setCurrentObjectId(map_id, type.object_id)} />
|
||||||
|
// ))}
|
||||||
|
// </NavLink>
|
||||||
|
// )
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ObjectTree
|
export default ObjectTree
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,10 @@
|
|||||||
import { Checkbox, Flex, NavLink, Slider, Stack } from '@mantine/core'
|
import { Checkbox, Flex, NavLink, Slider, Stack } from '@mantine/core'
|
||||||
import BaseLayer from 'ol/layer/Base'
|
import BaseLayer from 'ol/layer/Base'
|
||||||
import Map from 'ol/Map'
|
import Map from 'ol/Map'
|
||||||
import React, { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
interface MapLayersProps {
|
interface MapLayersProps {
|
||||||
map: React.MutableRefObject<Map | null>
|
map: Map | null
|
||||||
}
|
}
|
||||||
|
|
||||||
const MapLayers = ({
|
const MapLayers = ({
|
||||||
@ -12,7 +12,7 @@ const MapLayers = ({
|
|||||||
}: MapLayersProps) => {
|
}: MapLayersProps) => {
|
||||||
return (
|
return (
|
||||||
<Stack gap='0'>
|
<Stack gap='0'>
|
||||||
{map.current?.getLayers().getArray() && map.current?.getLayers().getArray().map((layer, index) => (
|
{map?.getLayers().getArray() && map?.getLayers().getArray().map((layer, index) => (
|
||||||
<LayerSetting key={index} index={index} layer={layer} />
|
<LayerSetting key={index} index={index} layer={layer} />
|
||||||
))}
|
))}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
104
client/src/components/map/MapLegend/MapLegend.tsx
Normal file
104
client/src/components/map/MapLegend/MapLegend.tsx
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import { Accordion, ActionIcon, Collapse, ColorSwatch, Flex, MantineStyleProp, ScrollAreaAutosize, Stack, Text, useMantineColorScheme } from '@mantine/core'
|
||||||
|
import useSWR from 'swr'
|
||||||
|
import { fetcher } from '../../../http/axiosInstance'
|
||||||
|
import { BASE_URL } from '../../../constants'
|
||||||
|
import { useDisclosure } from '@mantine/hooks'
|
||||||
|
import { IconChevronDown } from '@tabler/icons-react'
|
||||||
|
|
||||||
|
const MapLegend = ({
|
||||||
|
selectedDistrict,
|
||||||
|
selectedYear,
|
||||||
|
style
|
||||||
|
}: {
|
||||||
|
selectedDistrict: number | null,
|
||||||
|
selectedYear: number | null,
|
||||||
|
style: MantineStyleProp
|
||||||
|
}) => {
|
||||||
|
const { colorScheme } = useMantineColorScheme()
|
||||||
|
|
||||||
|
const { data: existingObjectsList } = useSWR(
|
||||||
|
selectedYear && selectedDistrict ? `/general/objects/list?year=${selectedYear}&city_id=${selectedDistrict}&planning=0` : null,
|
||||||
|
(url) => fetcher(url, BASE_URL.ems),
|
||||||
|
{
|
||||||
|
revalidateOnFocus: false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const { data: planningObjectsList } = useSWR(
|
||||||
|
selectedYear && selectedDistrict ? `/general/objects/list?year=${selectedYear}&city_id=${selectedDistrict}&planning=1` : null,
|
||||||
|
(url) => fetcher(url, BASE_URL.ems),
|
||||||
|
{
|
||||||
|
revalidateOnFocus: false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const [opened, { toggle }] = useDisclosure(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ScrollAreaAutosize maw='300px' w='100%' fz='xs' mt='auto' style={{ ...style, zIndex: 1, backdropFilter: 'blur(8px)', backgroundColor: colorScheme === 'light' ? '#FFFFFFAA' : '#000000AA', borderRadius: '4px' }}>
|
||||||
|
<Stack gap='sm' p='sm'>
|
||||||
|
<Flex align='center'>
|
||||||
|
<Text fz='xs'>
|
||||||
|
Легенда
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<ActionIcon ml='auto' variant='subtle' onClick={toggle} >
|
||||||
|
<IconChevronDown style={{ transform: opened ? 'rotate(0deg)' : 'rotate(180deg)' }} />
|
||||||
|
</ActionIcon>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Collapse in={opened}>
|
||||||
|
<Accordion defaultValue={['existing', 'planning']} multiple>
|
||||||
|
<Accordion.Item value='existing' key='existing'>
|
||||||
|
<Accordion.Control>Существующие</Accordion.Control>
|
||||||
|
<Accordion.Panel>
|
||||||
|
{existingObjectsList && <LegendGroup objectsList={existingObjectsList} border='solid' />}
|
||||||
|
</Accordion.Panel>
|
||||||
|
</Accordion.Item>
|
||||||
|
|
||||||
|
<Accordion.Item value='planning' key='planning'>
|
||||||
|
<Accordion.Control>Планируемые</Accordion.Control>
|
||||||
|
<Accordion.Panel>
|
||||||
|
{planningObjectsList && <LegendGroup objectsList={planningObjectsList} border='dotted' />}
|
||||||
|
</Accordion.Panel>
|
||||||
|
</Accordion.Item>
|
||||||
|
</Accordion>
|
||||||
|
</Collapse>
|
||||||
|
</Stack>
|
||||||
|
</ScrollAreaAutosize>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const LegendGroup = ({
|
||||||
|
objectsList,
|
||||||
|
border
|
||||||
|
}: {
|
||||||
|
objectsList: { id: number, name: string, count: number, r: number | null, g: number | null, b: number | null }[],
|
||||||
|
border: 'solid' | 'dotted'
|
||||||
|
}) => {
|
||||||
|
|
||||||
|
const borderStyle = () => {
|
||||||
|
switch (border) {
|
||||||
|
case 'solid':
|
||||||
|
return '2px solid black'
|
||||||
|
case 'dotted':
|
||||||
|
return '2px dotted black'
|
||||||
|
default:
|
||||||
|
return 'none'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack gap={4}>
|
||||||
|
{objectsList.map(object => (
|
||||||
|
<Flex gap='xs' align='center' key={object.id}>
|
||||||
|
<ColorSwatch style={{ border: borderStyle() }} radius={0} size={16} color={`rgb(${object.r},${object.g},${object.b})`} />
|
||||||
|
-
|
||||||
|
<Text fz='xs'>{object.name}</Text>
|
||||||
|
</Flex>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MapLegend
|
||||||
125
client/src/components/map/MapLineTest.tsx
Normal file
125
client/src/components/map/MapLineTest.tsx
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
import { useEffect, useRef } from 'react'
|
||||||
|
import 'ol/ol.css'
|
||||||
|
import { Container, Stack, Tabs } from '@mantine/core'
|
||||||
|
import OlMap from 'ol/Map'
|
||||||
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
import TileLayer from 'ol/layer/Tile'
|
||||||
|
import { OSM } from 'ol/source'
|
||||||
|
import View from 'ol/View'
|
||||||
|
import { transform } from 'ol/proj'
|
||||||
|
import VectorLayer from 'ol/layer/Vector'
|
||||||
|
import VectorSource from 'ol/source/Vector'
|
||||||
|
import Feature from 'ol/Feature'
|
||||||
|
import { LineString } from 'ol/geom'
|
||||||
|
import { Stroke, Style, Text } from 'ol/style'
|
||||||
|
|
||||||
|
const center = [14443331.466543002, 8878970.176309839]
|
||||||
|
|
||||||
|
const style = new Style({
|
||||||
|
stroke: new Stroke({ color: 'blue', width: 2 }),
|
||||||
|
text: new Text({
|
||||||
|
font: 'bold 14px',
|
||||||
|
placement: 'line',
|
||||||
|
offsetY: -14
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const MapLineTest = () => {
|
||||||
|
const lines = [
|
||||||
|
{ name: 'A', points: [[100, 100], [200, 200]] },
|
||||||
|
{ name: 'B', points: [[200, 200], [300, 200]] },
|
||||||
|
{ name: 'X', points: [[200, 200], [300, 300]] },
|
||||||
|
{ name: 'L', points: [[300, 300], [350, 300]] },
|
||||||
|
{ name: 'N', points: [[300, 300], [250, 300]] },
|
||||||
|
{ name: 'I', points: [[300, 200], [300, 100]] },
|
||||||
|
{ name: 'J', points: [[300, 100], [250, 50]] },
|
||||||
|
{ name: 'C', points: [[300, 200], [400, 150]] },
|
||||||
|
{ name: 'D', points: [[400, 150], [400, 100]] },
|
||||||
|
]
|
||||||
|
|
||||||
|
const map = useRef<OlMap | null>(null)
|
||||||
|
const vectorLayer = useRef(new VectorLayer({
|
||||||
|
source: new VectorSource(),
|
||||||
|
style: feature => {
|
||||||
|
style.getText()?.setText(feature.get('label'))
|
||||||
|
return style
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
const mapElement = useRef<HTMLDivElement | null>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
map.current = new OlMap({
|
||||||
|
controls: [],
|
||||||
|
layers: [
|
||||||
|
new TileLayer({ source: new OSM(), properties: { id: uuidv4(), name: 'OpenStreetMap' } }),
|
||||||
|
vectorLayer.current
|
||||||
|
]
|
||||||
|
})
|
||||||
|
map.current.setTarget(mapElement.current as HTMLDivElement)
|
||||||
|
map.current.setView(new View({
|
||||||
|
center: transform([129.7466541, 62.083504], 'EPSG:4326', 'EPSG:3857'),
|
||||||
|
zoom: 16,
|
||||||
|
maxZoom: 21,
|
||||||
|
}))
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (map.current) {
|
||||||
|
const graph = new Map<string, { node: string, distance: number }[]>()
|
||||||
|
|
||||||
|
// build graph adjacency list
|
||||||
|
lines.forEach(({ points }) => {
|
||||||
|
const [start, end] = points.map(pt => pt.join(','))
|
||||||
|
const distance = Math.hypot(points[1][0] - points[0][0], points[1][1] - points[0][1])
|
||||||
|
|
||||||
|
if (!graph.has(start)) graph.set(start, [])
|
||||||
|
if (!graph.has(end)) graph.set(end, [])
|
||||||
|
|
||||||
|
graph.get(start)?.push({ node: end, distance })
|
||||||
|
graph.get(end)?.push({ node: start, distance })
|
||||||
|
})
|
||||||
|
|
||||||
|
// perform DFS to calculate distances from "A"
|
||||||
|
const startNode = lines[0].points[0].join(',')
|
||||||
|
const distances = new Map<string, number>()
|
||||||
|
const dfs = (node: string, currentDist: number) => {
|
||||||
|
if (distances.has(node) && distances.get(node)! <= currentDist) return
|
||||||
|
distances.set(node, currentDist)
|
||||||
|
for (const { node: neighbor, distance } of graph.get(node) || []) {
|
||||||
|
dfs(neighbor, currentDist + distance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dfs(startNode, 0)
|
||||||
|
|
||||||
|
// render features
|
||||||
|
lines.forEach(({ name, points }) => {
|
||||||
|
const lineCoords = points.map(point => [point[0] + center[0], point[1] + center[1]])
|
||||||
|
const feature = new Feature(new LineString(lineCoords))
|
||||||
|
|
||||||
|
const lastNode = points[1].join(',')
|
||||||
|
const label = `${name} ${feature.getGeometry()?.getLength().toFixed(2)} (${distances.get(lastNode)?.toFixed(1) ?? '∞'})`
|
||||||
|
|
||||||
|
feature.set('label', label)
|
||||||
|
vectorLayer.current.getSource()?.addFeature(feature)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container fluid w='100%' pos='relative' p={0}>
|
||||||
|
<Tabs h='100%' variant='default' value={'map'} keepMounted={true}>
|
||||||
|
<Stack gap={0} h='100%'>
|
||||||
|
<Tabs.List>
|
||||||
|
<Tabs.Tab value={'map'}>Map</Tabs.Tab>
|
||||||
|
</Tabs.List>
|
||||||
|
<Tabs.Panel value={'map'} h='100%' pos='relative'>
|
||||||
|
<Container pos='absolute' fluid p={0} w='100%' h='100%' ref={mapElement}></Container>
|
||||||
|
</Tabs.Panel>
|
||||||
|
</Stack>
|
||||||
|
</Tabs>
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MapLineTest
|
||||||
107
client/src/components/map/MapMode.tsx
Normal file
107
client/src/components/map/MapMode.tsx
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import { Button, Flex, FloatingIndicator, Popover, SegmentedControl } from '@mantine/core'
|
||||||
|
import { Mode, setMode, useMapStore } from '../../store/map'
|
||||||
|
import { IconChevronDown, IconCropLandscape, IconCropPortrait, IconEdit, IconEye, IconPrinter } from '@tabler/icons-react'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { PrintOrientation, setPrintOrientation, usePrintStore } from '../../store/print'
|
||||||
|
|
||||||
|
const MapMode = ({
|
||||||
|
map_id
|
||||||
|
}: { map_id: string }) => {
|
||||||
|
const [rootRef, setRootRef] = useState<HTMLDivElement | null>(null);
|
||||||
|
const [controlsRefs, setControlsRefs] = useState<Record<string, HTMLButtonElement | null>>({});
|
||||||
|
|
||||||
|
const { mode } = useMapStore().id[map_id]
|
||||||
|
|
||||||
|
const setControlRef = (item: Mode) => (node: HTMLButtonElement) => {
|
||||||
|
controlsRefs[item] = node;
|
||||||
|
setControlsRefs(controlsRefs);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { printOrientation } = usePrintStore()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
}, [printOrientation])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex ref={setRootRef} p={4} gap={4}>
|
||||||
|
<Button
|
||||||
|
variant={mode === 'view' ? 'filled' : 'subtle'}
|
||||||
|
key={'view'}
|
||||||
|
ref={setControlRef('view' as Mode)}
|
||||||
|
onClick={() => {
|
||||||
|
setMode(map_id, 'view' as Mode)
|
||||||
|
}}
|
||||||
|
leftSection={<IconEye size={16} />}
|
||||||
|
mod={{ active: mode === 'view' as Mode }}
|
||||||
|
>
|
||||||
|
Просмотр
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant={mode === 'edit' ? 'filled' : 'subtle'}
|
||||||
|
key={'edit'}
|
||||||
|
ref={setControlRef('edit' as Mode)}
|
||||||
|
onClick={() => {
|
||||||
|
setMode(map_id, 'edit' as Mode)
|
||||||
|
}}
|
||||||
|
leftSection={<IconEdit size={16} />}
|
||||||
|
mod={{ active: mode === 'edit' as Mode }}
|
||||||
|
>
|
||||||
|
Редактирование
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Popover width='auto' position='bottom-end' >
|
||||||
|
<Popover.Target>
|
||||||
|
<Button.Group>
|
||||||
|
<Button
|
||||||
|
variant={mode === 'print' ? 'filled' : 'subtle'}
|
||||||
|
key={'print'}
|
||||||
|
ref={setControlRef('print' as Mode)}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
setMode(map_id, 'print' as Mode)
|
||||||
|
}}
|
||||||
|
leftSection={<IconPrinter size={16} />}
|
||||||
|
mod={{ active: mode === 'print' as Mode }}
|
||||||
|
>
|
||||||
|
Печать
|
||||||
|
</Button>
|
||||||
|
<Button variant={mode === 'print' ? 'filled' : 'subtle'} w='auto' p={8} title='Ориентация'>
|
||||||
|
<IconChevronDown size={16} />
|
||||||
|
</Button>
|
||||||
|
</Button.Group>
|
||||||
|
</Popover.Target>
|
||||||
|
|
||||||
|
<Popover.Dropdown p={0} style={{ display: 'flex' }}>
|
||||||
|
<SegmentedControl
|
||||||
|
color='blue'
|
||||||
|
value={printOrientation}
|
||||||
|
onChange={(value) => {
|
||||||
|
setPrintOrientation(value as PrintOrientation)
|
||||||
|
setMode(map_id, 'print' as Mode)
|
||||||
|
}}
|
||||||
|
data={[
|
||||||
|
{
|
||||||
|
value: 'horizontal',
|
||||||
|
label: (
|
||||||
|
<IconCropLandscape title='Горизонтальная' style={{ display: 'block' }} size={20} />
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'vertical',
|
||||||
|
label: (
|
||||||
|
<IconCropPortrait title='Вертикальная' style={{ display: 'block' }} size={20} />
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Popover.Dropdown>
|
||||||
|
</Popover>
|
||||||
|
|
||||||
|
<FloatingIndicator target={controlsRefs[mode]} parent={rootRef} />
|
||||||
|
</Flex >
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MapMode
|
||||||
234
client/src/components/map/MapPrint/MapPrint.tsx
Normal file
234
client/src/components/map/MapPrint/MapPrint.tsx
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
import { ActionIcon, Button, Checkbox, Flex, Modal, Radio, ScrollAreaAutosize, Select, Stack, Text } from '@mantine/core'
|
||||||
|
import { IconHelp, IconWindowMaximize, IconWindowMinimize } from '@tabler/icons-react'
|
||||||
|
import React, { useEffect, useRef, useState } from 'react'
|
||||||
|
import { clearPrintArea, PrintScale, setPreviousView, setPrintScale, setPrintScaleLine, useMapStore } from '../../../store/map'
|
||||||
|
import { PrintFormat, PrintOrientation, printResolutions, setPrintOrientation, setPrintResolution, usePrintStore } from '../../../store/print'
|
||||||
|
import { printDimensions, scaleOptions } from '../../../constants/map'
|
||||||
|
import { useObjectsStore } from '../../../store/objects'
|
||||||
|
// import { getPointResolution } from 'ol/proj'
|
||||||
|
import jsPDF from 'jspdf'
|
||||||
|
import { getCenter } from 'ol/extent'
|
||||||
|
import ScaleLine from 'ol/control/ScaleLine'
|
||||||
|
|
||||||
|
const MapPrint = ({
|
||||||
|
id,
|
||||||
|
mapElement
|
||||||
|
}: {
|
||||||
|
id: string
|
||||||
|
mapElement: React.MutableRefObject<HTMLDivElement | null>
|
||||||
|
}) => {
|
||||||
|
const [fullscreen, setFullscreen] = useState(false)
|
||||||
|
const { printOrientation, printResolution, printFormat } = usePrintStore()
|
||||||
|
const { selectedYear, selectedRegion, selectedDistrict } = useObjectsStore().id[id]
|
||||||
|
|
||||||
|
const {
|
||||||
|
map,
|
||||||
|
previousView, printArea, printSource, printAreaDraw, printScale, printScaleLine,
|
||||||
|
} = useMapStore().id[id]
|
||||||
|
|
||||||
|
const exportToPDF = (format: PrintFormat, resolution: number, orientation: PrintOrientation) => {
|
||||||
|
const dim = printDimensions[format]
|
||||||
|
|
||||||
|
const width = Math.round((dim[orientation === 'horizontal' ? 0 : 1] * resolution) / 25.4)
|
||||||
|
const height = Math.round((dim[orientation === 'horizontal' ? 1 : 0] * resolution) / 25.4)
|
||||||
|
|
||||||
|
if (!map) return
|
||||||
|
|
||||||
|
// Store original size and scale
|
||||||
|
const originalSize = map.getSize()
|
||||||
|
const originalResolution = map.getView().getResolution()
|
||||||
|
|
||||||
|
if (!originalSize || !originalResolution) return
|
||||||
|
|
||||||
|
// Calculate new resolution to fit high DPI
|
||||||
|
const scaleFactor = width / originalSize[0]
|
||||||
|
const newResolution = originalResolution / scaleFactor
|
||||||
|
|
||||||
|
// console.log(`New resolution: ${newResolution}`)
|
||||||
|
|
||||||
|
// const center = map.getView().getCenter()
|
||||||
|
// let scaleResolution = 1
|
||||||
|
// if (center) {
|
||||||
|
// scaleResolution = Number(printScale) / getPointResolution(map.getView().getProjection(), Number(resolution) / 25.4, center)
|
||||||
|
// // console.log(`Scaled resolution: ${scaleResolution}`)
|
||||||
|
// }
|
||||||
|
|
||||||
|
console.log(width, height)
|
||||||
|
// Set new high-resolution rendering
|
||||||
|
map.setSize([width, height])
|
||||||
|
map.getView().setResolution(newResolution)
|
||||||
|
map.renderSync()
|
||||||
|
|
||||||
|
map.once("rendercomplete", function () {
|
||||||
|
const mapCanvas = document.createElement("canvas")
|
||||||
|
mapCanvas.width = width
|
||||||
|
mapCanvas.height = height
|
||||||
|
const mapContext = mapCanvas.getContext("2d")
|
||||||
|
|
||||||
|
if (!mapContext) return
|
||||||
|
|
||||||
|
const canvas = document.querySelector('canvas')
|
||||||
|
if (canvas) {
|
||||||
|
if (canvas.width > 0) {
|
||||||
|
const opacity = canvas.parentElement?.style.opacity || "1"
|
||||||
|
mapContext.globalAlpha = parseFloat(opacity)
|
||||||
|
|
||||||
|
const transform = canvas.style.transform
|
||||||
|
const matrixMatch = transform.match(/^matrix\(([^)]+)\)$/)
|
||||||
|
if (matrixMatch) {
|
||||||
|
const matrix = matrixMatch[1].split(",").map(Number)
|
||||||
|
mapContext.setTransform(...matrix as [number, number, number, number, number, number])
|
||||||
|
}
|
||||||
|
|
||||||
|
mapContext.drawImage(canvas, 0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mapContext.globalAlpha = 1
|
||||||
|
mapContext.setTransform(1, 0, 0, 1, 0, 0)
|
||||||
|
|
||||||
|
// Restore original map settings
|
||||||
|
map.setSize(originalSize)
|
||||||
|
map.getView().setResolution(originalResolution)
|
||||||
|
map.renderSync()
|
||||||
|
|
||||||
|
const dimensions = {
|
||||||
|
w: orientation === 'horizontal' ? dim[0] : dim[1],
|
||||||
|
h: orientation === 'horizontal' ? dim[1] : dim[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate PDF
|
||||||
|
const pdf = new jsPDF(orientation === 'horizontal' ? "landscape" : 'portrait', undefined, format)
|
||||||
|
pdf.addImage(mapCanvas.toDataURL("image/jpeg"), "JPEG", 0, 0, dimensions.w, dimensions.h)
|
||||||
|
|
||||||
|
const filename = `${selectedYear}-${selectedRegion}-${selectedDistrict}-${new Date().toISOString()}.pdf`
|
||||||
|
pdf.save(filename, {
|
||||||
|
returnPromise: true
|
||||||
|
}).then(() => {
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const scaleLine = useRef(new ScaleLine({
|
||||||
|
bar: true,
|
||||||
|
text: true,
|
||||||
|
minWidth: 125
|
||||||
|
}))
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (printArea) {
|
||||||
|
// backup view before entering print mode
|
||||||
|
setPreviousView(id, map?.getView())
|
||||||
|
|
||||||
|
map?.setTarget('print-portal')
|
||||||
|
|
||||||
|
printSource.clear()
|
||||||
|
map?.getView().setCenter(getCenter(printArea))
|
||||||
|
map?.getView().fit(printArea, {
|
||||||
|
size: printOrientation === 'horizontal' ? [594, 420] : [420, 594]
|
||||||
|
})
|
||||||
|
map?.removeInteraction(printAreaDraw)
|
||||||
|
}
|
||||||
|
}, [printArea, map])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (printScaleLine && printArea) {
|
||||||
|
map?.addControl(scaleLine.current)
|
||||||
|
} else {
|
||||||
|
map?.removeControl(scaleLine.current)
|
||||||
|
}
|
||||||
|
}, [printScaleLine, printArea])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal.Root
|
||||||
|
scrollAreaComponent={ScrollAreaAutosize}
|
||||||
|
keepMounted size='auto'
|
||||||
|
opened={!!printArea}
|
||||||
|
onClose={() => {
|
||||||
|
clearPrintArea(id)
|
||||||
|
map?.setTarget(mapElement.current as HTMLDivElement)
|
||||||
|
map?.addInteraction(printAreaDraw)
|
||||||
|
}} fullScreen={fullscreen}>
|
||||||
|
<Modal.Overlay />
|
||||||
|
<Modal.Content style={{ transition: 'all .3s ease' }}>
|
||||||
|
<Modal.Header>
|
||||||
|
<Modal.Title>
|
||||||
|
Предпросмотр области печати
|
||||||
|
</Modal.Title>
|
||||||
|
|
||||||
|
<Flex ml='auto' gap='md'>
|
||||||
|
<ActionIcon title='Помощь' ml='auto' variant='transparent'>
|
||||||
|
<IconHelp color='gray' />
|
||||||
|
</ActionIcon>
|
||||||
|
<ActionIcon title={fullscreen ? 'Свернуть' : 'Развернуть'} variant='transparent' onClick={() => setFullscreen(!fullscreen)}>
|
||||||
|
{fullscreen ? <IconWindowMinimize color='gray' /> : <IconWindowMaximize color='gray' />}
|
||||||
|
</ActionIcon>
|
||||||
|
<Modal.CloseButton title='Закрыть' />
|
||||||
|
</Flex>
|
||||||
|
</Modal.Header>
|
||||||
|
<Modal.Body>
|
||||||
|
<Stack align='center'>
|
||||||
|
<Text w='100%'>Область печати можно передвигать.</Text>
|
||||||
|
|
||||||
|
<div id='print-portal' style={{
|
||||||
|
width: printOrientation === 'horizontal' ? '594px' : '420px',
|
||||||
|
height: printOrientation === 'horizontal' ? '420px' : '594px'
|
||||||
|
}}>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Flex w='100%' wrap='wrap' gap='lg' justify='space-between'>
|
||||||
|
<Radio.Group
|
||||||
|
label='Ориентация'
|
||||||
|
value={printOrientation}
|
||||||
|
onChange={(value) => setPrintOrientation(value as PrintOrientation)}
|
||||||
|
>
|
||||||
|
<Stack>
|
||||||
|
<Radio value='horizontal' label='Горизонтальная' />
|
||||||
|
<Radio value='vertical' label='Вертикальная' />
|
||||||
|
</Stack>
|
||||||
|
</Radio.Group>
|
||||||
|
|
||||||
|
<Select
|
||||||
|
allowDeselect={false}
|
||||||
|
label="Разрешение"
|
||||||
|
placeholder="Выберите разрешение"
|
||||||
|
data={printResolutions}
|
||||||
|
value={printResolution.toString()}
|
||||||
|
onChange={(value) => setPrintResolution(Number(value))}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Select
|
||||||
|
allowDeselect={false}
|
||||||
|
label="Масштаб"
|
||||||
|
placeholder="Выберите масштаб"
|
||||||
|
data={scaleOptions}
|
||||||
|
value={printScale}
|
||||||
|
onChange={(value) => setPrintScale(id, value as PrintScale)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Checkbox
|
||||||
|
checked={printScaleLine}
|
||||||
|
label="Масштабная линия"
|
||||||
|
onChange={(event) => setPrintScaleLine(id, event.currentTarget.checked)}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Flex w='100%' gap='sm' align='center'>
|
||||||
|
<Button ml='auto' onClick={() => {
|
||||||
|
if (previousView) {
|
||||||
|
exportToPDF(printFormat, printResolution, printOrientation)
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
Печать
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
</Stack>
|
||||||
|
</Modal.Body>
|
||||||
|
</Modal.Content>
|
||||||
|
</Modal.Root>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MapPrint
|
||||||
@ -26,7 +26,7 @@ const customMapSource = new XYZ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const regionsLayerSource = new VectorSource({
|
const regionsLayerSource = new VectorSource({
|
||||||
url: 'sakha_republic.geojson',
|
url: 'http://localhost:5000/gis/bounds/region',
|
||||||
format: new GeoJSON(),
|
format: new GeoJSON(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -4,39 +4,41 @@ import { useMapStore } from '../../../store/map';
|
|||||||
|
|
||||||
interface IMapStatusbarProps {
|
interface IMapStatusbarProps {
|
||||||
mapControlsStyle: CSSProperties;
|
mapControlsStyle: CSSProperties;
|
||||||
|
map_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MapStatusbar = ({
|
const MapStatusbar = ({
|
||||||
mapControlsStyle,
|
mapControlsStyle,
|
||||||
|
map_id
|
||||||
}: IMapStatusbarProps) => {
|
}: IMapStatusbarProps) => {
|
||||||
const mapState = useMapStore()
|
const { currentCoordinate, currentX, currentY, currentZ, statusText } = useMapStore().id[map_id]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex gap='sm' p={'4px'} miw={'100%'} fz={'xs'} pos='absolute' bottom='0px' left='0px' style={{ ...mapControlsStyle, borderRadius: 0 }}>
|
<Flex gap='sm' p={'4px'} w={'100%'} fz={'xs'} style={{ ...mapControlsStyle, borderRadius: 0 }}>
|
||||||
<Text fz='xs' w={rem(130)}>
|
<Text fz='xs' w={rem(130)}>
|
||||||
x: {mapState.currentCoordinate?.[0]}
|
x: {currentCoordinate?.[0]}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text fz='xs' w={rem(130)}>
|
<Text fz='xs' w={rem(130)}>
|
||||||
y: {mapState.currentCoordinate?.[1]}
|
y: {currentCoordinate?.[1]}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Divider orientation='vertical' />
|
<Divider orientation='vertical' />
|
||||||
|
|
||||||
<Text fz='xs'>
|
<Text fz='xs'>
|
||||||
Z={mapState.currentZ}
|
Z={currentZ}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text fz='xs'>
|
<Text fz='xs'>
|
||||||
X={mapState.currentX}
|
X={currentX}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text fz='xs'>
|
<Text fz='xs'>
|
||||||
Y={mapState.currentY}
|
Y={currentY}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text fz='xs' ml='auto'>
|
<Text fz='xs' ml='auto'>
|
||||||
{mapState.statusText}
|
{statusText}
|
||||||
</Text>
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import Feature, { FeatureLike } from "ol/Feature";
|
import { FeatureLike } from "ol/Feature";
|
||||||
import { Text } from "ol/style";
|
import { Text } from "ol/style";
|
||||||
import Fill from "ol/style/Fill";
|
import Fill from "ol/style/Fill";
|
||||||
import { FlatStyleLike } from "ol/style/flat";
|
import { FlatStyleLike } from "ol/style/flat";
|
||||||
@ -90,101 +90,39 @@ export function overlayStyle(feature: FeatureLike) {
|
|||||||
return styles
|
return styles
|
||||||
}
|
}
|
||||||
|
|
||||||
export function styleFunction(feature: Feature) {
|
const figureStyle = new Style({
|
||||||
return [
|
fill: new Fill({
|
||||||
new Style({
|
color: 'rgba(255,255,255,0.4)'
|
||||||
fill: new Fill({
|
}),
|
||||||
color: 'rgba(255,255,255,0.4)'
|
stroke: new Stroke({
|
||||||
}),
|
color: 'black',
|
||||||
stroke: new Stroke({
|
width: 1.25
|
||||||
color: '#3399CC',
|
}),
|
||||||
width: 1.25
|
text: new Text({
|
||||||
}),
|
font: '12px Calibri,sans-serif',
|
||||||
text: new Text({
|
fill: new Fill({ color: '#000' }),
|
||||||
font: '12px Calibri,sans-serif',
|
stroke: new Stroke({
|
||||||
fill: new Fill({ color: '#000' }),
|
color: '#fff', width: 2
|
||||||
stroke: new Stroke({
|
|
||||||
color: '#fff', width: 2
|
|
||||||
}),
|
|
||||||
// get the text from the feature - `this` is ol.Feature
|
|
||||||
// and show only under certain resolution
|
|
||||||
text: feature.get('object_id')
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
];
|
})
|
||||||
}
|
})
|
||||||
|
|
||||||
export function firstStyleFunction(feature: Feature) {
|
const lineStyle = new Style({
|
||||||
return [
|
stroke: new Stroke({
|
||||||
new Style({
|
color: '#3399CC',
|
||||||
fill: new Fill({
|
width: 1
|
||||||
color: 'rgba(255,255,255,0.4)'
|
}),
|
||||||
}),
|
text: new Text({
|
||||||
stroke: new Stroke({
|
font: '12px Calibri,sans-serif',
|
||||||
color: 'red',
|
fill: new Fill({ color: '#000' }),
|
||||||
width: 1.25
|
stroke: new Stroke({
|
||||||
}),
|
color: '#fff', width: 2
|
||||||
text: new Text({
|
}),
|
||||||
font: '12px Calibri,sans-serif',
|
placement: 'line',
|
||||||
fill: new Fill({ color: '#000' }),
|
overflow: true,
|
||||||
stroke: new Stroke({
|
//declutterMode: 'obstacle'
|
||||||
color: '#fff', width: 2
|
})
|
||||||
}),
|
})
|
||||||
// get the text from the feature - `this` is ol.Feature
|
|
||||||
// and show only under certain resolution
|
|
||||||
text: feature.get('object_id')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function thirdStyleFunction(feature: Feature) {
|
|
||||||
return [
|
|
||||||
new Style({
|
|
||||||
fill: new Fill({
|
|
||||||
color: 'rgba(255,255,255,0.4)'
|
|
||||||
}),
|
|
||||||
stroke: new Stroke({
|
|
||||||
color: '#33ccb3',
|
|
||||||
width: 1.25
|
|
||||||
}),
|
|
||||||
text: new Text({
|
|
||||||
font: '12px Calibri,sans-serif',
|
|
||||||
fill: new Fill({ color: '#000' }),
|
|
||||||
stroke: new Stroke({
|
|
||||||
color: '#fff', width: 2
|
|
||||||
}),
|
|
||||||
// get the text from the feature - `this` is ol.Feature
|
|
||||||
// and show only under certain resolution
|
|
||||||
text: feature.get('object_id')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fourthStyleFunction(feature: Feature) {
|
|
||||||
return [
|
|
||||||
new Style({
|
|
||||||
fill: new Fill({
|
|
||||||
color: 'rgba(255,255,255,0.4)'
|
|
||||||
}),
|
|
||||||
stroke: new Stroke({
|
|
||||||
color: '#3399CC',
|
|
||||||
width: 1.25
|
|
||||||
}),
|
|
||||||
text: new Text({
|
|
||||||
font: '12px Calibri,sans-serif',
|
|
||||||
fill: new Fill({ color: '#000' }),
|
|
||||||
stroke: new Stroke({
|
|
||||||
color: '#fff', width: 2
|
|
||||||
}),
|
|
||||||
// get the text from the feature - `this` is ol.Feature
|
|
||||||
// and show only under certain resolution
|
|
||||||
text: `${feature.get('object_id')}\n ${feature.get('angle')}`
|
|
||||||
})
|
|
||||||
})
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
const drawingLayerStyle: FlatStyleLike = {
|
const drawingLayerStyle: FlatStyleLike = {
|
||||||
'fill-color': 'rgba(255, 255, 255, 0.2)',
|
'fill-color': 'rgba(255, 255, 255, 0.2)',
|
||||||
@ -218,5 +156,7 @@ const regionsLayerStyle = new Style({
|
|||||||
export {
|
export {
|
||||||
drawingLayerStyle,
|
drawingLayerStyle,
|
||||||
selectStyle,
|
selectStyle,
|
||||||
regionsLayerStyle
|
regionsLayerStyle,
|
||||||
|
lineStyle,
|
||||||
|
figureStyle
|
||||||
}
|
}
|
||||||
@ -1,93 +1,90 @@
|
|||||||
import { ActionIcon, useMantineColorScheme } from '@mantine/core'
|
import { ActionIcon, Flex, useMantineColorScheme } from '@mantine/core'
|
||||||
import { IconArrowBackUp, IconArrowsMove, IconCircle, IconExclamationCircle, IconLine, IconPoint, IconPolygon, IconRuler, IconTransformPoint } from '@tabler/icons-react'
|
import { IconArrowBackUp, IconArrowsMove, IconCircle, IconExclamationCircle, IconLine, IconPoint, IconPolygon, IconRuler, IconTransformPoint } from '@tabler/icons-react'
|
||||||
import { setCurrentTool, useMapStore } from '../../../store/map';
|
import { getDraw, setCurrentTool, useMapStore } from '../../../store/map';
|
||||||
|
import { saveFeatures } from '../mapUtils';
|
||||||
interface IToolbarProps {
|
|
||||||
onSave: () => void;
|
|
||||||
onRemove: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MapToolbar = ({
|
const MapToolbar = ({
|
||||||
onSave,
|
map_id
|
||||||
onRemove,
|
}: { map_id: string }) => {
|
||||||
}: IToolbarProps) => {
|
const { currentTool } = useMapStore().id[map_id]
|
||||||
const mapState = useMapStore()
|
|
||||||
const { colorScheme } = useMantineColorScheme();
|
const { colorScheme } = useMantineColorScheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ActionIcon.Group orientation='vertical' pos='absolute' top='8px' right='8px' style={{ zIndex: 1, backdropFilter: 'blur(8px)', backgroundColor: colorScheme === 'light' ? '#FFFFFFAA' : '#000000AA', borderRadius: '4px' }}>
|
<Flex>
|
||||||
<ActionIcon size='lg' variant='transparent' onClick={onSave}>
|
<ActionIcon.Group orientation='vertical' style={{ zIndex: 1, backdropFilter: 'blur(8px)', backgroundColor: colorScheme === 'light' ? '#FFFFFFAA' : '#000000AA', borderRadius: '4px' }}>
|
||||||
<IconExclamationCircle />
|
<ActionIcon size='lg' variant='transparent' onClick={() => saveFeatures(map_id)}>
|
||||||
</ActionIcon>
|
<IconExclamationCircle />
|
||||||
|
</ActionIcon>
|
||||||
|
|
||||||
<ActionIcon size='lg' variant='transparent' onClick={onRemove}>
|
<ActionIcon size='lg' variant='transparent' onClick={() => getDraw(map_id)?.removeLastPoint()}>
|
||||||
<IconArrowBackUp />
|
<IconArrowBackUp />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
|
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
size='lg'
|
size='lg'
|
||||||
variant={mapState.currentTool === 'Edit' ? 'filled' : 'transparent'}
|
variant={currentTool === 'Edit' ? 'filled' : 'transparent'}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setCurrentTool('Edit')
|
setCurrentTool(map_id, 'Edit')
|
||||||
}}>
|
}}>
|
||||||
<IconTransformPoint />
|
<IconTransformPoint />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
|
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
size='lg'
|
size='lg'
|
||||||
variant={mapState.currentTool === 'Point' ? 'filled' : 'transparent'}
|
variant={currentTool === 'Point' ? 'filled' : 'transparent'}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setCurrentTool('Point')
|
setCurrentTool(map_id, 'Point')
|
||||||
}}>
|
}}>
|
||||||
<IconPoint />
|
<IconPoint />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
|
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
size='lg'
|
size='lg'
|
||||||
variant={mapState.currentTool === 'LineString' ? 'filled' : 'transparent'}
|
variant={currentTool === 'LineString' ? 'filled' : 'transparent'}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setCurrentTool('LineString')
|
setCurrentTool(map_id, 'LineString')
|
||||||
}}>
|
}}>
|
||||||
<IconLine />
|
<IconLine />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
|
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
size='lg'
|
size='lg'
|
||||||
variant={mapState.currentTool === 'Polygon' ? 'filled' : 'transparent'}
|
variant={currentTool === 'Polygon' ? 'filled' : 'transparent'}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setCurrentTool('Polygon')
|
setCurrentTool(map_id, 'Polygon')
|
||||||
}}>
|
}}>
|
||||||
<IconPolygon />
|
<IconPolygon />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
|
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
size='lg'
|
size='lg'
|
||||||
variant={mapState.currentTool === 'Circle' ? 'filled' : 'transparent'}
|
variant={currentTool === 'Circle' ? 'filled' : 'transparent'}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setCurrentTool('Circle')
|
setCurrentTool(map_id, 'Circle')
|
||||||
}}>
|
}}>
|
||||||
<IconCircle />
|
<IconCircle />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
|
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
size='lg'
|
size='lg'
|
||||||
variant={mapState.currentTool === 'Mover' ? 'filled' : 'transparent'}
|
variant={currentTool === 'Mover' ? 'filled' : 'transparent'}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setCurrentTool('Mover')
|
setCurrentTool(map_id, 'Mover')
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconArrowsMove />
|
<IconArrowsMove />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
|
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
size='lg'
|
size='lg'
|
||||||
variant={mapState.currentTool === 'Measure' ? 'filled' : 'transparent'}
|
variant={currentTool === 'Measure' ? 'filled' : 'transparent'}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setCurrentTool('Measure')
|
setCurrentTool(map_id, 'Measure')
|
||||||
}}>
|
}}>
|
||||||
<IconRuler />
|
<IconRuler />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</ActionIcon.Group>
|
</ActionIcon.Group>
|
||||||
|
</Flex>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -138,6 +138,7 @@ const formatArea = function (polygon: Geometry) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function measureStyleFunction(
|
export function measureStyleFunction(
|
||||||
|
map_id: string,
|
||||||
feature: FeatureLike,
|
feature: FeatureLike,
|
||||||
drawType?: Type,
|
drawType?: Type,
|
||||||
tip?: string,
|
tip?: string,
|
||||||
@ -149,7 +150,7 @@ export function measureStyleFunction(
|
|||||||
const type = geometry?.getType();
|
const type = geometry?.getType();
|
||||||
const segmentStyles = [segmentStyle];
|
const segmentStyles = [segmentStyle];
|
||||||
|
|
||||||
const segments = getMeasureShowSegments()
|
const segments = getMeasureShowSegments(map_id)
|
||||||
|
|
||||||
if (!geometry) return
|
if (!geometry) return
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { BASE_URL } from '../../constants'
|
|||||||
|
|
||||||
const ObjectData = (object_data: IObjectData) => {
|
const ObjectData = (object_data: IObjectData) => {
|
||||||
const { data: typeData } = useSWR(
|
const { data: typeData } = useSWR(
|
||||||
object_data.type ? `/general/types/all` : null,
|
object_data.type ? `/general/types` : null,
|
||||||
(url) => fetcher(url, BASE_URL.ems),
|
(url) => fetcher(url, BASE_URL.ems),
|
||||||
{
|
{
|
||||||
revalidateOnFocus: false
|
revalidateOnFocus: false
|
||||||
|
|||||||
@ -6,15 +6,17 @@ import TCBParameter from './TCBParameter'
|
|||||||
import TableValue from './TableValue'
|
import TableValue from './TableValue'
|
||||||
|
|
||||||
interface ObjectParameterProps {
|
interface ObjectParameterProps {
|
||||||
showLabel?: boolean,
|
showLabel?: boolean;
|
||||||
param: IObjectParam,
|
param: IObjectParam;
|
||||||
|
map_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ObjectParameter = ({
|
const ObjectParameter = ({
|
||||||
param
|
param,
|
||||||
|
map_id
|
||||||
}: ObjectParameterProps) => {
|
}: ObjectParameterProps) => {
|
||||||
const { data: paramData } = useSWR(
|
const { data: paramData } = useSWR(
|
||||||
`/general/params/all?param_id=${param.id_param}`,
|
`/general/params/?param_id=${param.id_param}`,
|
||||||
(url) => fetcher(url, BASE_URL.ems).then(res => res[0] as IParam),
|
(url) => fetcher(url, BASE_URL.ems).then(res => res[0] as IParam),
|
||||||
{
|
{
|
||||||
revalidateOnFocus: false,
|
revalidateOnFocus: false,
|
||||||
@ -26,44 +28,48 @@ const ObjectParameter = ({
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case 'bit':
|
case 'bit':
|
||||||
return (
|
return (
|
||||||
<TableValue value={value} name={name} type='boolean' />
|
<TableValue map_id={map_id} value={value} name={name} type='boolean' />
|
||||||
|
)
|
||||||
|
case 'int':
|
||||||
|
return (
|
||||||
|
<TableValue map_id={map_id} value={value} name={name} type='number' />
|
||||||
)
|
)
|
||||||
case 'bigint':
|
case 'bigint':
|
||||||
return (
|
return (
|
||||||
<TableValue value={value} name={name} type='number' />
|
<TableValue map_id={map_id} value={value} name={name} type='number' />
|
||||||
)
|
)
|
||||||
case 'tinyint':
|
case 'tinyint':
|
||||||
return (
|
return (
|
||||||
<TableValue value={value} name={name} type='number' />
|
<TableValue map_id={map_id} value={value} name={name} type='number' />
|
||||||
)
|
)
|
||||||
// TODO: Calculate from calc procedures
|
// TODO: Calculate from calc procedures
|
||||||
case 'calculate':
|
case 'calculate':
|
||||||
return (
|
return (
|
||||||
<TableValue value={value} name={name} type='value' />
|
<TableValue map_id={map_id} value={value} name={name} type='value' />
|
||||||
)
|
)
|
||||||
case 'GTCB':
|
case 'GTCB':
|
||||||
return (
|
return (
|
||||||
<TCBParameter value={value as string} vtable={vtable} name={name} />
|
<TCBParameter map_id={map_id} value={value as string} vtable={vtable} name={name} />
|
||||||
)
|
)
|
||||||
case 'TCB':
|
case 'TCB':
|
||||||
return (
|
return (
|
||||||
<TCBParameter value={value as string} vtable={vtable} name={name} />
|
<TCBParameter map_id={map_id} value={value as string} vtable={vtable} name={name} />
|
||||||
)
|
)
|
||||||
case type.match(/varchar\((\d+)\)/)?.input:
|
case type.match(/varchar\((\d+)\)/)?.input:
|
||||||
return (
|
return (
|
||||||
<TableValue value={value} name={name} type='string' />
|
<TableValue map_id={map_id} value={value} name={name} type='string' />
|
||||||
)
|
)
|
||||||
case type.match(/numeric\((\d+),(\d+)\)/)?.input:
|
case type.match(/numeric\((\d+),(\d+)\)/)?.input:
|
||||||
return (
|
return (
|
||||||
<TableValue value={value} name={name} type='number' unit={unit} />
|
<TableValue map_id={map_id} value={value} name={name} type='number' unit={unit} />
|
||||||
)
|
)
|
||||||
case 'year':
|
case 'year':
|
||||||
return (
|
return (
|
||||||
<TableValue value={value} name={name} type='number' />
|
<TableValue map_id={map_id} value={value} name={name} type='number' />
|
||||||
)
|
)
|
||||||
case 'uniqueidentifier':
|
case 'uniqueidentifier':
|
||||||
return (
|
return (
|
||||||
<TableValue value={value} name={name} type='value'/>
|
<TableValue map_id={map_id} value={value} name={name} type='value' />
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -6,11 +6,16 @@ import { BASE_URL } from '../../../constants';
|
|||||||
import { fetcher } from '../../../http/axiosInstance';
|
import { fetcher } from '../../../http/axiosInstance';
|
||||||
import { useObjectsStore } from '../../../store/objects';
|
import { useObjectsStore } from '../../../store/objects';
|
||||||
|
|
||||||
const ObjectParameters = () => {
|
const ObjectParameters = ({
|
||||||
const { currentObjectId } = useObjectsStore()
|
map_id
|
||||||
|
}: {
|
||||||
|
map_id: string
|
||||||
|
}) => {
|
||||||
|
|
||||||
|
const { currentObjectId } = useObjectsStore().id[map_id]
|
||||||
|
|
||||||
const { data: valuesData, isValidating: valuesValidating } = useSWR(
|
const { data: valuesData, isValidating: valuesValidating } = useSWR(
|
||||||
currentObjectId ? `/general/values/all?object_id=${currentObjectId}` : null,
|
currentObjectId ? `/general/values/?object_id=${currentObjectId}` : null,
|
||||||
(url) => fetcher(url, BASE_URL.ems),
|
(url) => fetcher(url, BASE_URL.ems),
|
||||||
{
|
{
|
||||||
revalidateOnFocus: false,
|
revalidateOnFocus: false,
|
||||||
@ -42,13 +47,13 @@ const ObjectParameters = () => {
|
|||||||
sortedParams.map((param: IObjectParam) => {
|
sortedParams.map((param: IObjectParam) => {
|
||||||
if (param.date_po == null) {
|
if (param.date_po == null) {
|
||||||
return (
|
return (
|
||||||
<ObjectParameter key={id_param} param={param} showLabel={false} />
|
<ObjectParameter map_id={map_id} key={id_param} param={param} showLabel={false} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
<ObjectParameter key={id_param} param={sortedParams[0]} />
|
<ObjectParameter map_id={map_id} key={id_param} param={sortedParams[0]} />
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,12 +9,14 @@ interface ITCBParameterProps {
|
|||||||
vtable: string;
|
vtable: string;
|
||||||
inactive?: boolean;
|
inactive?: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
|
map_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TCBParameter = ({
|
const TCBParameter = ({
|
||||||
value,
|
value,
|
||||||
vtable,
|
vtable,
|
||||||
name
|
name,
|
||||||
|
map_id
|
||||||
}: ITCBParameterProps) => {
|
}: ITCBParameterProps) => {
|
||||||
|
|
||||||
//Get value
|
//Get value
|
||||||
@ -28,6 +30,8 @@ const TCBParameter = ({
|
|||||||
)
|
)
|
||||||
|
|
||||||
const tables = [
|
const tables = [
|
||||||
|
'BoilersTemper',
|
||||||
|
'FuelsParametrs',
|
||||||
'PipesTypes',
|
'PipesTypes',
|
||||||
'vAddRepairEvent',
|
'vAddRepairEvent',
|
||||||
'vBoilers',
|
'vBoilers',
|
||||||
@ -80,7 +84,7 @@ const TCBParameter = ({
|
|||||||
const TCBValue = (vtable: string) => {
|
const TCBValue = (vtable: string) => {
|
||||||
if (tables.includes(vtable)) {
|
if (tables.includes(vtable)) {
|
||||||
return (
|
return (
|
||||||
<TableValue value={tcbValue?.id} name={name} type='select' vtable={vtable} />
|
<TableValue map_id={map_id} value={tcbValue?.id} name={name} type='select' vtable={vtable} />
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -10,6 +10,7 @@ interface TableValueProps {
|
|||||||
type: 'value' | 'boolean' | 'number' | 'select' | 'string';
|
type: 'value' | 'boolean' | 'number' | 'select' | 'string';
|
||||||
unit?: string | null | undefined;
|
unit?: string | null | undefined;
|
||||||
vtable?: string;
|
vtable?: string;
|
||||||
|
map_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TableValue = ({
|
const TableValue = ({
|
||||||
@ -17,10 +18,10 @@ const TableValue = ({
|
|||||||
value,
|
value,
|
||||||
type,
|
type,
|
||||||
unit,
|
unit,
|
||||||
vtable
|
vtable,
|
||||||
|
map_id
|
||||||
}: TableValueProps) => {
|
}: TableValueProps) => {
|
||||||
const { selectedDistrict } = useObjectsStore()
|
const { selectedDistrict } = useObjectsStore().id[map_id]
|
||||||
|
|
||||||
//Get available values
|
//Get available values
|
||||||
const { data: tcbAll, isValidating } = useSWR(
|
const { data: tcbAll, isValidating } = useSWR(
|
||||||
type === 'select' && selectedDistrict ? `/general/params/tcb?vtable=${vtable}&id_city=${selectedDistrict}` : null,
|
type === 'select' && selectedDistrict ? `/general/params/tcb?vtable=${vtable}&id_city=${selectedDistrict}` : null,
|
||||||
@ -56,10 +57,10 @@ const TableValue = ({
|
|||||||
/>
|
/>
|
||||||
:
|
:
|
||||||
type === 'select' && !isValidating && tcbAll ?
|
type === 'select' && !isValidating && tcbAll ?
|
||||||
<Select size='xs' data={tcbAll} defaultValue={JSON.stringify(value)} />
|
<Select size='xs' data={tcbAll} value={JSON.stringify(value)} />
|
||||||
:
|
:
|
||||||
type === 'string' ?
|
type === 'string' ?
|
||||||
<Textarea size='xs' defaultValue={value as string} autosize minRows={1} />
|
<Textarea size='xs' value={value as string} autosize minRows={1} />
|
||||||
:
|
:
|
||||||
<Text size='xs'>{value as string}</Text>
|
<Text size='xs'>{value as string}</Text>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,9 +31,9 @@ const TabsPane = ({
|
|||||||
</ScrollAreaAutosize>
|
</ScrollAreaAutosize>
|
||||||
|
|
||||||
|
|
||||||
<ScrollAreaAutosize h='100%' offsetScrollbars p='xs'>
|
<ScrollAreaAutosize h='100%' offsetScrollbars>
|
||||||
{tabs.map(tab => (
|
{tabs.map(tab => (
|
||||||
<Tabs.Panel key={tab.value} value={tab.value}>
|
<Tabs.Panel p='xs' key={tab.value} value={tab.value}>
|
||||||
{tab.view}
|
{tab.view}
|
||||||
</Tabs.Panel>
|
</Tabs.Panel>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -1,34 +1,35 @@
|
|||||||
import { Coordinate, distance, rotate } from "ol/coordinate";
|
import { Coordinate, distance, rotate } from "ol/coordinate";
|
||||||
import { containsExtent, Extent, getCenter, getHeight, getWidth } from "ol/extent";
|
import { Extent, getCenter, getHeight, getWidth } from "ol/extent";
|
||||||
import Feature from "ol/Feature";
|
import Feature from "ol/Feature";
|
||||||
import GeoJSON from "ol/format/GeoJSON";
|
import GeoJSON from "ol/format/GeoJSON";
|
||||||
import { Circle, Geometry, LineString, Polygon, SimpleGeometry } from "ol/geom";
|
import { Circle, Geometry, LineString, Point, Polygon, SimpleGeometry } from "ol/geom";
|
||||||
import VectorLayer from "ol/layer/Vector";
|
import VectorLayer from "ol/layer/Vector";
|
||||||
import VectorImageLayer from "ol/layer/VectorImage";
|
|
||||||
import Map from "ol/Map";
|
|
||||||
import { addCoordinateTransforms, addProjection, get, getTransform, Projection, ProjectionLike, transform } from "ol/proj";
|
import { addCoordinateTransforms, addProjection, get, getTransform, Projection, ProjectionLike, transform } from "ol/proj";
|
||||||
import VectorSource from "ol/source/Vector";
|
|
||||||
import proj4 from "proj4";
|
import proj4 from "proj4";
|
||||||
import { firstStyleFunction, fourthStyleFunction, selectStyle, styleFunction, thirdStyleFunction } from "./MapStyles";
|
|
||||||
import { Type } from "ol/geom/Geometry";
|
import { Type } from "ol/geom/Geometry";
|
||||||
import { Draw, Modify, Snap, Translate } from "ol/interaction";
|
import { Draw, Modify, Snap, Translate } from "ol/interaction";
|
||||||
import { noModifierKeys } from "ol/events/condition";
|
import { never, noModifierKeys, platformModifierKeyOnly, primaryAction } from "ol/events/condition";
|
||||||
import { IGeometryType, IRectCoords } from "../../interfaces/map";
|
import { IGeometryType } from "../../interfaces/map";
|
||||||
import { uploadCoordinates } from "../../actions/map";
|
import { uploadCoordinates } from "../../actions/map";
|
||||||
import { ImageStatic } from "ol/source";
|
import { ImageStatic } from "ol/source";
|
||||||
import ImageLayer from "ol/layer/Image";
|
|
||||||
import { IFigure, ILine } from "../../interfaces/gis";
|
import { IFigure, ILine } from "../../interfaces/gis";
|
||||||
import { fromCircle, fromExtent } from "ol/geom/Polygon";
|
import { fromCircle, fromExtent } from "ol/geom/Polygon";
|
||||||
import { measureStyleFunction, modifyStyle } from "./Measure/MeasureStyles";
|
import { measureStyleFunction, modifyStyle } from "./Measure/MeasureStyles";
|
||||||
import { getCurrentTool, getMeasureClearPrevious, getMeasureType, getTipPoint, setStatusText } from "../../store/map";
|
import { getCurrentTool, getDraw, getDrawingLayerSource, getImageLayer, getMap, getMeasureClearPrevious, getMeasureDraw, getMeasureModify, getMeasureSource, getMeasureType, getOverlayLayerSource, getSnap, getTipPoint, getTranslate, PrintOrientation, setDraw, setFile, setMeasureDraw, setPolygonExtent, setRectCoords, setSnap, setTranslate } from "../../store/map";
|
||||||
import { MutableRefObject } from "react";
|
import Collection from "ol/Collection";
|
||||||
import { getSelectedCity, getSelectedYear, setSelectedRegion } from "../../store/objects";
|
import { SketchCoordType } from "ol/interaction/Draw";
|
||||||
|
|
||||||
|
const calculateAngle = (coords: [number, number][]) => {
|
||||||
|
const [start, end] = coords;
|
||||||
|
const dx = end[0] - start[0];
|
||||||
|
const dy = end[1] - start[1];
|
||||||
|
return Math.atan2(dy, dx); // Angle in radians
|
||||||
|
}
|
||||||
|
|
||||||
export function processLine(
|
export function processLine(
|
||||||
line: ILine,
|
line: ILine,
|
||||||
scaling: number,
|
scaling: number,
|
||||||
mapCenter: Coordinate,
|
mapCenter: Coordinate
|
||||||
linesLayer: MutableRefObject<VectorLayer<VectorSource>>
|
|
||||||
) {
|
) {
|
||||||
const x1 = line.x1 * scaling
|
const x1 = line.x1 * scaling
|
||||||
const y1 = line.y1 * scaling
|
const y1 = line.y1 * scaling
|
||||||
@ -37,27 +38,30 @@ export function processLine(
|
|||||||
|
|
||||||
const center = [mapCenter[0], mapCenter[1]]
|
const center = [mapCenter[0], mapCenter[1]]
|
||||||
|
|
||||||
const testCoords = [
|
const testCoords: [number, number][] = [
|
||||||
[center[0] + x1, center[1] - y1],
|
[center[0] + x1, center[1] - y1],
|
||||||
[center[0] + x2, center[1] - y2],
|
[center[0] + x2, center[1] - y2],
|
||||||
]
|
]
|
||||||
|
|
||||||
const feature = new Feature(new LineString(testCoords))
|
const geometry = new LineString(testCoords)
|
||||||
feature.setStyle(styleFunction(feature))
|
|
||||||
|
|
||||||
feature.set('type', line.type)
|
return {
|
||||||
feature.set('geometry_type', 'line')
|
type: "Feature",
|
||||||
feature.set('planning', line.planning)
|
geometry: new GeoJSON().writeGeometryObject(geometry),
|
||||||
feature.set('object_id', line.object_id)
|
properties: {
|
||||||
|
type: line.type,
|
||||||
linesLayer.current?.getSource()?.addFeature(feature)
|
geometry_type: 'line',
|
||||||
|
object_id: line.object_id,
|
||||||
|
planning: line.planning,
|
||||||
|
rotation: calculateAngle(testCoords)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function processFigure(
|
export function processFigure(
|
||||||
figure: IFigure,
|
figure: IFigure,
|
||||||
scaling: number,
|
scaling: number,
|
||||||
mapCenter: Coordinate,
|
mapCenter: Coordinate,
|
||||||
figuresLayer: MutableRefObject<VectorLayer<VectorSource>>
|
|
||||||
) {
|
) {
|
||||||
if (figure.figure_type_id == 1) {
|
if (figure.figure_type_id == 1) {
|
||||||
const width = figure.width * scaling
|
const width = figure.width * scaling
|
||||||
@ -75,13 +79,15 @@ export function processFigure(
|
|||||||
const ellipseGeom = fromCircle(circleGeom, 64)
|
const ellipseGeom = fromCircle(circleGeom, 64)
|
||||||
ellipseGeom.scale(1, height / width)
|
ellipseGeom.scale(1, height / width)
|
||||||
|
|
||||||
const feature = new Feature(ellipseGeom)
|
return {
|
||||||
|
type: "Feature",
|
||||||
feature.setStyle(firstStyleFunction(feature))
|
geometry: new GeoJSON().writeGeometryObject(ellipseGeom),
|
||||||
feature.set('type', figure.type)
|
properties: {
|
||||||
feature.set('object_id', figure.object_id)
|
type: figure.type,
|
||||||
feature.set('planning', figure.planning)
|
object_id: figure.object_id,
|
||||||
figuresLayer.current?.getSource()?.addFeature(feature)
|
planning: figure.planning
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (figure.figure_type_id == 3) {
|
if (figure.figure_type_id == 3) {
|
||||||
@ -101,15 +107,15 @@ export function processFigure(
|
|||||||
if (coords) {
|
if (coords) {
|
||||||
const polygon = new Polygon([coords])
|
const polygon = new Polygon([coords])
|
||||||
|
|
||||||
const feature = new Feature({
|
return {
|
||||||
geometry: polygon
|
type: "Feature",
|
||||||
})
|
geometry: new GeoJSON().writeGeometryObject(polygon),
|
||||||
|
properties: {
|
||||||
feature.set('object_id', figure.object_id)
|
type: figure.type,
|
||||||
feature.set('planning', figure.planning)
|
object_id: figure.object_id,
|
||||||
feature.set('type', figure.type)
|
planning: figure.planning
|
||||||
feature.setStyle(thirdStyleFunction(feature))
|
}
|
||||||
figuresLayer.current?.getSource()?.addFeature(feature)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,23 +141,179 @@ export function processFigure(
|
|||||||
const geometry1 = new Polygon([testCoords])
|
const geometry1 = new Polygon([testCoords])
|
||||||
const anchor1 = center
|
const anchor1 = center
|
||||||
geometry1.rotate(-figure.angle * Math.PI / 180, anchor1)
|
geometry1.rotate(-figure.angle * Math.PI / 180, anchor1)
|
||||||
const feature1 = new Feature(geometry1)
|
|
||||||
feature1.set('object_id', figure.object_id)
|
return {
|
||||||
feature1.set('planning', figure.planning)
|
type: "Feature",
|
||||||
feature1.set('type', figure.type)
|
geometry: new GeoJSON().writeGeometryObject(geometry1),
|
||||||
feature1.set('angle', figure.angle)
|
properties: {
|
||||||
feature1.setStyle(fourthStyleFunction(feature1))
|
type: figure.type,
|
||||||
figuresLayer.current?.getSource()?.addFeature(feature1)
|
object_id: figure.object_id,
|
||||||
|
planning: figure.planning,
|
||||||
|
angle: figure.angle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const handleImageDrop = (
|
||||||
|
event: React.DragEvent<HTMLDivElement>,
|
||||||
|
map_id: string,
|
||||||
|
) => {
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
|
||||||
|
if (!event.dataTransfer?.files) return
|
||||||
|
|
||||||
|
const files = event.dataTransfer.files
|
||||||
|
if (files.length > 0) {
|
||||||
|
const file = files[0]
|
||||||
|
setFile(map_id, file)
|
||||||
|
|
||||||
|
if (file.type.startsWith('image/')) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
|
||||||
|
reader.onload = () => {
|
||||||
|
const imageUrl = reader.result as string;
|
||||||
|
const img = new Image();
|
||||||
|
img.src = imageUrl;
|
||||||
|
img.onload = () => {
|
||||||
|
const map = getMap(map_id)
|
||||||
|
|
||||||
|
if (map) {
|
||||||
|
const center = map.getView().getCenter() || [0, 0];
|
||||||
|
|
||||||
|
const width = img.naturalWidth;
|
||||||
|
const height = img.naturalHeight;
|
||||||
|
const resolution = map.getView().getResolution() || 0;
|
||||||
|
|
||||||
|
const extent = [
|
||||||
|
center[0] - (width * resolution) / 20,
|
||||||
|
center[1] - (height * resolution) / 20,
|
||||||
|
center[0] + (width * resolution) / 20,
|
||||||
|
center[1] + (height * resolution) / 20,
|
||||||
|
];
|
||||||
|
|
||||||
|
// Create a polygon feature with the same extent as the image
|
||||||
|
const polygonFeature = new Feature({ geometry: fromExtent(extent), });
|
||||||
|
|
||||||
|
const overlayLayerSource = getOverlayLayerSource(map_id)
|
||||||
|
// Add the polygon feature to the drawing layer source
|
||||||
|
overlayLayerSource.addFeature(polygonFeature);
|
||||||
|
|
||||||
|
const imageLayer = getImageLayer(map_id)
|
||||||
|
// Set up the initial image layer with the extent
|
||||||
|
imageLayer.setSource(new ImageStatic({ url: imageUrl, imageExtent: extent, }));
|
||||||
|
|
||||||
|
updateImageSource(map_id, imageUrl, polygonFeature)
|
||||||
|
|
||||||
|
//map.current.addLayer(imageLayer.current);
|
||||||
|
|
||||||
|
// Add interactions for translation and scaling
|
||||||
|
setTranslate(map_id, new Translate({
|
||||||
|
layers: [imageLayer],
|
||||||
|
features: new Collection([polygonFeature]),
|
||||||
|
}))
|
||||||
|
|
||||||
|
const defaultStyle = new Modify({ source: overlayLayerSource })
|
||||||
|
.getOverlay()
|
||||||
|
.getStyleFunction();
|
||||||
|
|
||||||
|
const modify = new Modify({
|
||||||
|
insertVertexCondition: never,
|
||||||
|
source: overlayLayerSource,
|
||||||
|
condition: function (event) {
|
||||||
|
return primaryAction(event) && !platformModifierKeyOnly(event);
|
||||||
|
},
|
||||||
|
deleteCondition: never,
|
||||||
|
features: new Collection([polygonFeature]),
|
||||||
|
style: function (feature) {
|
||||||
|
feature.get('features').forEach(function (modifyFeature: Feature) {
|
||||||
|
const modifyGeometry = modifyFeature.get('modifyGeometry')
|
||||||
|
if (modifyGeometry) {
|
||||||
|
const point = (feature.getGeometry() as Point).getCoordinates()
|
||||||
|
let modifyPoint = modifyGeometry.point
|
||||||
|
if (!modifyPoint) {
|
||||||
|
// save the initial geometry and vertex position
|
||||||
|
modifyPoint = point;
|
||||||
|
modifyGeometry.point = modifyPoint;
|
||||||
|
modifyGeometry.geometry0 = modifyGeometry.geometry;
|
||||||
|
// get anchor and minimum radius of vertices to be used
|
||||||
|
const result = calculateCenter(modifyGeometry.geometry0);
|
||||||
|
modifyGeometry.center = result.center;
|
||||||
|
modifyGeometry.minRadius = result.minRadius;
|
||||||
|
}
|
||||||
|
const center = modifyGeometry.center;
|
||||||
|
const minRadius = modifyGeometry.minRadius;
|
||||||
|
let dx, dy;
|
||||||
|
dx = modifyPoint[0] - center[0];
|
||||||
|
dy = modifyPoint[1] - center[1];
|
||||||
|
const initialRadius = Math.sqrt(dx * dx + dy * dy);
|
||||||
|
if (initialRadius > minRadius) {
|
||||||
|
const initialAngle = Math.atan2(dy, dx);
|
||||||
|
dx = point[0] - center[0];
|
||||||
|
dy = point[1] - center[1];
|
||||||
|
const currentRadius = Math.sqrt(dx * dx + dy * dy);
|
||||||
|
if (currentRadius > 0) {
|
||||||
|
const currentAngle = Math.atan2(dy, dx);
|
||||||
|
const geometry = modifyGeometry.geometry0.clone();
|
||||||
|
geometry.scale(currentRadius / initialRadius, undefined, center);
|
||||||
|
geometry.rotate(currentAngle - initialAngle, center);
|
||||||
|
modifyGeometry.geometry = geometry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const res = map?.getView()?.getResolution()
|
||||||
|
if (typeof res === 'number' && feature && defaultStyle) {
|
||||||
|
return defaultStyle(feature, res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const translate = getTranslate(map_id)
|
||||||
|
|
||||||
|
if (translate) {
|
||||||
|
translate.on('translateend', () => updateImageSource(map_id, imageUrl, polygonFeature));
|
||||||
|
map.addInteraction(translate);
|
||||||
|
}
|
||||||
|
|
||||||
|
//modify.on('modifyend', updateImageSource);
|
||||||
|
|
||||||
|
modify.on('modifystart', function (event) {
|
||||||
|
event.features.forEach(function (feature) {
|
||||||
|
feature.set(
|
||||||
|
'modifyGeometry',
|
||||||
|
{ geometry: feature.getGeometry()?.clone() },
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modify.on('modifyend', function (event) {
|
||||||
|
event.features.forEach(function (feature) {
|
||||||
|
const modifyGeometry = feature.get('modifyGeometry');
|
||||||
|
if (modifyGeometry) {
|
||||||
|
feature.setGeometry(modifyGeometry.geometry);
|
||||||
|
feature.unset('modifyGeometry', true);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
updateImageSource(map_id, imageUrl, polygonFeature)
|
||||||
|
})
|
||||||
|
|
||||||
|
map.addInteraction(modify);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to update the image layer with a new source when extent changes
|
// Function to update the image layer with a new source when extent changes
|
||||||
export const updateImageSource = (
|
export const updateImageSource = (
|
||||||
|
map_id: string,
|
||||||
imageUrl: string,
|
imageUrl: string,
|
||||||
imageLayer: React.MutableRefObject<ImageLayer<ImageStatic>>,
|
polygonFeature: Feature<Polygon>
|
||||||
polygonFeature: Feature<Polygon>,
|
|
||||||
setPolygonExtent: (value: React.SetStateAction<Extent | undefined>) => void,
|
|
||||||
setRectCoords: React.Dispatch<React.SetStateAction<IRectCoords | undefined>>
|
|
||||||
) => {
|
) => {
|
||||||
const newExtent = polygonFeature.getGeometry()?.getExtent();
|
const newExtent = polygonFeature.getGeometry()?.getExtent();
|
||||||
|
|
||||||
@ -160,14 +322,14 @@ export const updateImageSource = (
|
|||||||
const topRight = polygonFeature.getGeometry()?.getCoordinates()[0][2]
|
const topRight = polygonFeature.getGeometry()?.getCoordinates()[0][2]
|
||||||
const bottomRight = polygonFeature.getGeometry()?.getCoordinates()[0][3]
|
const bottomRight = polygonFeature.getGeometry()?.getCoordinates()[0][3]
|
||||||
|
|
||||||
setRectCoords({
|
setRectCoords(map_id, {
|
||||||
bl: bottomLeft,
|
bl: bottomLeft,
|
||||||
tl: topLeft,
|
tl: topLeft,
|
||||||
tr: topRight,
|
tr: topRight,
|
||||||
br: bottomRight
|
br: bottomRight
|
||||||
})
|
})
|
||||||
|
|
||||||
setPolygonExtent(newExtent)
|
setPolygonExtent(map_id, newExtent)
|
||||||
|
|
||||||
if (newExtent && bottomLeft && bottomRight && topRight && topLeft) {
|
if (newExtent && bottomLeft && bottomRight && topRight && topLeft) {
|
||||||
const originalExtent = calculateExtent(bottomLeft, topLeft, topRight, bottomRight)
|
const originalExtent = calculateExtent(bottomLeft, topLeft, topRight, bottomRight)
|
||||||
@ -175,55 +337,94 @@ export const updateImageSource = (
|
|||||||
url: imageUrl,
|
url: imageUrl,
|
||||||
imageExtent: originalExtent,
|
imageExtent: originalExtent,
|
||||||
projection: rotateProjection('EPSG:3857', calculateRotationAngle(bottomLeft, bottomRight), originalExtent)
|
projection: rotateProjection('EPSG:3857', calculateRotationAngle(bottomLeft, bottomRight), originalExtent)
|
||||||
});
|
})
|
||||||
imageLayer.current.setSource(newImageSource);
|
getImageLayer(map_id).setSource(newImageSource)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const fixedAspectRatioBox = (
|
||||||
|
coordinates: SketchCoordType,
|
||||||
|
geometry: SimpleGeometry | undefined,
|
||||||
|
orientation?: PrintOrientation
|
||||||
|
): SimpleGeometry => {
|
||||||
|
if (!Array.isArray(coordinates) || coordinates.length < 2) {
|
||||||
|
return geometry ?? new Polygon([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [start, end] = coordinates as Coordinate[];
|
||||||
|
const minX = start[0];
|
||||||
|
const minY = start[1];
|
||||||
|
const maxX = end[0];
|
||||||
|
|
||||||
|
const width = maxX - minX;
|
||||||
|
const height = orientation === 'horizontal' ? Math.abs(width / Math.sqrt(2)) : Math.abs(width * Math.sqrt(2)); // Maintain 1:√2 ratio
|
||||||
|
|
||||||
|
const maxY = end[1] > minY ? minY + height : minY - height;
|
||||||
|
|
||||||
|
const boxCoords: Coordinate[][] = [[
|
||||||
|
[minX, minY],
|
||||||
|
[maxX, minY],
|
||||||
|
[maxX, maxY],
|
||||||
|
[minX, maxY],
|
||||||
|
[minX, minY], // Close the polygon
|
||||||
|
]];
|
||||||
|
|
||||||
|
if (geometry) {
|
||||||
|
geometry.setCoordinates(boxCoords);
|
||||||
|
return geometry;
|
||||||
|
}
|
||||||
|
return new Polygon(boxCoords);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export const addInteractions = (
|
export const addInteractions = (
|
||||||
drawingLayerSource: React.MutableRefObject<VectorSource<Feature<Geometry>>>,
|
map_id: string
|
||||||
translate: React.MutableRefObject<Translate | null>,
|
|
||||||
draw: React.MutableRefObject<Draw | null>,
|
|
||||||
map: React.MutableRefObject<Map | null>,
|
|
||||||
snap: React.MutableRefObject<Snap | null>,
|
|
||||||
measureDraw: React.MutableRefObject<Draw | null>,
|
|
||||||
measureSource: React.MutableRefObject<VectorSource<Feature<Geometry>>>,
|
|
||||||
measureModify: React.MutableRefObject<Modify>,
|
|
||||||
) => {
|
) => {
|
||||||
const currentTool = getCurrentTool()
|
console.log("Adding interactions")
|
||||||
const clearPrevious = getMeasureClearPrevious()
|
const currentTool = getCurrentTool(map_id)
|
||||||
const measureType = getMeasureType()
|
const clearPrevious = getMeasureClearPrevious(map_id)
|
||||||
const tipPoint = getTipPoint()
|
const measureType = getMeasureType(map_id)
|
||||||
|
const tipPoint = getTipPoint(map_id)
|
||||||
|
const map = getMap(map_id)
|
||||||
|
const measureModify = getMeasureModify(map_id)
|
||||||
|
|
||||||
if (currentTool !== 'Measure' && currentTool !== 'Mover' && currentTool !== 'Edit') {
|
if (currentTool !== 'Measure' && currentTool !== 'Mover' && currentTool !== 'Edit') {
|
||||||
draw.current = new Draw({
|
setDraw(map_id, new Draw({
|
||||||
source: drawingLayerSource.current,
|
source: getDrawingLayerSource(map_id),
|
||||||
type: currentTool as Type,
|
type: currentTool as Type,
|
||||||
condition: noModifierKeys
|
condition: noModifierKeys
|
||||||
})
|
}))
|
||||||
|
|
||||||
draw.current.on('drawend', function (s) {
|
const draw = getDraw(map_id)
|
||||||
console.log(s.feature.getGeometry()?.getType())
|
|
||||||
let type: IGeometryType = 'POLYGON'
|
|
||||||
|
|
||||||
switch (s.feature.getGeometry()?.getType()) {
|
if (draw) {
|
||||||
case 'LineString':
|
draw.on('drawend', function (s) {
|
||||||
type = 'LINE'
|
console.log(s.feature.getGeometry()?.getType())
|
||||||
break
|
let type: IGeometryType = 'POLYGON'
|
||||||
case 'Polygon':
|
|
||||||
type = 'POLYGON'
|
switch (s.feature.getGeometry()?.getType()) {
|
||||||
break
|
case 'LineString':
|
||||||
default:
|
type = 'LINE'
|
||||||
type = 'POLYGON'
|
break
|
||||||
break
|
case 'Polygon':
|
||||||
|
type = 'POLYGON'
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
type = 'POLYGON'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
const coordinates = (s.feature.getGeometry() as SimpleGeometry).getCoordinates() as Coordinate[]
|
||||||
|
uploadCoordinates(coordinates, type)
|
||||||
|
})
|
||||||
|
|
||||||
|
map?.addInteraction(draw)
|
||||||
|
setSnap(map_id, new Snap({ source: getDrawingLayerSource(map_id) }))
|
||||||
|
|
||||||
|
const snap = getSnap(map_id)
|
||||||
|
if (snap) {
|
||||||
|
map?.addInteraction(snap)
|
||||||
}
|
}
|
||||||
const coordinates = (s.feature.getGeometry() as SimpleGeometry).getCoordinates() as Coordinate[]
|
}
|
||||||
uploadCoordinates(coordinates, type)
|
|
||||||
})
|
|
||||||
|
|
||||||
map?.current?.addInteraction(draw.current)
|
|
||||||
snap.current = new Snap({ source: drawingLayerSource.current })
|
|
||||||
map?.current?.addInteraction(snap.current)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentTool == 'Measure') {
|
if (currentTool == 'Measure') {
|
||||||
@ -234,35 +435,45 @@ export const addInteractions = (
|
|||||||
const idleTip = 'Кликните, чтобы начать измерение';
|
const idleTip = 'Кликните, чтобы начать измерение';
|
||||||
let tip = idleTip;
|
let tip = idleTip;
|
||||||
|
|
||||||
measureDraw.current = new Draw({
|
setMeasureDraw(map_id, new Draw({
|
||||||
source: measureSource.current,
|
source: getMeasureSource(map_id),
|
||||||
type: drawType,
|
type: drawType,
|
||||||
style: function (feature) {
|
style: function (feature) {
|
||||||
return measureStyleFunction(feature, drawType, tip);
|
return measureStyleFunction(map_id, feature, drawType, tip);
|
||||||
},
|
},
|
||||||
});
|
}))
|
||||||
measureDraw.current.on('drawstart', function () {
|
|
||||||
if (clearPrevious) {
|
const measureDraw = getMeasureDraw(map_id)
|
||||||
measureSource.current.clear();
|
|
||||||
}
|
if (measureDraw) {
|
||||||
measureModify.current.setActive(false);
|
measureDraw.on('drawstart', function () {
|
||||||
tip = activeTip;
|
if (clearPrevious) {
|
||||||
});
|
getMeasureSource(map_id).clear();
|
||||||
measureDraw.current.on('drawend', function () {
|
}
|
||||||
modifyStyle.setGeometry(tipPoint as Geometry);
|
measureModify.setActive(false);
|
||||||
measureModify.current.setActive(true);
|
tip = activeTip;
|
||||||
map.current?.once('pointermove', function () {
|
|
||||||
modifyStyle.setGeometry('');
|
|
||||||
});
|
});
|
||||||
tip = idleTip;
|
measureDraw.on('drawend', function () {
|
||||||
});
|
modifyStyle.setGeometry(tipPoint as Geometry);
|
||||||
measureModify.current.setActive(true);
|
measureModify.setActive(true);
|
||||||
map.current?.addInteraction(measureDraw.current);
|
map?.once('pointermove', function () {
|
||||||
|
modifyStyle.setGeometry('');
|
||||||
|
});
|
||||||
|
tip = idleTip;
|
||||||
|
});
|
||||||
|
measureModify.setActive(true)
|
||||||
|
|
||||||
|
map?.addInteraction(measureDraw)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentTool == 'Mover') {
|
if (currentTool == 'Mover') {
|
||||||
translate.current = new Translate()
|
setTranslate(map_id, new Translate())
|
||||||
map?.current?.addInteraction(translate.current)
|
|
||||||
|
const translate = getTranslate(map_id)
|
||||||
|
if (translate) {
|
||||||
|
map?.addInteraction(translate)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentTool == 'Edit') {
|
if (currentTool == 'Edit') {
|
||||||
@ -271,91 +482,12 @@ export const addInteractions = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function regionsInit(
|
export const zoomToFeature = (map_id: string, feature: Feature) => {
|
||||||
map: React.MutableRefObject<Map | null>,
|
|
||||||
selectedRegion: React.MutableRefObject<Feature<Geometry> | null>,
|
|
||||||
regionsLayer: React.MutableRefObject<VectorImageLayer<Feature<Geometry>, VectorSource<Feature<Geometry>>>>,
|
|
||||||
) {
|
|
||||||
regionsLayer.current.once('change', function () {
|
|
||||||
if (getSelectedCity() === null || getSelectedYear() === null) {
|
|
||||||
const extent = regionsLayer.current.getSource()?.getExtent()
|
|
||||||
|
|
||||||
if (extent && !extent?.every(val => Math.abs(val) === Infinity)) {
|
|
||||||
map.current?.getView().fit(fromExtent(extent) as SimpleGeometry, { duration: 500, maxZoom: 18, padding: [60, 60, 60, 60] })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
map.current?.on('click', function (e) {
|
|
||||||
if (selectedRegion.current !== null) {
|
|
||||||
selectedRegion.current = null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (map.current) {
|
|
||||||
map.current.forEachFeatureAtPixel(e.pixel, function (feature, layer) {
|
|
||||||
if (layer === regionsLayer.current) {
|
|
||||||
selectedRegion.current = feature as Feature
|
|
||||||
// Zoom to the selected feature
|
|
||||||
zoomToFeature(map, selectedRegion.current)
|
|
||||||
|
|
||||||
if (feature.get('id')) {
|
|
||||||
setSelectedRegion(feature.get('id'))
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
} else return false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Show current selected region
|
|
||||||
map.current?.on('pointermove', function (e) {
|
|
||||||
if (selectedRegion.current !== null) {
|
|
||||||
selectedRegion.current.setStyle(undefined)
|
|
||||||
selectedRegion.current = null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (map.current) {
|
|
||||||
map.current.forEachFeatureAtPixel(e.pixel, function (feature, layer) {
|
|
||||||
if (layer === regionsLayer.current) {
|
|
||||||
selectedRegion.current = feature as Feature
|
|
||||||
selectedRegion.current.setStyle(selectStyle)
|
|
||||||
|
|
||||||
if (feature.get('district')) {
|
|
||||||
setStatusText(feature.get('district'))
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
} else return false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Hide regions layer when fully visible
|
|
||||||
map.current?.on('moveend', function () {
|
|
||||||
const viewExtent = map.current?.getView().calculateExtent(map.current.getSize())
|
|
||||||
const features = regionsLayer.current.getSource()?.getFeatures()
|
|
||||||
|
|
||||||
let isViewCovered = false
|
|
||||||
|
|
||||||
features?.forEach((feature: Feature) => {
|
|
||||||
const featureExtent = feature?.getGeometry()?.getExtent()
|
|
||||||
if (viewExtent && featureExtent) {
|
|
||||||
if (containsExtent(featureExtent, viewExtent)) {
|
|
||||||
isViewCovered = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
regionsLayer.current.setVisible(!isViewCovered)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const zoomToFeature = (map: React.MutableRefObject<Map | null>, feature: Feature) => {
|
|
||||||
const geometry = feature.getGeometry()
|
const geometry = feature.getGeometry()
|
||||||
const extent = geometry?.getExtent()
|
const extent = geometry?.getExtent()
|
||||||
|
|
||||||
if (map.current && extent) {
|
if (getMap(map_id) && extent) {
|
||||||
map.current.getView().fit(extent, {
|
getMap(map_id)?.getView().fit(extent, {
|
||||||
duration: 300,
|
duration: 300,
|
||||||
maxZoom: 19,
|
maxZoom: 19,
|
||||||
})
|
})
|
||||||
@ -363,8 +495,8 @@ const zoomToFeature = (map: React.MutableRefObject<Map | null>, feature: Feature
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Function to save features to localStorage
|
// Function to save features to localStorage
|
||||||
export const saveFeatures = (layerRef: MutableRefObject<VectorLayer<VectorSource> | null>) => {
|
export const saveFeatures = (map_id: string) => {
|
||||||
const features = layerRef.current?.getSource()?.getFeatures()
|
const features = getDrawingLayerSource(map_id).getFeatures()
|
||||||
if (features && features.length > 0) {
|
if (features && features.length > 0) {
|
||||||
const geoJSON = new GeoJSON()
|
const geoJSON = new GeoJSON()
|
||||||
const featuresJSON = geoJSON.writeFeatures(features)
|
const featuresJSON = geoJSON.writeFeatures(features)
|
||||||
@ -373,14 +505,14 @@ export const saveFeatures = (layerRef: MutableRefObject<VectorLayer<VectorSource
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Function to load features from localStorage
|
// Function to load features from localStorage
|
||||||
export const loadFeatures = (layerSource: React.MutableRefObject<VectorSource<Feature<Geometry>>>) => {
|
export const loadFeatures = (map_id: string) => {
|
||||||
const savedFeatures = localStorage.getItem('savedFeatures')
|
const savedFeatures = localStorage.getItem('savedFeatures')
|
||||||
if (savedFeatures) {
|
if (savedFeatures) {
|
||||||
const geoJSON = new GeoJSON()
|
const geoJSON = new GeoJSON()
|
||||||
const features = geoJSON.readFeatures(savedFeatures, {
|
const features = geoJSON.readFeatures(savedFeatures, {
|
||||||
featureProjection: 'EPSG:4326', // Ensure the projection is correct
|
featureProjection: 'EPSG:4326', // Ensure the projection is correct
|
||||||
})
|
})
|
||||||
layerSource.current?.addFeatures(features) // Add features to the vector source
|
getDrawingLayerSource(map_id).addFeatures(features)
|
||||||
//drawingLayer.current?.getSource()?.changed()
|
//drawingLayer.current?.getSource()?.changed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -531,6 +663,25 @@ function getGridCellPosition(x: number, y: number, extent: Extent, zoom: number)
|
|||||||
return { tileX, tileY };
|
return { tileX, tileY };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function calculateTransformations(alignPoints: Coordinate[]) {
|
||||||
|
const [P1, P2, P3, P4] = alignPoints;
|
||||||
|
|
||||||
|
// Translation vector (move P1 to P3)
|
||||||
|
const translation = [P3[0] - P1[0], P3[1] - P1[1]];
|
||||||
|
|
||||||
|
// Scaling factor (distance between P3 and P4 divided by P1 and P2)
|
||||||
|
const distanceLayer = Math.sqrt((P2[0] - P1[0]) ** 2 + (P2[1] - P1[1]) ** 2);
|
||||||
|
const distanceMap = Math.sqrt((P4[0] - P3[0]) ** 2 + (P4[1] - P3[1]) ** 2);
|
||||||
|
const scale = distanceMap / distanceLayer;
|
||||||
|
|
||||||
|
// Rotation angle (difference in angles between the two lines)
|
||||||
|
const angleLayer = Math.atan2(P2[1] - P1[1], P2[0] - P1[0]);
|
||||||
|
const angleMap = Math.atan2(P4[1] - P3[1], P4[0] - P3[0]);
|
||||||
|
const rotation = angleMap - angleLayer;
|
||||||
|
|
||||||
|
return { translation, scale, rotation };
|
||||||
|
}
|
||||||
|
|
||||||
function calculateCenter(geometry: SimpleGeometry) {
|
function calculateCenter(geometry: SimpleGeometry) {
|
||||||
let center, coordinates, minRadius;
|
let center, coordinates, minRadius;
|
||||||
const type = geometry.getType();
|
const type = geometry.getType();
|
||||||
@ -574,8 +725,41 @@ function calculateCenter(geometry: SimpleGeometry) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function applyTransformations(
|
||||||
|
layer: VectorLayer,
|
||||||
|
transformations: {
|
||||||
|
translation: number[];
|
||||||
|
scale: number;
|
||||||
|
rotation: number;
|
||||||
|
},
|
||||||
|
origin: Coordinate
|
||||||
|
) {
|
||||||
|
const { translation, scale, rotation } = transformations;
|
||||||
|
|
||||||
|
const source = layer.getSource();
|
||||||
|
if (!source) return;
|
||||||
|
|
||||||
|
source.getFeatures().forEach((feature) => {
|
||||||
|
const geometry = feature.getGeometry();
|
||||||
|
|
||||||
|
if (geometry) {
|
||||||
|
// Translate
|
||||||
|
geometry.translate(translation[0], translation[1]);
|
||||||
|
|
||||||
|
// Scale (around the origin)
|
||||||
|
geometry.scale(scale, scale, origin);
|
||||||
|
|
||||||
|
// Rotate (around the origin)
|
||||||
|
geometry.rotate(rotation, origin);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("Transformations applied to figuresLayer");
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
rotateProjection,
|
rotateProjection,
|
||||||
|
calculateTransformations,
|
||||||
calculateRotationAngle,
|
calculateRotationAngle,
|
||||||
calculateExtent,
|
calculateExtent,
|
||||||
calculateCentroid,
|
calculateCentroid,
|
||||||
@ -583,5 +767,6 @@ export {
|
|||||||
normalize,
|
normalize,
|
||||||
getTileIndex,
|
getTileIndex,
|
||||||
getGridCellPosition,
|
getGridCellPosition,
|
||||||
calculateCenter
|
calculateCenter,
|
||||||
|
applyTransformations
|
||||||
}
|
}
|
||||||
@ -21,7 +21,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface ViewerProps {
|
interface ViewerProps {
|
||||||
url: string
|
url: string | ArrayBuffer | Blob
|
||||||
}
|
}
|
||||||
|
|
||||||
function PdfViewer({
|
function PdfViewer({
|
||||||
@ -82,7 +82,7 @@ function DocxViewer({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function ExcelViewer({
|
export function ExcelViewer({
|
||||||
url
|
url
|
||||||
}: ViewerProps) {
|
}: ViewerProps) {
|
||||||
const previewContainerRef = useRef(null)
|
const previewContainerRef = useRef(null)
|
||||||
@ -120,7 +120,7 @@ function ImageViewer({
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%'
|
height: '100%'
|
||||||
}}>
|
}}>
|
||||||
<img alt='image-preview' src={url} style={{
|
<img alt='image-preview' src={url as string} style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
maxWidth: '100%',
|
maxWidth: '100%',
|
||||||
maxHeight: '100%'
|
maxHeight: '100%'
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import { IconBuildingFactory2, IconComponents, IconDeviceDesktopAnalytics, IconFiles, IconHome, IconLogin, IconLogin2, IconMap, IconPassword, IconReport, IconServer, IconSettings, IconShield, IconTable, IconUsers } from "@tabler/icons-react";
|
import { IconBuildingFactory2, IconComponents, IconDeviceDesktopAnalytics, IconFiles, IconFlame, IconHome, IconLogin, IconLogin2, IconMap, IconPassword, IconReport, icons, IconServer, IconSettings, IconShield, IconUsers } from "@tabler/icons-react";
|
||||||
import SignIn from "../pages/auth/SignIn";
|
import SignIn from "../pages/auth/SignIn";
|
||||||
import SignUp from "../pages/auth/SignUp";
|
import SignUp from "../pages/auth/SignUp";
|
||||||
import PasswordReset from "../pages/auth/PasswordReset";
|
import PasswordReset from "../pages/auth/PasswordReset";
|
||||||
import TableTest from "../pages/TableTest";
|
|
||||||
import ComponentTest from "../pages/ComponentTest";
|
import ComponentTest from "../pages/ComponentTest";
|
||||||
import MonitorPage from "../pages/MonitorPage";
|
import MonitorPage from "../pages/MonitorPage";
|
||||||
import Settings from "../pages/Settings";
|
import Settings from "../pages/Settings";
|
||||||
@ -14,6 +13,10 @@ import Reports from "../pages/Reports";
|
|||||||
import Servers from "../pages/Servers";
|
import Servers from "../pages/Servers";
|
||||||
import Boilers from "../pages/Boilers";
|
import Boilers from "../pages/Boilers";
|
||||||
import MapTest from "../pages/MapTest";
|
import MapTest from "../pages/MapTest";
|
||||||
|
import PrintReport from "../pages/PrintReport";
|
||||||
|
import DBManager from "../pages/DBManager";
|
||||||
|
import MapLineTest from "../components/map/MapLineTest";
|
||||||
|
import FuelPage from "../pages/Fuel";
|
||||||
|
|
||||||
// Определение страниц с путями и компонентом для рендера
|
// Определение страниц с путями и компонентом для рендера
|
||||||
|
|
||||||
@ -126,6 +129,15 @@ const pages = [
|
|||||||
dashboard: true,
|
dashboard: true,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: "Map line test",
|
||||||
|
path: "/map-line-test",
|
||||||
|
icon: <IconMap />,
|
||||||
|
component: <MapLineTest />,
|
||||||
|
drawer: true,
|
||||||
|
dashboard: true,
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: "Монитор",
|
label: "Монитор",
|
||||||
path: "/monitor",
|
path: "/monitor",
|
||||||
@ -135,15 +147,6 @@ const pages = [
|
|||||||
dashboard: true,
|
dashboard: true,
|
||||||
enabled: false,
|
enabled: false,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: "Table test",
|
|
||||||
path: "/table-test",
|
|
||||||
icon: <IconTable />,
|
|
||||||
component: <TableTest />,
|
|
||||||
drawer: true,
|
|
||||||
dashboard: true,
|
|
||||||
enabled: false,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: "Component test",
|
label: "Component test",
|
||||||
path: "/component-test",
|
path: "/component-test",
|
||||||
@ -153,6 +156,33 @@ const pages = [
|
|||||||
dashboard: true,
|
dashboard: true,
|
||||||
enabled: false,
|
enabled: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: "Print report test",
|
||||||
|
path: "/print-report-test",
|
||||||
|
icon: <IconComponents />,
|
||||||
|
component: <PrintReport />,
|
||||||
|
drawer: true,
|
||||||
|
dashboard: true,
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Тест БД",
|
||||||
|
path: "/db-manager",
|
||||||
|
icon: <IconComponents />,
|
||||||
|
component: <DBManager />,
|
||||||
|
drawer: true,
|
||||||
|
dashboard: true,
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Fuel',
|
||||||
|
path: '/fuel',
|
||||||
|
icon: <IconFlame />,
|
||||||
|
component: <FuelPage />,
|
||||||
|
drawer: true,
|
||||||
|
dashboard: true,
|
||||||
|
enabled: true
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|||||||
48
client/src/constants/map.ts
Normal file
48
client/src/constants/map.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
export const schemas = [
|
||||||
|
'2018',
|
||||||
|
'2019',
|
||||||
|
'2020',
|
||||||
|
'2021',
|
||||||
|
'2022',
|
||||||
|
'2023',
|
||||||
|
'2024',
|
||||||
|
]
|
||||||
|
|
||||||
|
export const scaleOptions = [
|
||||||
|
{
|
||||||
|
label: '1:500000',
|
||||||
|
value: '500'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '1:100000',
|
||||||
|
value: '250'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '1:50000',
|
||||||
|
value: '50'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '1:25000',
|
||||||
|
value: '25'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '1:10000',
|
||||||
|
value: '10'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export const satMapsProviders = [
|
||||||
|
{ label: 'Google', value: 'google' },
|
||||||
|
{ label: 'Яндекс', value: 'yandex' },
|
||||||
|
{ label: 'Подложка', value: 'custom' },
|
||||||
|
{ label: 'Static', value: 'static' }
|
||||||
|
]
|
||||||
|
|
||||||
|
export const printDimensions = {
|
||||||
|
a0: [1189, 841],
|
||||||
|
a1: [841, 594],
|
||||||
|
a2: [594, 420],
|
||||||
|
a3: [420, 297],
|
||||||
|
a4: [297, 210],
|
||||||
|
a5: [210, 148],
|
||||||
|
}
|
||||||
29
client/src/dto/fuel/fuel.dto.ts
Normal file
29
client/src/dto/fuel/fuel.dto.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
export class FuelExpenseDto {
|
||||||
|
id_boiler?: string
|
||||||
|
id_fuel?: number
|
||||||
|
date?: Date
|
||||||
|
value?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FuelExpenseDtoHeaders = {
|
||||||
|
id_boiler: 'Boiler ID',
|
||||||
|
id_fuel: 'Fuel ID',
|
||||||
|
date: 'Date',
|
||||||
|
value: 'Value',
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FuelLimitDto {
|
||||||
|
id_boiler?: string
|
||||||
|
id_fuel?: number
|
||||||
|
month?: Date
|
||||||
|
year?: number
|
||||||
|
value?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FuelLimitDtoHeaders = {
|
||||||
|
id_boiler: 'Boiler ID',
|
||||||
|
id_fuel: 'Fuel ID',
|
||||||
|
month: 'Month',
|
||||||
|
year: 'Year',
|
||||||
|
value: 'Value'
|
||||||
|
}
|
||||||
27
client/src/http/axiosInstanceNest.ts
Normal file
27
client/src/http/axiosInstanceNest.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import axios, { ResponseType } from 'axios';
|
||||||
|
import { useAuthStore } from '../store/auth';
|
||||||
|
|
||||||
|
const axiosInstance = axios.create();
|
||||||
|
|
||||||
|
axiosInstance.interceptors.request.use(
|
||||||
|
(config) => {
|
||||||
|
const token = useAuthStore.getState().token;
|
||||||
|
if (token) {
|
||||||
|
config.headers['Authorization'] = `Bearer ${token}`;
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const fetcher = (url: string, baseURL?: string, responseType?: ResponseType) => axiosInstance.get(url, {
|
||||||
|
baseURL: baseURL || import.meta.env.VITE_API_NEST_URL,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
},
|
||||||
|
responseType: responseType ? responseType : "json"
|
||||||
|
}).then(res => res.data)
|
||||||
|
|
||||||
|
export default axiosInstance;
|
||||||
@ -1,3 +1,10 @@
|
|||||||
|
import { Point } from "ol/geom";
|
||||||
|
import { ToolType } from "../types/tools";
|
||||||
|
import { SatelliteMapsProvider } from "./map";
|
||||||
|
import Map from "ol/Map";
|
||||||
|
import { Coordinate } from "ol/coordinate";
|
||||||
|
import { Mode } from "../store/map";
|
||||||
|
|
||||||
export interface IFigure {
|
export interface IFigure {
|
||||||
object_id: string,
|
object_id: string,
|
||||||
figure_type_id: number,
|
figure_type_id: number,
|
||||||
@ -33,4 +40,58 @@ export interface ILine {
|
|||||||
year: number,
|
year: number,
|
||||||
type: number,
|
type: number,
|
||||||
planning: boolean
|
planning: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICitySettings {
|
||||||
|
city_id: number;
|
||||||
|
image_width: number;
|
||||||
|
image_height: number;
|
||||||
|
scale: number;
|
||||||
|
offset_x: number;
|
||||||
|
offset_y: number;
|
||||||
|
rotation: number;
|
||||||
|
image_scale: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TypeRole {
|
||||||
|
id: number;
|
||||||
|
sname: string;
|
||||||
|
r: number | null;
|
||||||
|
g: number | null;
|
||||||
|
b: number | null;
|
||||||
|
object_type_id: number;
|
||||||
|
object_role_id: number;
|
||||||
|
parent_type_id: string | null;
|
||||||
|
owner_role_ids: string | null;
|
||||||
|
necessary_params_ids: string | null;
|
||||||
|
vis_params_ids: string | null;
|
||||||
|
read_only_params_ids: string | null;
|
||||||
|
inactive_r: number | null;
|
||||||
|
inactive_g: number | null;
|
||||||
|
inactive_b: number | null;
|
||||||
|
color_group: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateMapState {
|
||||||
|
currentTool: ToolType;
|
||||||
|
measureType: "LineString" | "Polygon";
|
||||||
|
measureShowSegments: boolean;
|
||||||
|
measureClearPrevious: boolean;
|
||||||
|
tipPoint: Point | null;
|
||||||
|
map: Map | null;
|
||||||
|
currentZ: number | undefined;
|
||||||
|
currentX: number | undefined;
|
||||||
|
currentY: number | undefined;
|
||||||
|
currentCoordinate: Coordinate | null;
|
||||||
|
statusText: string;
|
||||||
|
satMapsProvider: SatelliteMapsProvider;
|
||||||
|
selectedObjectType: number | null;
|
||||||
|
alignMode: boolean;
|
||||||
|
mode: Mode;
|
||||||
|
typeRoles: TypeRole[] | null;
|
||||||
|
setCurrentCoordinate: (currentCoordinate: Coordinate | null) => void;
|
||||||
|
setCurrentZ: (currentZ: number | undefined) => void;
|
||||||
|
setCurrentX: (currentX: number | undefined) => void;
|
||||||
|
setCurrentY: (currentY: number | undefined) => void;
|
||||||
|
setStatusText: (statusText: string) => void;
|
||||||
}
|
}
|
||||||
@ -9,7 +9,7 @@ import { pages } from '../constants/app';
|
|||||||
|
|
||||||
function DashboardLayout() {
|
function DashboardLayout() {
|
||||||
const [mobileOpened, { toggle: toggleMobile }] = useDisclosure()
|
const [mobileOpened, { toggle: toggleMobile }] = useDisclosure()
|
||||||
const [desktopOpened, { toggle: toggleDesktop }] = useDisclosure(true)
|
const [desktopOpened, { toggle: toggleDesktop }] = useDisclosure(false)
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
|
||||||
const getPageTitle = () => {
|
const getPageTitle = () => {
|
||||||
@ -50,7 +50,7 @@ function DashboardLayout() {
|
|||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<Group w='auto'>
|
<Group w='auto'>
|
||||||
{getPageTitle()}
|
<Text fw='600'>{getPageTitle()}</Text>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<Group id='header-portal' w='auto' ml='auto'>
|
<Group id='header-portal' w='auto' ml='auto'>
|
||||||
@ -123,14 +123,20 @@ function DashboardLayout() {
|
|||||||
leftSection={item.icon}
|
leftSection={item.icon}
|
||||||
active={location.pathname === item.path}
|
active={location.pathname === item.path}
|
||||||
style={{ textWrap: 'nowrap' }}
|
style={{ textWrap: 'nowrap' }}
|
||||||
|
// styles={(theme, { active }) => ({
|
||||||
|
// root: {
|
||||||
|
// color: active ? theme.colors.blue[6] : theme.colors.dark[5],
|
||||||
|
// fontWeight: active ? "bold" : "normal",
|
||||||
|
// },
|
||||||
|
// leftSection: {
|
||||||
|
// color: active ? theme.colors.blue[6] : theme.colors.dark[5], // Icon color
|
||||||
|
// }
|
||||||
|
// })}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</AppShell.Navbar>
|
</AppShell.Navbar>
|
||||||
<AppShell.Main>
|
<AppShell.Main>
|
||||||
<Flex w={{
|
<Flex bg={colorScheme === 'dark' ? undefined : '#E8E8E8'} w={{ sm: desktopOpened ? 'calc(100% - 200px)' : 'calc(100% - 50px)', base: '100%' }} h={'calc(100% - 60px)'} style={{ transition: "width 0.2s ease" }} pos={'fixed'}>
|
||||||
sm: desktopOpened ? 'calc(100% - 200px)' : 'calc(100% - 50px)',
|
|
||||||
base: '100%'
|
|
||||||
}} h={'calc(100% - 60px)'} style={{ transition: "width 0.2s ease" }} pos={'fixed'}>
|
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</Flex>
|
</Flex>
|
||||||
</AppShell.Main>
|
</AppShell.Main>
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
// Layout for fullscreen pages
|
|
||||||
|
|
||||||
import { Flex } from "@mantine/core";
|
import { Flex } from "@mantine/core";
|
||||||
import { Outlet } from "react-router-dom";
|
import { Outlet } from "react-router-dom";
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
import "@fontsource/inter";
|
import "@fontsource/inter";
|
||||||
import '@mantine/core/styles.css';
|
import '@mantine/core/styles.css';
|
||||||
|
import '@mantine/dates/styles.css';
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom/client'
|
import ReactDOM from 'react-dom/client'
|
||||||
import App from './App.tsx'
|
import App from './App.tsx'
|
||||||
import './index.css'
|
import './index.css'
|
||||||
import { createTheme, DEFAULT_THEME, MantineProvider, mergeMantineTheme } from '@mantine/core';
|
import { createTheme, DEFAULT_THEME, MantineProvider, mergeMantineTheme } from '@mantine/core';
|
||||||
|
import 'dayjs/locale/ru';
|
||||||
|
import { DatesProvider } from "@mantine/dates";
|
||||||
|
|
||||||
const overrides = createTheme({
|
const overrides = createTheme({
|
||||||
// Set this color to `--mantine-color-body` CSS variable
|
// Set this color to `--mantine-color-body` CSS variable
|
||||||
@ -19,7 +22,9 @@ const theme = mergeMantineTheme(DEFAULT_THEME, overrides);
|
|||||||
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<MantineProvider theme={theme}>
|
<MantineProvider theme={theme}>
|
||||||
<App />
|
<DatesProvider settings={{ locale: 'ru' }}>
|
||||||
|
<App />
|
||||||
|
</DatesProvider>
|
||||||
</MantineProvider>
|
</MantineProvider>
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
)
|
)
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useBoilers } from '../hooks/swrHooks'
|
import { useBoilers } from '../hooks/swrHooks'
|
||||||
import { Badge, ScrollAreaAutosize, Table, Text } from '@mantine/core'
|
import { Stack, Text } from '@mantine/core'
|
||||||
import { IBoiler } from '../interfaces/fuel'
|
import CustomTable from '../components/CustomTable'
|
||||||
|
|
||||||
function Boilers() {
|
function Boilers() {
|
||||||
const [boilersPage, setBoilersPage] = useState(1)
|
const [boilersPage, setBoilersPage] = useState(1)
|
||||||
@ -24,21 +24,43 @@ function Boilers() {
|
|||||||
setBoilerSearch("")
|
setBoilerSearch("")
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const boilersColumns = [
|
|
||||||
{ field: 'id_object', headerName: 'ID', type: "number" },
|
|
||||||
{ field: 'boiler_name', headerName: 'Название', type: "string", flex: 1 },
|
|
||||||
{ field: 'boiler_code', headerName: 'Код', type: "string", flex: 1 },
|
|
||||||
{ field: 'id_city', headerName: 'Город', type: "string", flex: 1 },
|
|
||||||
{ field: 'activity', headerName: 'Активен', type: "boolean", flex: 1 },
|
|
||||||
]
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollAreaAutosize w={'100%'} h={'100%'} p='sm'>
|
<Stack w={'100%'} h={'100%'} p='sm'>
|
||||||
<Text size="xl" fw={600}>
|
<Text size="xl" fw={600}>
|
||||||
Котельные
|
Котельные
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
{boilers &&
|
{boilers &&
|
||||||
|
<CustomTable data={boilers} columns={[
|
||||||
|
{
|
||||||
|
accessorKey: 'id_object',
|
||||||
|
header: 'ID',
|
||||||
|
cell: (info) => info.getValue(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'boiler_name',
|
||||||
|
header: 'Название',
|
||||||
|
cell: (info) => info.getValue(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'boiler_code',
|
||||||
|
header: 'Код',
|
||||||
|
cell: (info) => info.getValue(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'id_city',
|
||||||
|
header: 'Город',
|
||||||
|
cell: (info) => info.getValue(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'activity',
|
||||||
|
header: 'Активен',
|
||||||
|
cell: (info) => info.getValue(),
|
||||||
|
},
|
||||||
|
]} />
|
||||||
|
}
|
||||||
|
|
||||||
|
{/* {boilers &&
|
||||||
<Table highlightOnHover>
|
<Table highlightOnHover>
|
||||||
<Table.Thead>
|
<Table.Thead>
|
||||||
<Table.Tr>
|
<Table.Tr>
|
||||||
@ -77,8 +99,8 @@ function Boilers() {
|
|||||||
))}
|
))}
|
||||||
</Table.Tbody>
|
</Table.Tbody>
|
||||||
</Table>
|
</Table>
|
||||||
}
|
} */}
|
||||||
</ScrollAreaAutosize>
|
</Stack>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
78
client/src/pages/DBManager.tsx
Normal file
78
client/src/pages/DBManager.tsx
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import { Stack, Tabs } from '@mantine/core'
|
||||||
|
import useSWR from 'swr'
|
||||||
|
import { BASE_URL } from '../constants'
|
||||||
|
import { fetcher } from '../http/axiosInstance'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import CustomTable from '../components/CustomTable'
|
||||||
|
|
||||||
|
const DBManager = () => {
|
||||||
|
const { data: tablesData } = useSWR(`/db/tables`, (key) => fetcher(key, BASE_URL.ems), {
|
||||||
|
revalidateOnFocus: false
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack w={'100%'} h={'100%'} p='xs'>
|
||||||
|
{tablesData && Array.isArray(tablesData) && tablesData.length > 0 &&
|
||||||
|
<Tabs w='100%' h='80%'>
|
||||||
|
<Stack h='100%'>
|
||||||
|
<Tabs.List>
|
||||||
|
{tablesData.map(table => (
|
||||||
|
<Tabs.Tab key={table.tablename} value={table.tablename}>
|
||||||
|
{table.tablename}
|
||||||
|
</Tabs.Tab>
|
||||||
|
))}
|
||||||
|
</Tabs.List>
|
||||||
|
|
||||||
|
{tablesData.map(table => (
|
||||||
|
<Tabs.Panel h='100%' key={table.tablename} value={table.tablename} w='100%'>
|
||||||
|
<TableData tablename={table.tablename} />
|
||||||
|
</Tabs.Panel>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
</Tabs>
|
||||||
|
}
|
||||||
|
{/* <Card withBorder radius='sm'>
|
||||||
|
<Stack>
|
||||||
|
<Group justify='flex-start'>
|
||||||
|
<Text fw='bold'>Figures</Text>
|
||||||
|
</Group>
|
||||||
|
<Grid>
|
||||||
|
<Button>Import from New_Gis (erases data)</Button>
|
||||||
|
</Grid>
|
||||||
|
</Stack>
|
||||||
|
</Card> */}
|
||||||
|
</Stack>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const TableData = ({
|
||||||
|
tablename
|
||||||
|
}: { tablename: string }) => {
|
||||||
|
const [offset] = useState(0)
|
||||||
|
const [limit] = useState(20)
|
||||||
|
|
||||||
|
const { data: columnsData } = useSWR(`/db/columns/${tablename}`, (key) => fetcher(key, BASE_URL.ems), {
|
||||||
|
revalidateOnFocus: false
|
||||||
|
})
|
||||||
|
|
||||||
|
const { data: rowsData } = useSWR(columnsData ? `/db/rows/${tablename}?offset=${offset}&limit=${limit}` : null, (key) => fetcher(key, BASE_URL.ems), {
|
||||||
|
revalidateOnFocus: false
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{columnsData && rowsData && Array.isArray(columnsData) && Array.isArray(rowsData) && columnsData.length > 0 &&
|
||||||
|
<CustomTable data={rowsData} columns={columnsData.map(column => (
|
||||||
|
{
|
||||||
|
accessorKey: column.column_name,
|
||||||
|
header: column.column_name,
|
||||||
|
cell: (info) => JSON.stringify(info.getValue()).length > 30 ? [JSON.stringify(info.getValue()).substring(0, 30), '...'].join('') : JSON.stringify(info.getValue()),
|
||||||
|
}
|
||||||
|
))} />
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DBManager
|
||||||
207
client/src/pages/Fuel.tsx
Normal file
207
client/src/pages/Fuel.tsx
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
import { ActionIcon, Button, Flex, Input, Loader, LoadingOverlay, Modal, Overlay, Table, Tabs, TextInput, useMantineColorScheme } from "@mantine/core";
|
||||||
|
import { IconMathMax, IconPlus, IconTableMinus, IconTablePlus } from "@tabler/icons-react";
|
||||||
|
import { FuelExpenseDto, FuelExpenseDtoHeaders, FuelLimitDto, FuelLimitDtoHeaders } from "../dto/fuel/fuel.dto";
|
||||||
|
import useSWR from "swr";
|
||||||
|
import { fetcher } from "../http/axiosInstanceNest";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { useDisclosure } from "@mantine/hooks";
|
||||||
|
import { DateInput, DatePicker } from '@mantine/dates'
|
||||||
|
import { SubmitHandler, useForm } from "react-hook-form";
|
||||||
|
|
||||||
|
import { AgGridReact } from "ag-grid-react";
|
||||||
|
import { AllCommunityModule, ColDef, ModuleRegistry } from 'ag-grid-community'
|
||||||
|
|
||||||
|
ModuleRegistry.registerModules([AllCommunityModule])
|
||||||
|
|
||||||
|
type FieldType = 'text' | 'number' | 'select' | 'date'
|
||||||
|
|
||||||
|
interface IPostInclude {
|
||||||
|
field: string
|
||||||
|
field_type: FieldType
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ITableSchema {
|
||||||
|
label: string
|
||||||
|
value: string
|
||||||
|
get: string
|
||||||
|
post: string
|
||||||
|
headers: { [key: string]: string }
|
||||||
|
post_include: IPostInclude[]
|
||||||
|
icon: JSX.Element
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function FuelPage() {
|
||||||
|
const tables: ITableSchema[] = [
|
||||||
|
{
|
||||||
|
label: 'Расходы',
|
||||||
|
value: 'expenses',
|
||||||
|
get: '/fuel/expenses',
|
||||||
|
post: '/fuel/expenses',
|
||||||
|
headers: FuelExpenseDtoHeaders,
|
||||||
|
post_include: [
|
||||||
|
{
|
||||||
|
field: 'id_boiler',
|
||||||
|
field_type: 'text'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'id_fuel',
|
||||||
|
field_type: 'text'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'date',
|
||||||
|
field_type: 'date'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'value',
|
||||||
|
field_type: 'text'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
icon: <IconTableMinus size={12} />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Лимиты',
|
||||||
|
value: 'limits',
|
||||||
|
get: '/fuel/limits',
|
||||||
|
post: '/fuel/limits',
|
||||||
|
headers: FuelLimitDtoHeaders,
|
||||||
|
post_include: [
|
||||||
|
{
|
||||||
|
field: 'id_boiler',
|
||||||
|
field_type: 'text'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'id_fuel',
|
||||||
|
field_type: 'text'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'month',
|
||||||
|
field_type: 'number'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'year',
|
||||||
|
field_type: 'number'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'value',
|
||||||
|
field_type: 'text'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
icon: <IconMathMax size={12} />,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const [currentTab, setCurrentTab] = useState(tables[0])
|
||||||
|
|
||||||
|
const { data, isLoading } = useSWR(currentTab.get, () => fetcher(currentTab.get), { revalidateOnFocus: false })
|
||||||
|
|
||||||
|
const [openedCreateModal, { open: openCreateModal, close: closeCreateModal }] = useDisclosure(false)
|
||||||
|
|
||||||
|
const { colorScheme } = useMantineColorScheme()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (colorScheme === 'dark') {
|
||||||
|
document.body.dataset.agThemeMode = 'dark'
|
||||||
|
} else {
|
||||||
|
document.body.dataset.agThemeMode = 'light'
|
||||||
|
}
|
||||||
|
}, [colorScheme])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ModalCreate openedCreateModal={openedCreateModal} closeCreateModal={closeCreateModal} currentTab={currentTab} />
|
||||||
|
|
||||||
|
<Tabs defaultValue={tables[0].value} w='100%' onChange={(tab) => setCurrentTab(tables.find(table => table.value === tab) || tables[0])}>
|
||||||
|
<Tabs.List>
|
||||||
|
{tables.map((table, index) => (
|
||||||
|
<Tabs.Tab key={index} value={table.value} leftSection={table.icon}>
|
||||||
|
{table.label}
|
||||||
|
</Tabs.Tab>
|
||||||
|
))}
|
||||||
|
</Tabs.List>
|
||||||
|
|
||||||
|
<Flex p='sm'>
|
||||||
|
<Button leftSection={<IconPlus />} onClick={openCreateModal}>
|
||||||
|
Добавить
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
{tables.map((table, index) => (
|
||||||
|
<Tabs.Panel key={index} value={table.value} w='100%' h='100%'>
|
||||||
|
{isLoading ?
|
||||||
|
<Flex w='100%' justify={'center'} p='md'>
|
||||||
|
<Loader />
|
||||||
|
</Flex>
|
||||||
|
:
|
||||||
|
<>
|
||||||
|
<AgGridReact
|
||||||
|
//rowData={data}
|
||||||
|
rowData={[
|
||||||
|
Object.keys(table.headers).reduce((obj, key) => ({ ...obj, [key]: 'test' }), {}),
|
||||||
|
Object.keys(table.headers).reduce((obj, key) => ({ ...obj, [key]: 'test' }), {})
|
||||||
|
]}
|
||||||
|
columnDefs={Object.keys(table.headers).map((header) => ({
|
||||||
|
field: header
|
||||||
|
})) as ColDef[]}
|
||||||
|
defaultColDef={{
|
||||||
|
flex: 1,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
</Tabs.Panel>
|
||||||
|
))}
|
||||||
|
</Tabs>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const ModalCreate = ({
|
||||||
|
openedCreateModal,
|
||||||
|
closeCreateModal,
|
||||||
|
currentTab
|
||||||
|
}: {
|
||||||
|
openedCreateModal: boolean
|
||||||
|
closeCreateModal: () => void
|
||||||
|
currentTab: ITableSchema
|
||||||
|
}) => {
|
||||||
|
const { register, handleSubmit, reset, watch, formState: { errors, isSubmitting, dirtyFields, isValid } } = useForm({
|
||||||
|
mode: 'onChange',
|
||||||
|
})
|
||||||
|
|
||||||
|
const onSubmit: SubmitHandler<any> = async (values: any) => {
|
||||||
|
console.log('Values to submit:', values)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal withinPortal opened={openedCreateModal} onClose={closeCreateModal}>
|
||||||
|
<LoadingOverlay visible={isSubmitting} />
|
||||||
|
|
||||||
|
<Flex direction='column' gap='sm' component='form' onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
{currentTab.post_include.map((header, index) => {
|
||||||
|
switch (header.field_type) {
|
||||||
|
case 'date':
|
||||||
|
return (
|
||||||
|
<DateInput label={header.field} />
|
||||||
|
)
|
||||||
|
case 'text':
|
||||||
|
return (
|
||||||
|
<TextInput key={index} label={header.field} {...register(header.field, {
|
||||||
|
required: true
|
||||||
|
})} />
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
return (
|
||||||
|
<TextInput key={index} label={header.field} {...register(header.field, {
|
||||||
|
required: true
|
||||||
|
})} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
|
||||||
|
<Button mt='xl' type='submit'>
|
||||||
|
Добавить
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -1,8 +1,81 @@
|
|||||||
|
import { Container, Stack, Tabs } from '@mantine/core'
|
||||||
import MapComponent from '../components/map/MapComponent'
|
import MapComponent from '../components/map/MapComponent'
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
import { initializeObjectsState } from '../store/objects'
|
||||||
|
import { deleteMapTab, setCurrentTab, useAppStore } from '../store/app'
|
||||||
|
import { initializeMapState, useMapStore } from '../store/map'
|
||||||
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
|
||||||
function MapTest() {
|
function MapTest() {
|
||||||
|
const { mapTab, currentTab } = useAppStore()
|
||||||
|
const { id } = useMapStore()
|
||||||
|
|
||||||
|
const tabs = [
|
||||||
|
{
|
||||||
|
id: uuidv4(),
|
||||||
|
year: 2018,
|
||||||
|
region: 11,
|
||||||
|
district: 146,
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// id: uuidv4(),
|
||||||
|
// year: 2023,
|
||||||
|
// region: 11,
|
||||||
|
// district: 146,
|
||||||
|
// },
|
||||||
|
]
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
tabs.map(tab => useAppStore.setState((state) => {
|
||||||
|
initializeObjectsState(tab.id, tab.region, tab.district, null, tab.year)
|
||||||
|
initializeMapState(tab.id)
|
||||||
|
|
||||||
|
return {
|
||||||
|
mapTab: {
|
||||||
|
...state.mapTab,
|
||||||
|
[tab.id]: {
|
||||||
|
year: tab.year,
|
||||||
|
region: tab.region,
|
||||||
|
district: tab.district
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
setCurrentTab(tabs[0].id)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
tabs.map(tab => deleteMapTab(tab.id))
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MapComponent />
|
<Container fluid w='100%' pos='relative' p={0}>
|
||||||
|
<Tabs h='100%' variant='default' value={currentTab} onChange={setCurrentTab} keepMounted={true}>
|
||||||
|
<Stack gap={0} h='100%'>
|
||||||
|
<Tabs.List>
|
||||||
|
{Object.entries(mapTab).map(([key]) => (
|
||||||
|
<Tabs.Tab value={key} key={key}>
|
||||||
|
{id[key]?.mapLabel}
|
||||||
|
</Tabs.Tab>
|
||||||
|
))}
|
||||||
|
</Tabs.List>
|
||||||
|
|
||||||
|
{Object.entries(mapTab).map(([key]) => (
|
||||||
|
<Tabs.Panel value={key} key={key} h='100%' pos='relative'>
|
||||||
|
<MapComponent
|
||||||
|
key={key}
|
||||||
|
id={key}
|
||||||
|
active={currentTab === key}
|
||||||
|
/>
|
||||||
|
|
||||||
|
</Tabs.Panel>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1275
client/src/pages/PrintReport.tsx
Normal file
1275
client/src/pages/PrintReport.tsx
Normal file
File diff suppressed because it is too large
Load Diff
@ -93,11 +93,11 @@ export default function Reports() {
|
|||||||
</Table.Thead>
|
</Table.Thead>
|
||||||
<Table.Tbody>
|
<Table.Tbody>
|
||||||
{[...new Set(Object.keys(report).flatMap(key => Object.keys(report[key])))].map(id => {
|
{[...new Set(Object.keys(report).flatMap(key => Object.keys(report[key])))].map(id => {
|
||||||
const row: any = { id: Number(id) };
|
const row: Record<string, unknown> = { id: Number(id) };
|
||||||
Object.keys(report).forEach(key => {
|
Object.keys(report).forEach(key => {
|
||||||
row[key] = report[key][id];
|
row[key] = report[key][id];
|
||||||
});
|
});
|
||||||
return (<Table.Tr key={row.id}>
|
return (<Table.Tr key={row.id as number}>
|
||||||
{[
|
{[
|
||||||
{ field: 'id', headerName: '№', width: 70 },
|
{ field: 'id', headerName: '№', width: 70 },
|
||||||
...Object.keys(report).map(key => ({
|
...Object.keys(report).map(key => ({
|
||||||
@ -125,7 +125,7 @@ export default function Reports() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Table.Td key={`${row.id}-${column.headerName}`}>{row[column.field]}</Table.Td>
|
<Table.Td key={`${row.id}-${column.headerName}`}>{row[column.field] as string}</Table.Td>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</Table.Tr>)
|
</Table.Tr>)
|
||||||
|
|||||||
@ -1,63 +1,42 @@
|
|||||||
import { useRoles } from '../hooks/swrHooks'
|
import { useRoles } from '../hooks/swrHooks'
|
||||||
import { CreateField } from '../interfaces/create'
|
import { CreateField } from '../interfaces/create'
|
||||||
import RoleService from '../services/RoleService'
|
import RoleService from '../services/RoleService'
|
||||||
import FormFields from '../components/FormFields'
|
import { Loader, Stack } from '@mantine/core'
|
||||||
import { Button, Loader, Modal, ScrollAreaAutosize, Table } from '@mantine/core'
|
import CustomTable from '../components/CustomTable'
|
||||||
import { useDisclosure } from '@mantine/hooks'
|
|
||||||
import { IRole } from '../interfaces/role'
|
|
||||||
|
|
||||||
export default function Roles() {
|
export default function Roles() {
|
||||||
const { roles, isError, isLoading } = useRoles()
|
const { roles, isError, isLoading } = useRoles()
|
||||||
|
|
||||||
const [opened, { open, close }] = useDisclosure(false);
|
|
||||||
|
|
||||||
const createFields: CreateField[] = [
|
const createFields: CreateField[] = [
|
||||||
{ key: 'name', headerName: 'Название', type: 'string', required: true, defaultValue: '' },
|
{ key: 'name', headerName: 'Название', type: 'string', required: true, defaultValue: '' },
|
||||||
{ key: 'description', headerName: 'Описание', type: 'string', required: false, defaultValue: '' },
|
{ key: 'description', headerName: 'Описание', type: 'string', required: false, defaultValue: '' },
|
||||||
]
|
]
|
||||||
|
|
||||||
const columns = [
|
|
||||||
{ field: 'id', headerName: 'ID', type: "number" },
|
|
||||||
{ field: 'name', headerName: 'Название', flex: 1, editable: true },
|
|
||||||
{ field: 'description', headerName: 'Описание', flex: 1, editable: true },
|
|
||||||
];
|
|
||||||
|
|
||||||
if (isError) return <div>Произошла ошибка при получении данных.</div>
|
if (isError) return <div>Произошла ошибка при получении данных.</div>
|
||||||
if (isLoading) return <Loader />
|
if (isLoading) return <Loader />
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollAreaAutosize w={'100%'} h={'100%'} p='sm'>
|
<Stack w={'100%'} h={'100%'} p='sm'>
|
||||||
<Button onClick={open}>
|
<CustomTable
|
||||||
Добавить роль
|
createFields={createFields}
|
||||||
</Button>
|
submitHandler={RoleService.createRole}
|
||||||
|
data={roles} columns={[
|
||||||
<Modal opened={opened} onClose={close} title="Создание роли" centered>
|
{
|
||||||
<FormFields
|
accessorKey: 'id',
|
||||||
fields={createFields}
|
header: 'id',
|
||||||
submitHandler={RoleService.createRole}
|
cell: (info) => info.getValue(),
|
||||||
/>
|
},
|
||||||
</Modal>
|
{
|
||||||
|
accessorKey: 'name',
|
||||||
<Table highlightOnHover>
|
header: 'Название',
|
||||||
<Table.Thead>
|
cell: (info) => info.getValue(),
|
||||||
<Table.Tr>
|
},
|
||||||
{columns.map(column => (
|
{
|
||||||
<Table.Th key={column.field}>{column.headerName}</Table.Th>
|
accessorKey: 'description',
|
||||||
))}
|
header: 'Описание',
|
||||||
</Table.Tr>
|
cell: (info) => info.getValue(),
|
||||||
</Table.Thead>
|
},
|
||||||
<Table.Tbody>
|
]} />
|
||||||
{roles.map((role: IRole) => (
|
</Stack>
|
||||||
<Table.Tr
|
|
||||||
key={role.id}
|
|
||||||
>
|
|
||||||
{columns.map(column => (
|
|
||||||
<Table.Td key={column.field}>{role[column.field as keyof IRole]}</Table.Td>
|
|
||||||
))}
|
|
||||||
</Table.Tr>
|
|
||||||
))}
|
|
||||||
</Table.Tbody>
|
|
||||||
</Table>
|
|
||||||
</ScrollAreaAutosize>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1,13 +0,0 @@
|
|||||||
import { Flex } from '@mantine/core';
|
|
||||||
import CustomTable from '../components/CustomTable';
|
|
||||||
|
|
||||||
function TableTest() {
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex direction='column' align='flex-start' gap='sm' p='sm'>
|
|
||||||
<CustomTable />
|
|
||||||
</Flex>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TableTest
|
|
||||||
@ -3,10 +3,8 @@ import { IRole } from "../interfaces/role"
|
|||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
import { CreateField } from "../interfaces/create"
|
import { CreateField } from "../interfaces/create"
|
||||||
import UserService from "../services/UserService"
|
import UserService from "../services/UserService"
|
||||||
import FormFields from "../components/FormFields"
|
import { Flex, Loader, Stack } from "@mantine/core"
|
||||||
import { Badge, Button, Flex, Loader, Modal, Pagination, ScrollAreaAutosize, Select, Table } from "@mantine/core"
|
import CustomTable from "../components/CustomTable"
|
||||||
import { useDisclosure } from "@mantine/hooks"
|
|
||||||
import { IUser } from "../interfaces/user"
|
|
||||||
|
|
||||||
export default function Users() {
|
export default function Users() {
|
||||||
const { users, isError, isLoading } = useUsers()
|
const { users, isError, isLoading } = useUsers()
|
||||||
@ -21,8 +19,6 @@ export default function Users() {
|
|||||||
}
|
}
|
||||||
}, [roles])
|
}, [roles])
|
||||||
|
|
||||||
const [opened, { open, close }] = useDisclosure(false);
|
|
||||||
|
|
||||||
const createFields: CreateField[] = [
|
const createFields: CreateField[] = [
|
||||||
{ key: 'email', headerName: 'E-mail', type: 'string', required: true, defaultValue: '' },
|
{ key: 'email', headerName: 'E-mail', type: 'string', required: true, defaultValue: '' },
|
||||||
{ key: 'login', headerName: 'Логин', type: 'string', required: true, defaultValue: '' },
|
{ key: 'login', headerName: 'Логин', type: 'string', required: true, defaultValue: '' },
|
||||||
@ -32,24 +28,6 @@ export default function Users() {
|
|||||||
{ key: 'password', headerName: 'Пароль', type: 'string', required: true, defaultValue: '' },
|
{ key: 'password', headerName: 'Пароль', type: 'string', required: true, defaultValue: '' },
|
||||||
]
|
]
|
||||||
|
|
||||||
const columns = [
|
|
||||||
{ field: 'id', headerName: 'ID', type: "number", flex: 1 },
|
|
||||||
{ field: 'email', headerName: 'Email', flex: 1, editable: true },
|
|
||||||
{ field: 'login', headerName: 'Логин', flex: 1, editable: true },
|
|
||||||
{ field: 'phone', headerName: 'Телефон', flex: 1, editable: true },
|
|
||||||
{ field: 'name', headerName: 'Имя', flex: 1, editable: true },
|
|
||||||
{ field: 'surname', headerName: 'Фамилия', flex: 1, editable: true },
|
|
||||||
{ field: 'is_active', headerName: 'Статус', type: "boolean", flex: 1, editable: true },
|
|
||||||
{
|
|
||||||
field: 'role_id',
|
|
||||||
headerName: 'Роль',
|
|
||||||
valueOptions: roles ? roles.map((role: IRole) => ({ label: role.name, value: role.id })) : [],
|
|
||||||
type: 'singleSelect',
|
|
||||||
flex: 1,
|
|
||||||
editable: true
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
if (isError) return (
|
if (isError) return (
|
||||||
<div>
|
<div>
|
||||||
Произошла ошибка при получении данных.
|
Произошла ошибка при получении данных.
|
||||||
@ -65,97 +43,50 @@ export default function Users() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollAreaAutosize w={'100%'} h={'100%'} p='sm'>
|
<Stack w={'100%'} h={'100%'} p='xs'>
|
||||||
<Button onClick={open}>
|
|
||||||
Добавить пользователя
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Modal opened={opened} onClose={close} title="Регистрация пользователя" centered>
|
|
||||||
<FormFields
|
|
||||||
fields={createFields}
|
|
||||||
submitHandler={UserService.createUser}
|
|
||||||
/>
|
|
||||||
</Modal>
|
|
||||||
|
|
||||||
{Array.isArray(roleOptions) &&
|
{Array.isArray(roleOptions) &&
|
||||||
<Table highlightOnHover>
|
<CustomTable
|
||||||
<Table.Thead>
|
createFields={createFields}
|
||||||
<Table.Tr>
|
submitHandler={UserService.createUser}
|
||||||
{columns.map(column => (
|
data={users}
|
||||||
<Table.Th key={column.field}>{column.headerName}</Table.Th>
|
columns={[
|
||||||
))}
|
{
|
||||||
</Table.Tr>
|
accessorKey: 'email',
|
||||||
</Table.Thead>
|
header: 'E-mail',
|
||||||
<Table.Tbody>
|
cell: (info) => info.getValue(),
|
||||||
{users.map((user: IUser) => (
|
},
|
||||||
<Table.Tr
|
{
|
||||||
key={user.id}
|
accessorKey: 'login',
|
||||||
//bg={selectedRows.includes(element.position) ? 'var(--mantine-color-blue-light)' : undefined}
|
header: 'Логин',
|
||||||
>
|
cell: (info) => info.getValue(),
|
||||||
{columns.map(column => {
|
},
|
||||||
if (column.field === 'is_active') {
|
{
|
||||||
return (
|
accessorKey: 'phone',
|
||||||
user.is_active ? (
|
header: 'Телефон',
|
||||||
<Table.Td key={column.field}>
|
cell: (info) => info.getValue(),
|
||||||
<Badge fullWidth variant="light">
|
},
|
||||||
Активен
|
{
|
||||||
</Badge>
|
accessorKey: 'name',
|
||||||
</Table.Td>
|
header: 'Имя',
|
||||||
) : (
|
cell: (info) => info.getValue(),
|
||||||
<Table.Td key={column.field}>
|
},
|
||||||
<Badge color="gray" fullWidth variant="light">
|
{
|
||||||
Отключен
|
accessorKey: 'surname',
|
||||||
</Badge>
|
header: 'Фамилия',
|
||||||
</Table.Td>
|
cell: (info) => info.getValue(),
|
||||||
)
|
},
|
||||||
)
|
{
|
||||||
}
|
accessorKey: 'is_active',
|
||||||
else if (column.field === 'role_id') {
|
header: 'Активен',
|
||||||
return (
|
cell: (info) => info.getValue(),
|
||||||
<Table.Td key={column.field}>
|
},
|
||||||
<Select
|
{
|
||||||
data={roleOptions}
|
accessorKey: 'role_id',
|
||||||
defaultValue={user.role_id.toString()}
|
header: 'Роль',
|
||||||
variant="unstyled"
|
cell: (info) => info.getValue(),
|
||||||
allowDeselect={false}
|
}
|
||||||
/>
|
]} />
|
||||||
</Table.Td>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else return (
|
|
||||||
<Table.Td key={column.field}>{user[column.field as keyof IUser]}</Table.Td>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</Table.Tr>
|
|
||||||
))}
|
|
||||||
</Table.Tbody>
|
|
||||||
</Table>
|
|
||||||
}
|
}
|
||||||
|
</Stack>
|
||||||
<Pagination total={10} />
|
|
||||||
|
|
||||||
{/* <DataGrid
|
|
||||||
density="compact"
|
|
||||||
autoHeight
|
|
||||||
style={{ width: "100%" }}
|
|
||||||
rows={users}
|
|
||||||
columns={columns}
|
|
||||||
initialState={{
|
|
||||||
pagination: {
|
|
||||||
paginationModel: { page: 0, pageSize: 10 },
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
pageSizeOptions={[10, 20, 50, 100]}
|
|
||||||
checkboxSelection
|
|
||||||
disableRowSelectionOnClick
|
|
||||||
|
|
||||||
processRowUpdate={(updatedRow) => {
|
|
||||||
return updatedRow
|
|
||||||
}}
|
|
||||||
|
|
||||||
onProcessRowUpdateError={() => {
|
|
||||||
}}
|
|
||||||
/> */}
|
|
||||||
</ScrollAreaAutosize>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
39
client/src/services/GisService.ts
Normal file
39
client/src/services/GisService.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { AxiosRequestConfig } from "axios";
|
||||||
|
import axiosInstance from "../http/axiosInstance";
|
||||||
|
import { BASE_URL } from "../constants";
|
||||||
|
import { Extent } from "ol/extent";
|
||||||
|
import { IRectCoords } from "../interfaces/map";
|
||||||
|
|
||||||
|
const config: AxiosRequestConfig = {
|
||||||
|
baseURL: BASE_URL.ems
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class GisService {
|
||||||
|
static async getAddress(limit?: number, page?: number) {
|
||||||
|
return await axiosInstance.get(`/general/address?limit=${limit || 10}&page=${page || 1}`, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
static async uploadOverlay(file: File | null, polygonExtent: Extent | undefined, rectCoords: IRectCoords | undefined) {
|
||||||
|
if (file && polygonExtent && rectCoords?.bl && rectCoords?.tl && rectCoords?.tr && rectCoords?.br) {
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('file', file)
|
||||||
|
|
||||||
|
formData.append('extentMinX', polygonExtent[0].toString())
|
||||||
|
formData.append('extentMinY', polygonExtent[1].toString())
|
||||||
|
formData.append('extentMaxX', polygonExtent[2].toString())
|
||||||
|
formData.append('extentMaxY', polygonExtent[3].toString())
|
||||||
|
formData.append('blX', rectCoords?.bl[0].toString())
|
||||||
|
formData.append('blY', rectCoords?.bl[1].toString())
|
||||||
|
formData.append('tlX', rectCoords?.tl[0].toString())
|
||||||
|
formData.append('tlY', rectCoords?.tl[1].toString())
|
||||||
|
formData.append('trX', rectCoords?.tr[0].toString())
|
||||||
|
formData.append('trY', rectCoords?.tr[1].toString())
|
||||||
|
formData.append('brX', rectCoords?.br[0].toString())
|
||||||
|
formData.append('brY', rectCoords?.br[1].toString())
|
||||||
|
|
||||||
|
return await axiosInstance.post(`/tiles/upload`, formData, config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//static async updateFigure(object_id: string, )
|
||||||
|
}
|
||||||
43
client/src/store/app.ts
Normal file
43
client/src/store/app.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { create } from 'zustand';
|
||||||
|
|
||||||
|
export type Mode = 'edit' | 'view'
|
||||||
|
|
||||||
|
export interface AppState {
|
||||||
|
mapTab: Record<string, {
|
||||||
|
year: number | null,
|
||||||
|
region: number | null,
|
||||||
|
district: number | null
|
||||||
|
}>,
|
||||||
|
currentTab: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useAppStore = create<AppState>(() => ({
|
||||||
|
currentTab: null,
|
||||||
|
mapTab: {}
|
||||||
|
}))
|
||||||
|
|
||||||
|
const getCurrentTab = () => useAppStore.getState().currentTab
|
||||||
|
const setCurrentTab = (id: string | null) => useAppStore.setState(() => ({ currentTab: id }))
|
||||||
|
|
||||||
|
const setMapTabYear = (id: string, year: number | null) =>
|
||||||
|
useAppStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
mapTab: {
|
||||||
|
...state.mapTab,
|
||||||
|
[id]: { ...state.mapTab[id], year: year }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const deleteMapTab = (id: string) =>
|
||||||
|
useAppStore.setState((state) => {
|
||||||
|
const { [id]: _, ...remainingTabs } = state.mapTab;
|
||||||
|
return { mapTab: remainingTabs };
|
||||||
|
})
|
||||||
|
|
||||||
|
export {
|
||||||
|
deleteMapTab,
|
||||||
|
getCurrentTab,
|
||||||
|
setCurrentTab,
|
||||||
|
setMapTabYear
|
||||||
|
}
|
||||||
@ -1,115 +1,783 @@
|
|||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { ToolType } from '../types/tools';
|
import { ToolType } from '../types/tools';
|
||||||
import { Point } from 'ol/geom';
|
import { Geometry, Point } from 'ol/geom';
|
||||||
import Map from 'ol/Map';
|
import Map from 'ol/Map';
|
||||||
import { Coordinate } from 'ol/coordinate';
|
import { Coordinate } from 'ol/coordinate';
|
||||||
import { SatelliteMapsProvider } from '../interfaces/map';
|
import { IRectCoords, SatelliteMapsProvider } from '../interfaces/map';
|
||||||
|
import { TypeRole } from '../interfaces/gis';
|
||||||
|
import VectorSource from 'ol/source/Vector';
|
||||||
|
import Feature from 'ol/Feature';
|
||||||
|
import { containsExtent, Extent } from 'ol/extent';
|
||||||
|
import { Draw, Modify, Select, Snap, Translate } from 'ol/interaction';
|
||||||
|
import TileLayer from 'ol/layer/Tile';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
import { googleMapsSatelliteSource } from '../components/map/MapSources';
|
||||||
|
import VectorLayer from 'ol/layer/Vector';
|
||||||
|
import { ImageStatic, OSM } from 'ol/source';
|
||||||
|
import ImageLayer from 'ol/layer/Image';
|
||||||
|
import { drawingLayerStyle, figureStyle, highlightStyleRed, highlightStyleYellow, lineStyle, overlayStyle, regionsLayerStyle, selectStyle } from '../components/map/MapStyles';
|
||||||
|
import { Fill, Stroke, Style } from 'ol/style';
|
||||||
|
import { VectorImage } from 'ol/layer';
|
||||||
|
import { click, pointerMove } from 'ol/events/condition';
|
||||||
|
import { measureStyleFunction, modifyStyle } from '../components/map/Measure/MeasureStyles';
|
||||||
|
import MapBrowserEvent from 'ol/MapBrowserEvent';
|
||||||
|
import { transform } from 'ol/proj';
|
||||||
|
import { applyTransformations, calculateTransformations, fixedAspectRatioBox, zoomToFeature } from '../components/map/mapUtils';
|
||||||
|
import { setCurrentObjectId, setSelectedRegion } from './objects';
|
||||||
|
import View from 'ol/View';
|
||||||
|
import { getPrintOrientation } from './print';
|
||||||
|
|
||||||
|
export type Mode = 'edit' | 'view' | 'print'
|
||||||
|
|
||||||
|
export type PrintScale = '500' | '250' | '50' | '25' | '10'
|
||||||
|
|
||||||
|
export type PrintOrientation = 'horizontal' | 'vertical'
|
||||||
|
|
||||||
interface MapState {
|
interface MapState {
|
||||||
currentTool: ToolType;
|
id: Record<string, {
|
||||||
measureType: "LineString" | "Polygon";
|
currentTool: ToolType;
|
||||||
measureShowSegments: boolean;
|
measureType: "LineString" | "Polygon";
|
||||||
measureClearPrevious: boolean;
|
measureShowSegments: boolean;
|
||||||
tipPoint: Point | null;
|
measureClearPrevious: boolean;
|
||||||
map: Map | null;
|
tipPoint: Point | null;
|
||||||
currentZ: number | undefined;
|
map: Map | null;
|
||||||
currentX: number | undefined;
|
currentZ: number | undefined;
|
||||||
currentY: number | undefined;
|
currentX: number | undefined;
|
||||||
currentCoordinate: Coordinate | null;
|
currentY: number | undefined;
|
||||||
statusText: string;
|
currentCoordinate: Coordinate | null;
|
||||||
satMapsProvider: SatelliteMapsProvider;
|
statusText: string;
|
||||||
selectedObjectType: number | null;
|
satMapsProvider: SatelliteMapsProvider;
|
||||||
|
selectedObjectType: number | null;
|
||||||
|
alignMode: boolean;
|
||||||
|
mode: Mode;
|
||||||
|
typeRoles: TypeRole[] | null;
|
||||||
|
mapLabel: string;
|
||||||
|
file: File | null;
|
||||||
|
measureSource: VectorSource<Feature<Geometry>>;
|
||||||
|
measureDraw: Draw | null;
|
||||||
|
polygonExtent: Extent | undefined;
|
||||||
|
rectCoords: IRectCoords | undefined;
|
||||||
|
alignPoints: Coordinate[];
|
||||||
|
alignModeLayer: VectorLayer;
|
||||||
|
drawingLayer: VectorLayer;
|
||||||
|
drawingLayerSource: VectorSource;
|
||||||
|
draw: Draw | null;
|
||||||
|
snap: Snap | null;
|
||||||
|
translate: Translate | null;
|
||||||
|
overlayLayerSource: VectorSource;
|
||||||
|
satLayer: TileLayer;
|
||||||
|
nodeLayer: VectorLayer;
|
||||||
|
nodeLayerSource: VectorSource;
|
||||||
|
staticMapLayer: ImageLayer<ImageStatic>;
|
||||||
|
figuresLayer: VectorLayer<VectorSource>;
|
||||||
|
linesLayer: VectorLayer<VectorSource>;
|
||||||
|
regionsLayer: VectorImage;
|
||||||
|
citiesLayer: VectorLayer;
|
||||||
|
districtBoundLayer: VectorImage;
|
||||||
|
imageLayer: ImageLayer<ImageStatic>;
|
||||||
|
selectedArea: Feature | null;
|
||||||
|
baseLayer: TileLayer;
|
||||||
|
measureLayer: VectorLayer;
|
||||||
|
measureModify: Modify;
|
||||||
|
overlayLayer: VectorLayer;
|
||||||
|
regionSelect: Select;
|
||||||
|
lineSelect: Select;
|
||||||
|
previousView: View | undefined | null;
|
||||||
|
printArea: Extent | null;
|
||||||
|
printLayer: VectorLayer;
|
||||||
|
printSource: VectorSource;
|
||||||
|
printAreaDraw: Draw;
|
||||||
|
printPreviewSize: number[];
|
||||||
|
printDim: 'a0' | 'a1' | 'a2' | 'a3' | 'a4' | 'a5';
|
||||||
|
printRes: number;
|
||||||
|
printOrientation: PrintOrientation;
|
||||||
|
printScale: PrintScale;
|
||||||
|
printScaleLine: boolean;
|
||||||
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useMapStore = create<MapState>(() => ({
|
export const useMapStore = create<MapState>(() => ({
|
||||||
currentTool: null,
|
id: {}
|
||||||
measureType: "LineString",
|
}))
|
||||||
measureShowSegments: true,
|
|
||||||
measureClearPrevious: true,
|
|
||||||
tipPoint: null,
|
|
||||||
map: null,
|
|
||||||
currentZ: undefined,
|
|
||||||
currentX: undefined,
|
|
||||||
currentY: undefined,
|
|
||||||
currentCoordinate: null,
|
|
||||||
statusText: '',
|
|
||||||
satMapsProvider: 'google',
|
|
||||||
selectedObjectType: null,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const setCurrentZ = (z: number | undefined) => useMapStore.setState(() => ({ currentZ: z }))
|
export const initializeMapState = (
|
||||||
const setCurrentX = (x: number | undefined) => useMapStore.setState(() => ({ currentX: x }))
|
id: string
|
||||||
const setCurrentY = (y: number | undefined) => useMapStore.setState(() => ({ currentY: y }))
|
) => {
|
||||||
const setCurrentCoordinate = (c: Coordinate | null) => useMapStore.setState(() => ({ currentCoordinate: c }))
|
useMapStore.setState((state) => {
|
||||||
const setStatusText = (t: string) => useMapStore.setState(() => ({ statusText: t }))
|
const hitTolerance = 10
|
||||||
const setSatMapsProvider = (p: SatelliteMapsProvider) => useMapStore.setState(() => ({ satMapsProvider: p }))
|
|
||||||
const setSelectedObjectType = (t: number | null) => useMapStore.setState(() => ({ selectedObjectType: t }))
|
|
||||||
const setMap = (m: Map | null) => useMapStore.setState(() => ({ map: m }))
|
|
||||||
|
|
||||||
const setTipPoint = (tipPoint: Point | null) => {
|
const baseLayer = new TileLayer({ source: new OSM(), properties: { id: uuidv4(), name: 'OpenStreetMap' } })
|
||||||
useMapStore.setState(() => ({ tipPoint: tipPoint }))
|
|
||||||
|
const satLayer = new TileLayer({ source: googleMapsSatelliteSource, visible: false, properties: { id: uuidv4(), name: 'Спутник' } })
|
||||||
|
|
||||||
|
const staticMapLayer = new ImageLayer<ImageStatic>({ properties: { id: uuidv4(), name: 'Подложка' } })
|
||||||
|
|
||||||
|
// Region select
|
||||||
|
const regionSelect = new Select({ condition: pointerMove, style: selectStyle, layers: (layer) => layer.get('type') === 'region' })
|
||||||
|
|
||||||
|
// Line select
|
||||||
|
const lineSelect = new Select({ condition: click, style: highlightStyleRed, hitTolerance: hitTolerance, layers: (layer) => layer.get('type') === 'line', })
|
||||||
|
lineSelect.on('select', (e) => {
|
||||||
|
if (e.selected[0]) {
|
||||||
|
setCurrentObjectId(id, e.selected[0].get('object_id'))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const lineHover = new Select({ condition: pointerMove, style: highlightStyleYellow, hitTolerance: hitTolerance, layers: (layer) => layer.get('type') === 'line', })
|
||||||
|
|
||||||
|
// Figure select
|
||||||
|
const figureSelect = new Select({ condition: click, style: highlightStyleRed, hitTolerance: hitTolerance, layers: (layer) => layer.get('type') === 'figure' })
|
||||||
|
figureSelect.on('select', (e) => {
|
||||||
|
if (e.selected[0]) {
|
||||||
|
setCurrentObjectId(id, e.selected[0].get('object_id'))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const figureHover = new Select({ condition: pointerMove, style: highlightStyleYellow, hitTolerance: hitTolerance, layers: (layer) => layer.get('type') === 'figure', })
|
||||||
|
|
||||||
|
const measureSource = new VectorSource()
|
||||||
|
const measureLayer = new VectorLayer({
|
||||||
|
source: measureSource,
|
||||||
|
style: (feature) => measureStyleFunction(id, feature),
|
||||||
|
properties: { id: uuidv4(), type: 'measure', name: 'Линейка' }
|
||||||
|
})
|
||||||
|
const measureModify = new Modify({
|
||||||
|
source: measureSource,
|
||||||
|
style: modifyStyle
|
||||||
|
})
|
||||||
|
|
||||||
|
const nodeLayerSource = new VectorSource()
|
||||||
|
const nodeLayer = new VectorLayer({
|
||||||
|
source: nodeLayerSource,
|
||||||
|
style: drawingLayerStyle,
|
||||||
|
properties: {
|
||||||
|
id: uuidv4(),
|
||||||
|
name: 'Узлы'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const overlayLayerSource = new VectorSource()
|
||||||
|
const overlayLayer = new VectorLayer({
|
||||||
|
source: overlayLayerSource,
|
||||||
|
style: overlayStyle,
|
||||||
|
properties: {
|
||||||
|
id: uuidv4(),
|
||||||
|
name: 'Наложения'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const drawingLayerSource = new VectorSource()
|
||||||
|
const drawingLayer = new VectorLayer({
|
||||||
|
source: drawingLayerSource
|
||||||
|
})
|
||||||
|
|
||||||
|
const regionsLayer = new VectorImage({
|
||||||
|
source: new VectorSource(),
|
||||||
|
declutter: true,
|
||||||
|
style: regionsLayerStyle,
|
||||||
|
properties: {
|
||||||
|
id: uuidv4(),
|
||||||
|
name: 'Регион',
|
||||||
|
type: 'region'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const districtBoundLayer = new VectorImage({ style: new Style({ stroke: new Stroke({ color: 'red', width: 2 }), }) })
|
||||||
|
|
||||||
|
const citiesLayer = new VectorLayer({ source: new VectorSource(), properties: { id: uuidv4(), name: 'Города' } })
|
||||||
|
|
||||||
|
const linesLayer = new VectorLayer({
|
||||||
|
source: new VectorSource(),
|
||||||
|
declutter: true,
|
||||||
|
properties: { id: uuidv4(), type: 'line', name: 'Линии' },
|
||||||
|
style: function (feature) {
|
||||||
|
const objectType = feature.get('type')
|
||||||
|
const typeRole = getTypeRoles(id)?.find((el) => el.id.toString() === String(objectType))
|
||||||
|
if (typeRole) {
|
||||||
|
lineStyle.setStroke(new Stroke({
|
||||||
|
color: `rgb(${typeRole.r},${typeRole.g},${typeRole.b})`
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
//lineStyle.getText()?.setText('11,4')//(feature.get('object_id'))
|
||||||
|
lineStyle.getText()?.setRotation(feature.get('rotation'))
|
||||||
|
lineStyle.getText()?.setOffsetY(-8)
|
||||||
|
return lineStyle
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const figuresLayer = new VectorLayer({
|
||||||
|
source: new VectorSource(),
|
||||||
|
declutter: true,
|
||||||
|
properties: { id: uuidv4(), type: 'figure', name: 'Фигуры' },
|
||||||
|
style: function (feature) {
|
||||||
|
const objectType = feature.get('type')
|
||||||
|
const typeRole = getTypeRoles(id)?.find((el) => el.id.toString() === String(objectType))
|
||||||
|
|
||||||
|
if (typeRole) {
|
||||||
|
figureStyle.setFill(new Fill({
|
||||||
|
color: `rgb(${typeRole.r},${typeRole.g},${typeRole.b})`
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
figureStyle.getText()?.setText(feature.get('object_id'))
|
||||||
|
return figureStyle
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const imageLayer = new ImageLayer<ImageStatic>({ properties: { id: uuidv4(), name: 'Изображение' } })
|
||||||
|
|
||||||
|
const alignModeLayer = new VectorLayer({ source: new VectorSource(), properties: { id: uuidv4(), type: 'align', name: 'Подгонка' } })
|
||||||
|
|
||||||
|
|
||||||
|
const printSource = new VectorSource()
|
||||||
|
const printLayer = new VectorLayer({
|
||||||
|
source: printSource
|
||||||
|
})
|
||||||
|
const printAreaDraw = new Draw({
|
||||||
|
source: printSource,
|
||||||
|
type: 'Circle',
|
||||||
|
style: () => {
|
||||||
|
return new Style({
|
||||||
|
fill: new Fill({
|
||||||
|
color: "rgba(0, 0, 255, 0.3)", // Semi-transparent blue fill
|
||||||
|
}),
|
||||||
|
stroke: new Stroke({
|
||||||
|
color: "blue",
|
||||||
|
width: 2,
|
||||||
|
}),
|
||||||
|
image: undefined, // 🚀 This removes the default point!
|
||||||
|
});
|
||||||
|
},
|
||||||
|
geometryFunction: function (coords, geom) {
|
||||||
|
const printOrientation = getPrintOrientation()
|
||||||
|
return fixedAspectRatioBox(coords, geom, printOrientation)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
printAreaDraw.on('drawend', (e) => {
|
||||||
|
const extent = e.feature.getGeometry()?.getExtent()
|
||||||
|
if (extent) {
|
||||||
|
setPrintArea(id, extent)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const map = new Map({
|
||||||
|
controls: [],
|
||||||
|
layers: [
|
||||||
|
baseLayer,
|
||||||
|
satLayer,
|
||||||
|
staticMapLayer,
|
||||||
|
regionsLayer,
|
||||||
|
districtBoundLayer,
|
||||||
|
citiesLayer,
|
||||||
|
linesLayer,
|
||||||
|
figuresLayer,
|
||||||
|
drawingLayer,
|
||||||
|
imageLayer,
|
||||||
|
overlayLayer,
|
||||||
|
nodeLayer,
|
||||||
|
measureLayer,
|
||||||
|
alignModeLayer,
|
||||||
|
printLayer
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
map.addInteraction(regionSelect)
|
||||||
|
map.addInteraction(lineSelect)
|
||||||
|
map.addInteraction(lineHover)
|
||||||
|
map.addInteraction(figureSelect)
|
||||||
|
map.addInteraction(figureHover)
|
||||||
|
|
||||||
|
// map.on('pointermove', function (e: MapBrowserEvent<UIEvent>) {
|
||||||
|
// setCurrentCoordinate(id, e.coordinate)
|
||||||
|
// const currentExtent = get('EPSG:3857')?.getExtent() as Extent
|
||||||
|
// const { tileX, tileY } = getGridCellPosition(e.coordinate[0], e.coordinate[1], currentExtent, Number(map?.getView().getZoom()?.toFixed(0)))
|
||||||
|
// setCurrentZ(id, Number(map?.getView().getZoom()?.toFixed(0)))
|
||||||
|
// setCurrentX(id, tileX)
|
||||||
|
// setCurrentY(id, tileY)
|
||||||
|
|
||||||
|
// const pixel = map?.getEventPixel(e.originalEvent)
|
||||||
|
// if (pixel) {
|
||||||
|
// map?.forEachFeatureAtPixel(pixel, function (feature, layer) {
|
||||||
|
// if (layer.get('type') === 'region') {
|
||||||
|
// if (feature.get('entity_id')) {
|
||||||
|
// setStatusText(id, feature.get('entity_id'))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
|
map.on('click', function (e: MapBrowserEvent<UIEvent>) {
|
||||||
|
if (getAlignMode(id)) {
|
||||||
|
const alignPoints = getAlignPoints(id)
|
||||||
|
const alignModeLayer = getAlignModeLayer(id)
|
||||||
|
if (alignPoints.length < 4) {
|
||||||
|
//setAlignPoints(id, [...alignPoints, e.coordinate])
|
||||||
|
alignPoints.push(e.coordinate)
|
||||||
|
alignModeLayer.getSource()?.addFeature(new Feature(new Point(e.coordinate)))
|
||||||
|
if (alignPoints.length === 4) {
|
||||||
|
const transformations = calculateTransformations(alignPoints);
|
||||||
|
// Use the first map point (P3) as the origin for scaling and rotation
|
||||||
|
const origin = alignPoints[2];
|
||||||
|
applyTransformations(getFiguresLayer(id), transformations, origin);
|
||||||
|
applyTransformations(getLinesLayer(id), transformations, origin);
|
||||||
|
|
||||||
|
setAlignPoints(id, [])
|
||||||
|
alignModeLayer.getSource()?.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const pixel = map?.getEventPixel(e.originalEvent)
|
||||||
|
|
||||||
|
if (pixel) {
|
||||||
|
map?.forEachFeatureAtPixel(pixel, function (feature, layer) {
|
||||||
|
if (layer) {
|
||||||
|
if (layer.get('type') === 'region') {
|
||||||
|
zoomToFeature(id, feature as Feature)
|
||||||
|
|
||||||
|
if (feature.get('entity_id')) {
|
||||||
|
setSelectedRegion(id, feature.get('entity_id'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
map.on('moveend', function () {
|
||||||
|
const viewExtent = map?.getView().calculateExtent(map.getSize())
|
||||||
|
const features = regionsLayer.getSource()?.getFeatures()
|
||||||
|
|
||||||
|
let isViewCovered = false
|
||||||
|
|
||||||
|
features?.forEach((feature: Feature) => {
|
||||||
|
const featureExtent = feature?.getGeometry()?.getExtent()
|
||||||
|
if (viewExtent && featureExtent) {
|
||||||
|
if (containsExtent(featureExtent, viewExtent)) {
|
||||||
|
isViewCovered = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
regionsLayer.setVisible(!isViewCovered)
|
||||||
|
})
|
||||||
|
|
||||||
|
map.setView(
|
||||||
|
new View({
|
||||||
|
center: transform([129.7466541, 62.083504], 'EPSG:4326', 'EPSG:3857'),//center: fromLonLat([130.401113, 67.797368]),
|
||||||
|
zoom: 5,
|
||||||
|
maxZoom: 21,
|
||||||
|
//extent: mapExtent,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: {
|
||||||
|
currentTool: null,
|
||||||
|
measureType: "LineString",
|
||||||
|
measureShowSegments: true,
|
||||||
|
measureClearPrevious: true,
|
||||||
|
tipPoint: null,
|
||||||
|
map: map,
|
||||||
|
currentZ: undefined,
|
||||||
|
currentX: undefined,
|
||||||
|
currentY: undefined,
|
||||||
|
currentCoordinate: null,
|
||||||
|
statusText: '',
|
||||||
|
satMapsProvider: 'google',
|
||||||
|
selectedObjectType: null,
|
||||||
|
alignMode: false,
|
||||||
|
mode: 'view',
|
||||||
|
typeRoles: null,
|
||||||
|
mapLabel: 'Карта',
|
||||||
|
file: null,
|
||||||
|
measureSource: measureSource,
|
||||||
|
measureDraw: null,
|
||||||
|
polygonExtent: undefined,
|
||||||
|
rectCoords: undefined,
|
||||||
|
alignPoints: [],
|
||||||
|
alignModeLayer: alignModeLayer,
|
||||||
|
drawingLayer: drawingLayer,
|
||||||
|
drawingLayerSource: drawingLayerSource,
|
||||||
|
draw: null,
|
||||||
|
snap: null,
|
||||||
|
translate: null,
|
||||||
|
overlayLayerSource: overlayLayerSource,
|
||||||
|
satLayer: satLayer,
|
||||||
|
nodeLayerSource: nodeLayerSource,
|
||||||
|
staticMapLayer: staticMapLayer,
|
||||||
|
figuresLayer: figuresLayer,
|
||||||
|
linesLayer: linesLayer,
|
||||||
|
regionsLayer: regionsLayer,
|
||||||
|
citiesLayer: citiesLayer,
|
||||||
|
districtBoundLayer: districtBoundLayer,
|
||||||
|
imageLayer: imageLayer,
|
||||||
|
selectedArea: null,
|
||||||
|
baseLayer: baseLayer,
|
||||||
|
measureLayer: measureLayer,
|
||||||
|
measureModify: measureModify,
|
||||||
|
nodeLayer: nodeLayer,
|
||||||
|
overlayLayer: overlayLayer,
|
||||||
|
regionSelect: regionSelect,
|
||||||
|
lineSelect: lineSelect,
|
||||||
|
previousView: null,
|
||||||
|
printArea: null,
|
||||||
|
printLayer: printLayer,
|
||||||
|
printSource: printSource,
|
||||||
|
printAreaDraw: printAreaDraw,
|
||||||
|
printPreviewSize: [640, 320],
|
||||||
|
printDim: 'a4',
|
||||||
|
printOrientation: 'horizontal',
|
||||||
|
printRes: 72,
|
||||||
|
printScale: '250',
|
||||||
|
printScaleLine: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const getTipPoint = () => {
|
export const setPrintOrientation = (id: string, orientation: PrintOrientation) => useMapStore.setState((state) => {
|
||||||
return useMapStore.getState().tipPoint
|
return {
|
||||||
}
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], printOrientation: orientation }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const getMap = () => {
|
export const setPrintScaleLine = (id: string, bool: boolean) => useMapStore.setState((state) => {
|
||||||
return useMapStore.getState().map
|
return {
|
||||||
}
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], printScaleLine: bool }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const setMeasureType = (tool: "LineString" | "Polygon") => {
|
export const setPrintScale = (id: string, printScale: PrintScale) => useMapStore.setState((state) => {
|
||||||
useMapStore.setState(() => ({ measureType: tool }))
|
return {
|
||||||
}
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], printScale: printScale }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const getMeasureType = () => {
|
export const setPreviousView = (id: string, view: View | undefined | null) => useMapStore.setState((state) => {
|
||||||
return useMapStore.getState().measureType
|
return {
|
||||||
}
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], previousView: view }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const setCurrentTool = (tool: ToolType) => {
|
export const clearPrintArea = (id: string) => useMapStore.setState((state) => {
|
||||||
tool === useMapStore.getState().currentTool
|
state.id[id].printSource.clear()
|
||||||
? useMapStore.setState(() => ({ currentTool: null }))
|
|
||||||
: useMapStore.setState(() => ({ currentTool: tool }))
|
|
||||||
}
|
|
||||||
|
|
||||||
const getCurrentTool = () => {
|
return {
|
||||||
return useMapStore.getState().currentTool
|
id: {
|
||||||
}
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], printArea: null }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const getMeasureShowSegments = () => {
|
export const setPrintArea = (id: string, extent: Extent | null) => useMapStore.setState((state) => {
|
||||||
return useMapStore.getState().measureShowSegments
|
return {
|
||||||
}
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], printArea: extent }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const getMeasureClearPrevious = () => {
|
export const getFiguresLayer = (id: string) => useMapStore.getState().id[id].figuresLayer
|
||||||
return useMapStore.getState().measureClearPrevious
|
export const getLinesLayer = (id: string) => useMapStore.getState().id[id].linesLayer
|
||||||
}
|
export const getMeasureModify = (id: string) => useMapStore.getState().id[id].measureModify
|
||||||
|
|
||||||
const setMeasureShowSegments = (bool: boolean) => {
|
export const getOverlayLayerSource = (id: string) => useMapStore.getState().id[id].overlayLayerSource
|
||||||
useMapStore.setState(() => ({ measureShowSegments: bool }))
|
export const setOverlayLayerSource = (id: string, source: VectorSource) => useMapStore.setState((state) => {
|
||||||
}
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], overlayLayerSource: source }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const setMeasureClearPrevious = (bool: boolean) => {
|
export const getImageLayer = (id: string) => useMapStore.getState().id[id].imageLayer
|
||||||
useMapStore.setState(() => ({ measureClearPrevious: bool }))
|
export const setImageLayer = (id: string, layer: ImageLayer<ImageStatic>) => useMapStore.setState((state) => {
|
||||||
}
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], imageLayer: layer }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
export {
|
export const getTranslate = (id: string) => useMapStore.getState().id[id].translate
|
||||||
setCurrentTool,
|
export const setTranslate = (id: string, translate: Translate | null) => useMapStore.setState((state) => {
|
||||||
getCurrentTool,
|
return {
|
||||||
setMeasureShowSegments,
|
id: {
|
||||||
setMeasureClearPrevious,
|
...state.id,
|
||||||
getMeasureShowSegments,
|
[id]: { ...state.id[id], translate: translate }
|
||||||
getMeasureClearPrevious,
|
}
|
||||||
setMeasureType,
|
}
|
||||||
getMeasureType,
|
})
|
||||||
getTipPoint,
|
|
||||||
setTipPoint,
|
export const getSnap = (id: string) => useMapStore.getState().id[id].snap
|
||||||
setCurrentZ,
|
export const setSnap = (id: string, snap: Snap | null) => useMapStore.setState((state) => {
|
||||||
setCurrentX,
|
return {
|
||||||
setCurrentY,
|
id: {
|
||||||
setCurrentCoordinate,
|
...state.id,
|
||||||
setStatusText,
|
[id]: { ...state.id[id], snap: snap }
|
||||||
setSatMapsProvider,
|
}
|
||||||
setSelectedObjectType,
|
}
|
||||||
setMap,
|
})
|
||||||
getMap
|
|
||||||
}
|
export const getDraw = (id: string) => useMapStore.getState().id[id].draw
|
||||||
|
export const setDraw = (id: string, draw: Draw | null) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], draw: draw }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getDrawingLayerSource = (id: string) => useMapStore.getState().id[id].drawingLayerSource
|
||||||
|
export const getMeasureSource = (id: string) => useMapStore.getState().id[id].measureSource
|
||||||
|
export const getMeasureDraw = (id: string) => useMapStore.getState().id[id].measureDraw
|
||||||
|
|
||||||
|
export const setMeasureDraw = (id: string, draw: Draw) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], measureDraw: draw }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const setAlignPoints = (id: string, c: Coordinate[]) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], alignPoints: c }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const setRectCoords = (id: string, c: IRectCoords | undefined) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], rectCoords: c }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const setPolygonExtent = (id: string, extent: Extent | undefined) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], polygonExtent: extent }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const setFile = (id: string, file: File | null) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], file: file }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const setMapLabel = (id: string, label: string) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], mapLabel: label }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const setCurrentZ = (id: string, z: number | undefined) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], currentZ: z }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const setCurrentX = (id: string, x: number | undefined) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], currentX: x }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const setCurrentY = (id: string, y: number | undefined) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], currentY: y }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const setCurrentCoordinate = (id: string, c: Coordinate | null) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], currentCoordinate: c }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const setStatusText = (id: string, t: string) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], statusText: t }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const setSatMapsProvider = (id: string, p: SatelliteMapsProvider) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], satMapsProvider: p }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const setSelectedObjectType = (id: string, t: number | null) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], selectedObjectType: t }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const setMap = (id: string, m: Map | null) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], map: m }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const setAlignMode = (id: string, m: boolean) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], alignMode: m }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const setTipPoint = (id: string, tipPoint: Point | null) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], tipPoint: tipPoint }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getTipPoint = (id: string) => useMapStore.getState().id[id].tipPoint
|
||||||
|
|
||||||
|
export const getAlignMode = (id: string) => useMapStore.getState().id[id].alignMode
|
||||||
|
|
||||||
|
export const getAlignModeLayer = (id: string) => useMapStore.getState().id[id].alignModeLayer
|
||||||
|
|
||||||
|
export const getAlignPoints = (id: string) => useMapStore.getState().id[id].alignPoints
|
||||||
|
|
||||||
|
export const getMap = (id: string) => useMapStore.getState().id[id].map
|
||||||
|
|
||||||
|
export const setMeasureType = (id: string, tool: "LineString" | "Polygon") => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], measureType: tool }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getMeasureType = (id: string) => useMapStore.getState().id[id].measureType
|
||||||
|
|
||||||
|
export const setCurrentTool = (id: string, tool: ToolType) =>
|
||||||
|
tool === useMapStore.getState().id[id].currentTool
|
||||||
|
? useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], currentTool: null }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
: useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], currentTool: tool }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getCurrentTool = (id: string) => useMapStore.getState().id[id].currentTool
|
||||||
|
|
||||||
|
export const getMeasureShowSegments = (id: string) => useMapStore.getState().id[id].measureShowSegments
|
||||||
|
|
||||||
|
export const getMeasureClearPrevious = (id: string) => useMapStore.getState().id[id].measureClearPrevious
|
||||||
|
|
||||||
|
export const setMeasureShowSegments = (id: string, bool: boolean) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], measureShowSegments: bool }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const setMeasureClearPrevious = (id: string, bool: boolean) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], measureClearPrevious: bool }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getMode = (id: string) => useMapStore.getState().id[id].mode
|
||||||
|
export const setMode = (id: string, mode: Mode) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], mode: mode }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getTypeRoles = (id: string) => useMapStore.getState().id[id].typeRoles
|
||||||
|
export const setTypeRoles = (id: string, typeRoles: TypeRole[] | null) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], typeRoles: typeRoles }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@ -1,60 +1,87 @@
|
|||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
|
|
||||||
interface ObjectsState {
|
interface ObjectsState {
|
||||||
selectedRegion: number | null;
|
id: Record<string, {
|
||||||
selectedDistrict: number | null;
|
selectedRegion: number | null;
|
||||||
selectedCity: number | null;
|
selectedDistrict: number | null;
|
||||||
selectedYear: number | null;
|
selectedCity: number | null;
|
||||||
currentObjectId: string | null;
|
selectedYear: number | null;
|
||||||
|
currentObjectId: string | null;
|
||||||
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useObjectsStore = create<ObjectsState>(() => ({
|
export const useObjectsStore = create<ObjectsState>(() => ({
|
||||||
selectedRegion: null,
|
id: {}
|
||||||
selectedDistrict: null,
|
|
||||||
selectedCity: null,
|
|
||||||
selectedYear: null,
|
|
||||||
currentObjectId: null
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const getSelectedCity = () => {
|
export const initializeObjectsState = (
|
||||||
return useObjectsStore.getState().selectedCity
|
id: string,
|
||||||
}
|
selectedRegion: number | null,
|
||||||
|
selectedDistrict: number | null,
|
||||||
|
selectedCity: number | null,
|
||||||
|
selectedYear: number | null,
|
||||||
|
) => useObjectsStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: {
|
||||||
|
selectedRegion: selectedRegion,
|
||||||
|
selectedDistrict: selectedDistrict,
|
||||||
|
selectedCity: selectedCity,
|
||||||
|
selectedYear: selectedYear,
|
||||||
|
currentObjectId: null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const setSelectedRegion = (region: number | null) => {
|
export const getSelectedCity = (id: string) => useObjectsStore.getState().id[id].selectedCity
|
||||||
useObjectsStore.setState(() => ({ selectedRegion: region }))
|
export const setSelectedCity = (id: string, city: number | null) => useObjectsStore.setState((state) => {
|
||||||
}
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], selectedCity: city }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const setSelectedDistrict = (district: number | null) => {
|
export const getSelectedRegion = (id: string) => useObjectsStore.getState().id[id].selectedRegion
|
||||||
useObjectsStore.setState(() => ({ selectedDistrict: district }))
|
export const setSelectedRegion = (id: string, region: number | null) => useObjectsStore.setState((state) => {
|
||||||
}
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], selectedRegion: region }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const setSelectedCity = (city: number | null) => {
|
export const getSelectedDistrict = (id: string) => useObjectsStore.getState().id[id].selectedDistrict
|
||||||
useObjectsStore.setState(() => ({ selectedCity: city }))
|
export const setSelectedDistrict = (id: string, district: number | null) => useObjectsStore.setState((state) => {
|
||||||
}
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], selectedDistrict: district }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const getSelectedYear = () => {
|
|
||||||
return useObjectsStore.getState().selectedYear
|
|
||||||
}
|
|
||||||
|
|
||||||
const setSelectedYear = (year: number | null) => {
|
export const getSelectedYear = (id: string) => useObjectsStore.getState().id[id].selectedYear
|
||||||
useObjectsStore.setState(() => ({ selectedYear: year }))
|
export const setSelectedYear = (id: string, year: number | null) => useObjectsStore.setState((state) => {
|
||||||
}
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], selectedYear: year }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const getCurrentObjectId = () => {
|
export const getCurrentObjectId = (id: string) => useObjectsStore.getState().id[id].currentObjectId
|
||||||
return useObjectsStore.getState().currentObjectId
|
export const setCurrentObjectId = (id: string, objectId: string | null) => useObjectsStore.setState((state) => {
|
||||||
}
|
return {
|
||||||
|
id: {
|
||||||
const setCurrentObjectId = (objectId: string | null) => {
|
...state.id,
|
||||||
useObjectsStore.setState(() => ({ currentObjectId: objectId }))
|
[id]: { ...state.id[id], currentObjectId: objectId }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
export {
|
})
|
||||||
getSelectedCity,
|
|
||||||
setSelectedCity,
|
|
||||||
getSelectedYear,
|
|
||||||
setSelectedYear,
|
|
||||||
getCurrentObjectId,
|
|
||||||
setCurrentObjectId,
|
|
||||||
setSelectedRegion,
|
|
||||||
setSelectedDistrict
|
|
||||||
}
|
|
||||||
23
client/src/store/print.ts
Normal file
23
client/src/store/print.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { create } from 'zustand';
|
||||||
|
|
||||||
|
export type PrintOrientation = 'horizontal' | 'vertical'
|
||||||
|
|
||||||
|
export type PrintFormat = 'a0' | 'a1' | 'a2' | 'a3' | 'a4' | 'a5'
|
||||||
|
export const printResolutions = ['72', '150', '200', '300']
|
||||||
|
|
||||||
|
export interface PrintState {
|
||||||
|
printFormat: PrintFormat;
|
||||||
|
printOrientation: PrintOrientation;
|
||||||
|
printResolution: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const usePrintStore = create<PrintState>(() => ({
|
||||||
|
printFormat: 'a4',
|
||||||
|
printOrientation: 'horizontal',
|
||||||
|
printResolution: 72
|
||||||
|
}))
|
||||||
|
|
||||||
|
export const getPrintOrientation = () => usePrintStore.getState().printOrientation
|
||||||
|
export const setPrintFormat = (format: PrintFormat) => usePrintStore.setState(() => ({ printFormat: format }))
|
||||||
|
export const setPrintOrientation = (orientation: PrintOrientation) => usePrintStore.setState(() => ({ printOrientation: orientation }))
|
||||||
|
export const setPrintResolution = (resolution: number) => usePrintStore.setState(() => ({ printResolution: resolution }))
|
||||||
@ -1,11 +1,13 @@
|
|||||||
import { defineConfig } from 'vite'
|
import { defineConfig, type PluginOption } from 'vite'
|
||||||
import react from '@vitejs/plugin-react-swc'
|
import react from '@vitejs/plugin-react-swc'
|
||||||
import { nodePolyfills } from 'vite-plugin-node-polyfills'
|
import { nodePolyfills } from 'vite-plugin-node-polyfills'
|
||||||
|
import { visualizer } from 'rollup-plugin-visualizer'
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
nodePolyfills(),
|
nodePolyfills(),
|
||||||
react(),
|
react(),
|
||||||
|
visualizer() as PluginOption
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|||||||
299
client/yarn.lock
299
client/yarn.lock
@ -936,10 +936,10 @@
|
|||||||
resolved "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz"
|
resolved "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz"
|
||||||
integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==
|
integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==
|
||||||
|
|
||||||
"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.0", "@babel/runtime@^7.20.13", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7":
|
"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.20.13", "@babel/runtime@^7.23.2", "@babel/runtime@^7.25.6", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7":
|
||||||
version "7.24.7"
|
version "7.26.0"
|
||||||
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz"
|
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz"
|
||||||
integrity sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==
|
integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==
|
||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime "^0.14.0"
|
regenerator-runtime "^0.14.0"
|
||||||
|
|
||||||
@ -982,6 +982,29 @@
|
|||||||
resolved "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.2.0.tgz"
|
resolved "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.2.0.tgz"
|
||||||
integrity sha512-+imAQkHf7U/Rwvu0wk1XWgsP3WnpCWmK7B48f0XqSNzgk64+grljTKC7pnO/xBiEMUziF7vKRfbBnOQhg126qQ==
|
integrity sha512-+imAQkHf7U/Rwvu0wk1XWgsP3WnpCWmK7B48f0XqSNzgk64+grljTKC7pnO/xBiEMUziF7vKRfbBnOQhg126qQ==
|
||||||
|
|
||||||
|
"@dnd-kit/accessibility@^3.1.1":
|
||||||
|
version "3.1.1"
|
||||||
|
resolved "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz"
|
||||||
|
integrity sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==
|
||||||
|
dependencies:
|
||||||
|
tslib "^2.0.0"
|
||||||
|
|
||||||
|
"@dnd-kit/core@^6.3.1":
|
||||||
|
version "6.3.1"
|
||||||
|
resolved "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz"
|
||||||
|
integrity sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==
|
||||||
|
dependencies:
|
||||||
|
"@dnd-kit/accessibility" "^3.1.1"
|
||||||
|
"@dnd-kit/utilities" "^3.2.2"
|
||||||
|
tslib "^2.0.0"
|
||||||
|
|
||||||
|
"@dnd-kit/utilities@^3.2.2":
|
||||||
|
version "3.2.2"
|
||||||
|
resolved "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz"
|
||||||
|
integrity sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==
|
||||||
|
dependencies:
|
||||||
|
tslib "^2.0.0"
|
||||||
|
|
||||||
"@esbuild/win32-x64@0.21.5":
|
"@esbuild/win32-x64@0.21.5":
|
||||||
version "0.21.5"
|
version "0.21.5"
|
||||||
resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz"
|
resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz"
|
||||||
@ -1065,6 +1088,19 @@
|
|||||||
resolved "https://registry.npmjs.org/@fontsource/open-sans/-/open-sans-5.0.28.tgz"
|
resolved "https://registry.npmjs.org/@fontsource/open-sans/-/open-sans-5.0.28.tgz"
|
||||||
integrity sha512-hBvJHY76pJT/JynGUB5EXWhnzjYfLdcMn655J5p1v9lTT9HdQSy+keq2KPVXO2Htlg998BBa3p6u/jlrZ6w0kg==
|
integrity sha512-hBvJHY76pJT/JynGUB5EXWhnzjYfLdcMn655J5p1v9lTT9HdQSy+keq2KPVXO2Htlg998BBa3p6u/jlrZ6w0kg==
|
||||||
|
|
||||||
|
"@hello-pangea/dnd@^17.0.0":
|
||||||
|
version "17.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/@hello-pangea/dnd/-/dnd-17.0.0.tgz"
|
||||||
|
integrity sha512-LDDPOix/5N0j5QZxubiW9T0M0+1PR0rTDWeZF5pu1Tz91UQnuVK4qQ/EjY83Qm2QeX0eM8qDXANfDh3VVqtR4Q==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.25.6"
|
||||||
|
css-box-model "^1.2.1"
|
||||||
|
memoize-one "^6.0.0"
|
||||||
|
raf-schd "^4.0.3"
|
||||||
|
react-redux "^9.1.2"
|
||||||
|
redux "^5.0.1"
|
||||||
|
use-memo-one "^1.1.3"
|
||||||
|
|
||||||
"@humanwhocodes/config-array@^0.11.14":
|
"@humanwhocodes/config-array@^0.11.14":
|
||||||
version "0.11.14"
|
version "0.11.14"
|
||||||
resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz"
|
resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz"
|
||||||
@ -1430,6 +1466,11 @@
|
|||||||
resolved "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.20.5.tgz"
|
resolved "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.20.5.tgz"
|
||||||
integrity sha512-P9dF7XbibHph2PFRz8gfBKEXEY/HJPOhym8CHmjF8y3q5mWpKx9xtZapXQUWCgkqvsK0R46Azuz+VaxD4Xl+Tg==
|
integrity sha512-P9dF7XbibHph2PFRz8gfBKEXEY/HJPOhym8CHmjF8y3q5mWpKx9xtZapXQUWCgkqvsK0R46Azuz+VaxD4Xl+Tg==
|
||||||
|
|
||||||
|
"@techstark/opencv-js@^4.10.0-release.1":
|
||||||
|
version "4.10.0-release.1"
|
||||||
|
resolved "https://registry.npmjs.org/@techstark/opencv-js/-/opencv-js-4.10.0-release.1.tgz"
|
||||||
|
integrity sha512-S4XELidRiQeA0q1s9VQLo540wCxUo24r1O4C+LqZ6llX+sPCXvZCPv3Ice8dEIr0uavyZ8YZeKXSBdDgMXSXjw==
|
||||||
|
|
||||||
"@tiptap/core@^2.7.0", "@tiptap/core@^2.7.3":
|
"@tiptap/core@^2.7.0", "@tiptap/core@^2.7.3":
|
||||||
version "2.7.3"
|
version "2.7.3"
|
||||||
resolved "https://registry.npmjs.org/@tiptap/core/-/core-2.7.3.tgz"
|
resolved "https://registry.npmjs.org/@tiptap/core/-/core-2.7.3.tgz"
|
||||||
@ -1707,7 +1748,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
|
|
||||||
"@types/react@*", "@types/react@^16.8.0 || ^17.0.0 || ^18.0.0", "@types/react@^16.9.0 || ^17.0.0 || ^18.0.0", "@types/react@^18.2.66", "@types/react@>=16.8":
|
"@types/react@*", "@types/react@^16.8.0 || ^17.0.0 || ^18.0.0", "@types/react@^16.9.0 || ^17.0.0 || ^18.0.0", "@types/react@^18.2.25 || ^19", "@types/react@^18.2.66", "@types/react@>=16.8":
|
||||||
version "18.3.3"
|
version "18.3.3"
|
||||||
resolved "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz"
|
resolved "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz"
|
||||||
integrity sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==
|
integrity sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==
|
||||||
@ -1851,6 +1892,26 @@ acorn-jsx@^5.3.2:
|
|||||||
resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz"
|
resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz"
|
||||||
integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==
|
integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==
|
||||||
|
|
||||||
|
ag-charts-types@11.3.2:
|
||||||
|
version "11.3.2"
|
||||||
|
resolved "https://registry.npmjs.org/ag-charts-types/-/ag-charts-types-11.3.2.tgz"
|
||||||
|
integrity sha512-trPGqgGYiTeLgtf9nLuztDYOPOFOLbqHn1g2D99phf7QowcwdX0TPx0wfWG8Hm90LjB8IH+G2s3AZe2vrdAtMQ==
|
||||||
|
|
||||||
|
ag-grid-community@33.3.2:
|
||||||
|
version "33.3.2"
|
||||||
|
resolved "https://registry.npmjs.org/ag-grid-community/-/ag-grid-community-33.3.2.tgz"
|
||||||
|
integrity sha512-9bx0e/+ykOyLvUxHqmdy0cRVANH6JAtv0yZdnBZEXYYqBAwN+G5a4NY+2I1KvoOCYzbk8SnStG7y4hCdVAAWOQ==
|
||||||
|
dependencies:
|
||||||
|
ag-charts-types "11.3.2"
|
||||||
|
|
||||||
|
ag-grid-react@^33.3.2:
|
||||||
|
version "33.3.2"
|
||||||
|
resolved "https://registry.npmjs.org/ag-grid-react/-/ag-grid-react-33.3.2.tgz"
|
||||||
|
integrity sha512-5bv4JIJvGov23sduIUIyQTqpa/qhoQrRkQm5pFOQb7RMwusfx6xBPrkLwIIlCJiQ8g0OOinxWzZ2kQ2Zml6tLw==
|
||||||
|
dependencies:
|
||||||
|
ag-grid-community "33.3.2"
|
||||||
|
prop-types "^15.8.1"
|
||||||
|
|
||||||
ajv@^6.12.4:
|
ajv@^6.12.4:
|
||||||
version "6.12.6"
|
version "6.12.6"
|
||||||
resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz"
|
resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz"
|
||||||
@ -2396,6 +2457,15 @@ clipboardy@3.0.0:
|
|||||||
execa "^5.1.1"
|
execa "^5.1.1"
|
||||||
is-wsl "^2.2.0"
|
is-wsl "^2.2.0"
|
||||||
|
|
||||||
|
cliui@^8.0.1:
|
||||||
|
version "8.0.1"
|
||||||
|
resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz"
|
||||||
|
integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
|
||||||
|
dependencies:
|
||||||
|
string-width "^4.2.0"
|
||||||
|
strip-ansi "^6.0.1"
|
||||||
|
wrap-ansi "^7.0.0"
|
||||||
|
|
||||||
clsx@^2.0.0, clsx@^2.1.1:
|
clsx@^2.0.0, clsx@^2.1.1:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz"
|
resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz"
|
||||||
@ -2611,6 +2681,13 @@ crypto-random-string@^2.0.0:
|
|||||||
resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz"
|
resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz"
|
||||||
integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
|
integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
|
||||||
|
|
||||||
|
css-box-model@^1.2.1:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz"
|
||||||
|
integrity sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==
|
||||||
|
dependencies:
|
||||||
|
tiny-invariant "^1.0.6"
|
||||||
|
|
||||||
css-line-break@^2.1.0:
|
css-line-break@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz"
|
resolved "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz"
|
||||||
@ -2774,6 +2851,11 @@ define-data-property@^1.0.1, define-data-property@^1.1.4:
|
|||||||
es-errors "^1.3.0"
|
es-errors "^1.3.0"
|
||||||
gopd "^1.0.1"
|
gopd "^1.0.1"
|
||||||
|
|
||||||
|
define-lazy-prop@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz"
|
||||||
|
integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==
|
||||||
|
|
||||||
define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1:
|
define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz"
|
resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz"
|
||||||
@ -2834,6 +2916,14 @@ doctrine@^3.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
esutils "^2.0.2"
|
esutils "^2.0.2"
|
||||||
|
|
||||||
|
docx-templates@^4.13.0:
|
||||||
|
version "4.13.0"
|
||||||
|
resolved "https://registry.npmjs.org/docx-templates/-/docx-templates-4.13.0.tgz"
|
||||||
|
integrity sha512-tTmR3WhROYctuyVReQ+PfCU3zprmC45/VuSVzn8EjovzpRkXYUdXiDatB9M8pasj0V+wuuOyY8bcSHvlQ2GNag==
|
||||||
|
dependencies:
|
||||||
|
jszip "^3.10.1"
|
||||||
|
sax "1.3.0"
|
||||||
|
|
||||||
dom-helpers@^5.0.1:
|
dom-helpers@^5.0.1:
|
||||||
version "5.2.1"
|
version "5.2.1"
|
||||||
resolved "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz"
|
resolved "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz"
|
||||||
@ -2847,7 +2937,7 @@ domain-browser@^4.22.0:
|
|||||||
resolved "https://registry.npmjs.org/domain-browser/-/domain-browser-4.23.0.tgz"
|
resolved "https://registry.npmjs.org/domain-browser/-/domain-browser-4.23.0.tgz"
|
||||||
integrity sha512-ArzcM/II1wCCujdCNyQjXrAFwS4mrLh4C7DZWlaI8mdh7h3BfKdNd3bKXITfl2PT9FtfQqaGvhi1vPRQPimjGA==
|
integrity sha512-ArzcM/II1wCCujdCNyQjXrAFwS4mrLh4C7DZWlaI8mdh7h3BfKdNd3bKXITfl2PT9FtfQqaGvhi1vPRQPimjGA==
|
||||||
|
|
||||||
dompurify@^2.2.0:
|
dompurify@^2.5.4:
|
||||||
version "2.5.6"
|
version "2.5.6"
|
||||||
resolved "https://registry.npmjs.org/dompurify/-/dompurify-2.5.6.tgz"
|
resolved "https://registry.npmjs.org/dompurify/-/dompurify-2.5.6.tgz"
|
||||||
integrity sha512-zUTaUBO8pY4+iJMPE1B9XlO2tXVYIcEA4SNGtvDELzTSCQO7RzH+j7S180BmhmJId78lqGU2z19vgVx2Sxs/PQ==
|
integrity sha512-zUTaUBO8pY4+iJMPE1B9XlO2tXVYIcEA4SNGtvDELzTSCQO7RzH+j7S180BmhmJId78lqGU2z19vgVx2Sxs/PQ==
|
||||||
@ -3038,7 +3128,7 @@ esbuild@^0.21.3:
|
|||||||
"@esbuild/win32-ia32" "0.21.5"
|
"@esbuild/win32-ia32" "0.21.5"
|
||||||
"@esbuild/win32-x64" "0.21.5"
|
"@esbuild/win32-x64" "0.21.5"
|
||||||
|
|
||||||
escalade@^3.1.2:
|
escalade@^3.1.1, escalade@^3.1.2:
|
||||||
version "3.1.2"
|
version "3.1.2"
|
||||||
resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz"
|
resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz"
|
||||||
integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
|
integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
|
||||||
@ -3241,10 +3331,10 @@ fastq@^1.6.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
reusify "^1.0.4"
|
reusify "^1.0.4"
|
||||||
|
|
||||||
fflate@^0.4.8:
|
fflate@^0.8.1:
|
||||||
version "0.4.8"
|
version "0.8.2"
|
||||||
resolved "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz"
|
resolved "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz"
|
||||||
integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==
|
integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==
|
||||||
|
|
||||||
file-entry-cache@^6.0.1:
|
file-entry-cache@^6.0.1:
|
||||||
version "6.0.1"
|
version "6.0.1"
|
||||||
@ -3386,6 +3476,11 @@ geotiff@^2.0.7:
|
|||||||
xml-utils "^1.0.2"
|
xml-utils "^1.0.2"
|
||||||
zstddec "^0.1.0"
|
zstddec "^0.1.0"
|
||||||
|
|
||||||
|
get-caller-file@^2.0.5:
|
||||||
|
version "2.0.5"
|
||||||
|
resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz"
|
||||||
|
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
|
||||||
|
|
||||||
get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4:
|
get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4:
|
||||||
version "1.2.4"
|
version "1.2.4"
|
||||||
resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz"
|
resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz"
|
||||||
@ -3590,7 +3685,7 @@ hmac-drbg@^1.0.1:
|
|||||||
minimalistic-assert "^1.0.0"
|
minimalistic-assert "^1.0.0"
|
||||||
minimalistic-crypto-utils "^1.0.1"
|
minimalistic-crypto-utils "^1.0.1"
|
||||||
|
|
||||||
html2canvas@^1.0.0-rc.5:
|
html2canvas@^1.0.0-rc.5, html2canvas@^1.4.1:
|
||||||
version "1.4.1"
|
version "1.4.1"
|
||||||
resolved "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz"
|
resolved "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz"
|
||||||
integrity sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==
|
integrity sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==
|
||||||
@ -3623,6 +3718,11 @@ ignore@^5.2.0, ignore@^5.3.1:
|
|||||||
resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz"
|
resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz"
|
||||||
integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==
|
integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==
|
||||||
|
|
||||||
|
immediate@~3.0.5:
|
||||||
|
version "3.0.6"
|
||||||
|
resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz"
|
||||||
|
integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==
|
||||||
|
|
||||||
immutable@^4.0.0:
|
immutable@^4.0.0:
|
||||||
version "4.3.7"
|
version "4.3.7"
|
||||||
resolved "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz"
|
resolved "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz"
|
||||||
@ -3751,7 +3851,7 @@ is-date-object@^1.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
has-tostringtag "^1.0.0"
|
has-tostringtag "^1.0.0"
|
||||||
|
|
||||||
is-docker@^2.0.0:
|
is-docker@^2.0.0, is-docker@^2.1.1:
|
||||||
version "2.2.1"
|
version "2.2.1"
|
||||||
resolved "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz"
|
resolved "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz"
|
||||||
integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==
|
integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==
|
||||||
@ -3995,21 +4095,31 @@ jsonpointer@^5.0.0:
|
|||||||
resolved "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz"
|
resolved "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz"
|
||||||
integrity sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==
|
integrity sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==
|
||||||
|
|
||||||
jspdf@^2.5.1:
|
jspdf@^2.5.1, jspdf@^2.5.2:
|
||||||
version "2.5.1"
|
version "2.5.2"
|
||||||
resolved "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz"
|
resolved "https://registry.npmjs.org/jspdf/-/jspdf-2.5.2.tgz"
|
||||||
integrity sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==
|
integrity sha512-myeX9c+p7znDWPk0eTrujCzNjT+CXdXyk7YmJq5nD5V7uLLKmSXnlQ/Jn/kuo3X09Op70Apm0rQSnFWyGK8uEQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.14.0"
|
"@babel/runtime" "^7.23.2"
|
||||||
atob "^2.1.2"
|
atob "^2.1.2"
|
||||||
btoa "^1.2.1"
|
btoa "^1.2.1"
|
||||||
fflate "^0.4.8"
|
fflate "^0.8.1"
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
canvg "^3.0.6"
|
canvg "^3.0.6"
|
||||||
core-js "^3.6.0"
|
core-js "^3.6.0"
|
||||||
dompurify "^2.2.0"
|
dompurify "^2.5.4"
|
||||||
html2canvas "^1.0.0-rc.5"
|
html2canvas "^1.0.0-rc.5"
|
||||||
|
|
||||||
|
jszip@^3.10.1:
|
||||||
|
version "3.10.1"
|
||||||
|
resolved "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz"
|
||||||
|
integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==
|
||||||
|
dependencies:
|
||||||
|
lie "~3.3.0"
|
||||||
|
pako "~1.0.2"
|
||||||
|
readable-stream "~2.3.6"
|
||||||
|
setimmediate "^1.0.5"
|
||||||
|
|
||||||
keyv@^4.5.3:
|
keyv@^4.5.3:
|
||||||
version "4.5.4"
|
version "4.5.4"
|
||||||
resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz"
|
resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz"
|
||||||
@ -4040,6 +4150,13 @@ levn@^0.4.1:
|
|||||||
prelude-ls "^1.2.1"
|
prelude-ls "^1.2.1"
|
||||||
type-check "~0.4.0"
|
type-check "~0.4.0"
|
||||||
|
|
||||||
|
lie@~3.3.0:
|
||||||
|
version "3.3.0"
|
||||||
|
resolved "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz"
|
||||||
|
integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==
|
||||||
|
dependencies:
|
||||||
|
immediate "~3.0.5"
|
||||||
|
|
||||||
lilconfig@^2.1.0:
|
lilconfig@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz"
|
resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz"
|
||||||
@ -4153,6 +4270,11 @@ mdurl@^2.0.0:
|
|||||||
resolved "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz"
|
resolved "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz"
|
||||||
integrity sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==
|
integrity sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==
|
||||||
|
|
||||||
|
memoize-one@^6.0.0:
|
||||||
|
version "6.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz"
|
||||||
|
integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==
|
||||||
|
|
||||||
merge-stream@^2.0.0:
|
merge-stream@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz"
|
resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz"
|
||||||
@ -4438,6 +4560,15 @@ onetime@^5.1.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
mimic-fn "^2.1.0"
|
mimic-fn "^2.1.0"
|
||||||
|
|
||||||
|
open@^8.4.0:
|
||||||
|
version "8.4.2"
|
||||||
|
resolved "https://registry.npmjs.org/open/-/open-8.4.2.tgz"
|
||||||
|
integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==
|
||||||
|
dependencies:
|
||||||
|
define-lazy-prop "^2.0.0"
|
||||||
|
is-docker "^2.1.1"
|
||||||
|
is-wsl "^2.2.0"
|
||||||
|
|
||||||
optionator@^0.9.3:
|
optionator@^0.9.3:
|
||||||
version "0.9.4"
|
version "0.9.4"
|
||||||
resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz"
|
resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz"
|
||||||
@ -4479,7 +4610,7 @@ pako@^2.0.4:
|
|||||||
resolved "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz"
|
resolved "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz"
|
||||||
integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==
|
integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==
|
||||||
|
|
||||||
pako@~1.0.5:
|
pako@~1.0.2, pako@~1.0.5:
|
||||||
version "1.0.11"
|
version "1.0.11"
|
||||||
resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz"
|
resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz"
|
||||||
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
|
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
|
||||||
@ -4956,6 +5087,11 @@ quickselect@^2.0.0:
|
|||||||
resolved "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz"
|
resolved "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz"
|
||||||
integrity sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==
|
integrity sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==
|
||||||
|
|
||||||
|
raf-schd@^4.0.3:
|
||||||
|
version "4.0.3"
|
||||||
|
resolved "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz"
|
||||||
|
integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==
|
||||||
|
|
||||||
raf@^3.4.1:
|
raf@^3.4.1:
|
||||||
version "3.4.1"
|
version "3.4.1"
|
||||||
resolved "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz"
|
resolved "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz"
|
||||||
@ -5000,7 +5136,7 @@ rc@^1.0.1, rc@^1.1.6:
|
|||||||
minimist "^1.2.0"
|
minimist "^1.2.0"
|
||||||
strip-json-comments "~2.0.1"
|
strip-json-comments "~2.0.1"
|
||||||
|
|
||||||
"react-dom@^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom@^17.0.0 || ^18.0.0", react-dom@^18.2.0, react-dom@>=16.6.0, react-dom@>=16.8, react-dom@>=16.8.0, react-dom@>=18.0.0:
|
"react-dom@^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^17.0.0 || ^18.0.0", react-dom@^18.0.0, react-dom@^18.2.0, react-dom@>=16.6.0, react-dom@>=16.8, react-dom@>=16.8.0, react-dom@>=18.0.0:
|
||||||
version "18.3.1"
|
version "18.3.1"
|
||||||
resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz"
|
resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz"
|
||||||
integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==
|
integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==
|
||||||
@ -5035,6 +5171,14 @@ react-number-format@^5.3.1:
|
|||||||
resolved "https://registry.npmjs.org/react-number-format/-/react-number-format-5.4.2.tgz"
|
resolved "https://registry.npmjs.org/react-number-format/-/react-number-format-5.4.2.tgz"
|
||||||
integrity sha512-cg//jVdS49PYDgmcYoBnMMHl4XNTMuV723ZnHD2aXYtWWWqbVF3hjQ8iB+UZEuXapLbeA8P8H+1o6ZB1lcw3vg==
|
integrity sha512-cg//jVdS49PYDgmcYoBnMMHl4XNTMuV723ZnHD2aXYtWWWqbVF3hjQ8iB+UZEuXapLbeA8P8H+1o6ZB1lcw3vg==
|
||||||
|
|
||||||
|
react-redux@^9.1.2:
|
||||||
|
version "9.2.0"
|
||||||
|
resolved "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz"
|
||||||
|
integrity sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==
|
||||||
|
dependencies:
|
||||||
|
"@types/use-sync-external-store" "^0.0.6"
|
||||||
|
use-sync-external-store "^1.4.0"
|
||||||
|
|
||||||
react-remove-scroll-bar@^2.3.6:
|
react-remove-scroll-bar@^2.3.6:
|
||||||
version "2.3.6"
|
version "2.3.6"
|
||||||
resolved "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz"
|
resolved "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz"
|
||||||
@ -5106,7 +5250,7 @@ react-transition-group@^4.4.5, react-transition-group@4.4.5:
|
|||||||
loose-envify "^1.4.0"
|
loose-envify "^1.4.0"
|
||||||
prop-types "^15.6.2"
|
prop-types "^15.6.2"
|
||||||
|
|
||||||
"react@^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.11.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17 || ^18 || ^19", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.1 || ^18.0.0", "react@^17.0.0 || ^18.0.0", react@^18.2.0, react@^18.3.1, "react@>= 16", "react@>= 16.8 || 18.0.0", react@>=16.6.0, react@>=16.8, react@>=16.8.0, react@>=18.0.0:
|
"react@^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.11.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17 || ^18 || ^19", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.1 || ^18.0.0", "react@^17.0.0 || ^18.0.0", "react@^18.0 || ^19", react@^18.0.0, react@^18.2.0, react@^18.3.1, "react@>= 16", "react@>= 16.8 || 18.0.0", react@>=16.6.0, react@>=16.8, react@>=16.8.0, react@>=18.0.0:
|
||||||
version "18.3.1"
|
version "18.3.1"
|
||||||
resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz"
|
resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz"
|
||||||
integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==
|
integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==
|
||||||
@ -5142,6 +5286,19 @@ readable-stream@^3.5.0, readable-stream@^3.6.0:
|
|||||||
string_decoder "^1.1.1"
|
string_decoder "^1.1.1"
|
||||||
util-deprecate "^1.0.1"
|
util-deprecate "^1.0.1"
|
||||||
|
|
||||||
|
readable-stream@~2.3.6:
|
||||||
|
version "2.3.8"
|
||||||
|
resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz"
|
||||||
|
integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==
|
||||||
|
dependencies:
|
||||||
|
core-util-is "~1.0.0"
|
||||||
|
inherits "~2.0.3"
|
||||||
|
isarray "~1.0.0"
|
||||||
|
process-nextick-args "~2.0.0"
|
||||||
|
safe-buffer "~5.1.1"
|
||||||
|
string_decoder "~1.1.1"
|
||||||
|
util-deprecate "~1.0.1"
|
||||||
|
|
||||||
readable-web-to-node-stream@^3.0.2:
|
readable-web-to-node-stream@^3.0.2:
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz"
|
resolved "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz"
|
||||||
@ -5177,6 +5334,11 @@ recharts@^2.10.3, recharts@^2.12.7:
|
|||||||
tiny-invariant "^1.3.1"
|
tiny-invariant "^1.3.1"
|
||||||
victory-vendor "^36.6.8"
|
victory-vendor "^36.6.8"
|
||||||
|
|
||||||
|
redux@^5.0.0, redux@^5.0.1:
|
||||||
|
version "5.0.1"
|
||||||
|
resolved "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz"
|
||||||
|
integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==
|
||||||
|
|
||||||
regenerate-unicode-properties@^10.1.0:
|
regenerate-unicode-properties@^10.1.0:
|
||||||
version "10.1.1"
|
version "10.1.1"
|
||||||
resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz"
|
resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz"
|
||||||
@ -5250,6 +5412,11 @@ regjsparser@^0.9.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
jsesc "~0.5.0"
|
jsesc "~0.5.0"
|
||||||
|
|
||||||
|
require-directory@^2.1.1:
|
||||||
|
version "2.1.1"
|
||||||
|
resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz"
|
||||||
|
integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
|
||||||
|
|
||||||
require-from-string@^2.0.2:
|
require-from-string@^2.0.2:
|
||||||
version "2.0.2"
|
version "2.0.2"
|
||||||
resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz"
|
resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz"
|
||||||
@ -5301,6 +5468,16 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
|
|||||||
hash-base "^3.0.0"
|
hash-base "^3.0.0"
|
||||||
inherits "^2.0.1"
|
inherits "^2.0.1"
|
||||||
|
|
||||||
|
rollup-plugin-visualizer@^5.12.0:
|
||||||
|
version "5.12.0"
|
||||||
|
resolved "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.12.0.tgz"
|
||||||
|
integrity sha512-8/NU9jXcHRs7Nnj07PF2o4gjxmm9lXIrZ8r175bT9dK8qoLlvKTwRMArRCMgpMGlq8CTLugRvEmyMeMXIU2pNQ==
|
||||||
|
dependencies:
|
||||||
|
open "^8.4.0"
|
||||||
|
picomatch "^2.3.1"
|
||||||
|
source-map "^0.7.4"
|
||||||
|
yargs "^17.5.1"
|
||||||
|
|
||||||
"rollup@^1.20.0 || ^2.0.0", rollup@^1.20.0||^2.0.0, rollup@^2.43.1:
|
"rollup@^1.20.0 || ^2.0.0", rollup@^1.20.0||^2.0.0, rollup@^2.43.1:
|
||||||
version "2.79.1"
|
version "2.79.1"
|
||||||
resolved "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz"
|
resolved "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz"
|
||||||
@ -5308,7 +5485,7 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.2"
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
rollup@^1.20.0||^2.0.0||^3.0.0||^4.0.0, rollup@^2.0.0||^3.0.0||^4.0.0, rollup@^2.78.0||^3.0.0||^4.0.0, rollup@^4.13.0:
|
rollup@^1.20.0||^2.0.0||^3.0.0||^4.0.0, rollup@^2.0.0||^3.0.0||^4.0.0, rollup@^2.78.0||^3.0.0||^4.0.0, rollup@^4.13.0, "rollup@2.x || 3.x || 4.x":
|
||||||
version "4.18.0"
|
version "4.18.0"
|
||||||
resolved "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz"
|
resolved "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz"
|
||||||
integrity sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==
|
integrity sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==
|
||||||
@ -5367,12 +5544,7 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2,
|
|||||||
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
|
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
|
||||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||||
|
|
||||||
safe-buffer@~5.1.0:
|
safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||||
version "5.1.2"
|
|
||||||
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz"
|
|
||||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
|
||||||
|
|
||||||
safe-buffer@~5.1.1:
|
|
||||||
version "5.1.2"
|
version "5.1.2"
|
||||||
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz"
|
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz"
|
||||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||||
@ -5430,6 +5602,11 @@ sass-embedded@*, sass-embedded@^1.79.5:
|
|||||||
sass-embedded-win32-ia32 "1.79.5"
|
sass-embedded-win32-ia32 "1.79.5"
|
||||||
sass-embedded-win32-x64 "1.79.5"
|
sass-embedded-win32-x64 "1.79.5"
|
||||||
|
|
||||||
|
sax@1.3.0:
|
||||||
|
version "1.3.0"
|
||||||
|
resolved "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz"
|
||||||
|
integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==
|
||||||
|
|
||||||
scheduler@^0.23.2:
|
scheduler@^0.23.2:
|
||||||
version "0.23.2"
|
version "0.23.2"
|
||||||
resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz"
|
resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz"
|
||||||
@ -5507,7 +5684,7 @@ set-function-name@^2.0.1, set-function-name@^2.0.2:
|
|||||||
functions-have-names "^1.2.3"
|
functions-have-names "^1.2.3"
|
||||||
has-property-descriptors "^1.0.2"
|
has-property-descriptors "^1.0.2"
|
||||||
|
|
||||||
setimmediate@^1.0.4:
|
setimmediate@^1.0.4, setimmediate@^1.0.5:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz"
|
resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz"
|
||||||
integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==
|
integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==
|
||||||
@ -5580,6 +5757,11 @@ source-map@^0.6.0:
|
|||||||
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
|
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
|
||||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||||
|
|
||||||
|
source-map@^0.7.4:
|
||||||
|
version "0.7.4"
|
||||||
|
resolved "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz"
|
||||||
|
integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==
|
||||||
|
|
||||||
source-map@^0.8.0-beta.0:
|
source-map@^0.8.0-beta.0:
|
||||||
version "0.8.0-beta.0"
|
version "0.8.0-beta.0"
|
||||||
resolved "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz"
|
resolved "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz"
|
||||||
@ -5638,7 +5820,16 @@ string_decoder@~1.1.1:
|
|||||||
is-fullwidth-code-point "^3.0.0"
|
is-fullwidth-code-point "^3.0.0"
|
||||||
strip-ansi "^6.0.1"
|
strip-ansi "^6.0.1"
|
||||||
|
|
||||||
string-width@^4.1.0:
|
string-width@^4.1.0, string-width@^4.2.0:
|
||||||
|
version "4.2.3"
|
||||||
|
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
|
||||||
|
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||||
|
dependencies:
|
||||||
|
emoji-regex "^8.0.0"
|
||||||
|
is-fullwidth-code-point "^3.0.0"
|
||||||
|
strip-ansi "^6.0.1"
|
||||||
|
|
||||||
|
string-width@^4.2.3:
|
||||||
version "4.2.3"
|
version "4.2.3"
|
||||||
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
|
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
|
||||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||||
@ -5908,7 +6099,7 @@ timers-browserify@^2.0.4:
|
|||||||
dependencies:
|
dependencies:
|
||||||
setimmediate "^1.0.4"
|
setimmediate "^1.0.4"
|
||||||
|
|
||||||
tiny-invariant@^1.3.1:
|
tiny-invariant@^1.0.6, tiny-invariant@^1.3.1:
|
||||||
version "1.3.3"
|
version "1.3.3"
|
||||||
resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz"
|
resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz"
|
||||||
integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==
|
integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==
|
||||||
@ -6158,6 +6349,11 @@ use-latest@^1.2.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
use-isomorphic-layout-effect "^1.1.1"
|
use-isomorphic-layout-effect "^1.1.1"
|
||||||
|
|
||||||
|
use-memo-one@^1.1.3:
|
||||||
|
version "1.1.3"
|
||||||
|
resolved "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz"
|
||||||
|
integrity sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==
|
||||||
|
|
||||||
use-sidecar@^1.1.2:
|
use-sidecar@^1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz"
|
resolved "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz"
|
||||||
@ -6176,6 +6372,11 @@ use-sync-external-store@^1.2.2:
|
|||||||
resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz"
|
resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz"
|
||||||
integrity sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==
|
integrity sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==
|
||||||
|
|
||||||
|
use-sync-external-store@^1.4.0:
|
||||||
|
version "1.4.0"
|
||||||
|
resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz"
|
||||||
|
integrity sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==
|
||||||
|
|
||||||
util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
|
util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
|
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
|
||||||
@ -6506,6 +6707,15 @@ workbox-window@^7.1.0, workbox-window@7.1.0:
|
|||||||
string-width "^4.1.0"
|
string-width "^4.1.0"
|
||||||
strip-ansi "^6.0.0"
|
strip-ansi "^6.0.0"
|
||||||
|
|
||||||
|
wrap-ansi@^7.0.0:
|
||||||
|
version "7.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz"
|
||||||
|
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||||
|
dependencies:
|
||||||
|
ansi-styles "^4.0.0"
|
||||||
|
string-width "^4.1.0"
|
||||||
|
strip-ansi "^6.0.0"
|
||||||
|
|
||||||
wrap-ansi@^8.0.1, wrap-ansi@^8.1.0:
|
wrap-ansi@^8.0.1, wrap-ansi@^8.1.0:
|
||||||
version "8.1.0"
|
version "8.1.0"
|
||||||
resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz"
|
resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz"
|
||||||
@ -6530,6 +6740,11 @@ xtend@^4.0.2:
|
|||||||
resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz"
|
resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz"
|
||||||
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
|
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
|
||||||
|
|
||||||
|
y18n@^5.0.5:
|
||||||
|
version "5.0.8"
|
||||||
|
resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz"
|
||||||
|
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
|
||||||
|
|
||||||
yallist@^3.0.2:
|
yallist@^3.0.2:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz"
|
resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz"
|
||||||
@ -6540,6 +6755,24 @@ yaml@^2.3.4:
|
|||||||
resolved "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz"
|
resolved "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz"
|
||||||
integrity sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==
|
integrity sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==
|
||||||
|
|
||||||
|
yargs-parser@^21.1.1:
|
||||||
|
version "21.1.1"
|
||||||
|
resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz"
|
||||||
|
integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
|
||||||
|
|
||||||
|
yargs@^17.5.1:
|
||||||
|
version "17.7.2"
|
||||||
|
resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz"
|
||||||
|
integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
|
||||||
|
dependencies:
|
||||||
|
cliui "^8.0.1"
|
||||||
|
escalade "^3.1.1"
|
||||||
|
get-caller-file "^2.0.5"
|
||||||
|
require-directory "^2.1.1"
|
||||||
|
string-width "^4.2.3"
|
||||||
|
y18n "^5.0.5"
|
||||||
|
yargs-parser "^21.1.1"
|
||||||
|
|
||||||
yocto-queue@^0.1.0:
|
yocto-queue@^0.1.0:
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"
|
resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"
|
||||||
|
|||||||
@ -1,26 +1,26 @@
|
|||||||
services:
|
services:
|
||||||
client_app:
|
web_client:
|
||||||
container_name: client_app
|
container_name: web_client
|
||||||
build:
|
build:
|
||||||
context: ./client
|
context: ./client
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
ports:
|
ports:
|
||||||
- 5173:5173
|
- ${CLIENT_PORT}:5173
|
||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
redis_db:
|
# redis_db:
|
||||||
image: "redis:alpine"
|
# image: "redis:alpine"
|
||||||
container_name: redis_db
|
# container_name: redis_db
|
||||||
ports:
|
# ports:
|
||||||
- ${REDIS_PORT}:${REDIS_PORT}
|
# - ${REDIS_PORT}:${REDIS_PORT}
|
||||||
environment:
|
# environment:
|
||||||
- REDIS_PASSWORD=${REDIS_PASSWORD}
|
# - REDIS_PASSWORD=${REDIS_PASSWORD}
|
||||||
command: [ "redis-server", "--requirepass", "${REDIS_PASSWORD}" ]
|
# command: [ "redis-server", "--requirepass", "${REDIS_PASSWORD}" ]
|
||||||
volumes:
|
# volumes:
|
||||||
- ./redis_data:/data
|
# - ./redis_data:/data
|
||||||
expose:
|
# expose:
|
||||||
- ${REDIS_PORT}:${REDIS_PORT}
|
# - ${REDIS_PORT}:${REDIS_PORT}
|
||||||
restart: unless-stopped
|
# restart: unless-stopped
|
||||||
|
|
||||||
ems:
|
ems:
|
||||||
container_name: ems
|
container_name: ems
|
||||||
@ -29,12 +29,12 @@ services:
|
|||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
volumes:
|
volumes:
|
||||||
- ./ems/public:/app/public
|
- ./ems/public:/app/public
|
||||||
links:
|
# links:
|
||||||
- redis_db:redis_db
|
# - redis_db:redis_db
|
||||||
- psql_db:psql_db
|
# - psql_db:psql_db
|
||||||
depends_on:
|
# depends_on:
|
||||||
- redis_db
|
# - redis_db
|
||||||
- psql_db
|
# - psql_db
|
||||||
environment:
|
environment:
|
||||||
- REDIS_PASSWORD=${REDIS_PASSWORD}
|
- REDIS_PASSWORD=${REDIS_PASSWORD}
|
||||||
- REDIS_HOST=${REDIS_HOST}
|
- REDIS_HOST=${REDIS_HOST}
|
||||||
@ -44,25 +44,34 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- ${EMS_PORT}:${EMS_PORT}
|
- ${EMS_PORT}:${EMS_PORT}
|
||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
monitor:
|
postgis_db:
|
||||||
container_name: monitor
|
container_name: postgis_db
|
||||||
build:
|
image: postgis/postgis:17-3.4-alpine
|
||||||
context: ./monitor
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
environment:
|
|
||||||
- MONITOR_PORT=${MONITOR_PORT}
|
|
||||||
ports:
|
|
||||||
- ${MONITOR_PORT}:${MONITOR_PORT}
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./monitor/data:/app/data
|
- ./postgis_db:/var/lib/postgresql/data
|
||||||
restart: always
|
environment:
|
||||||
|
- POSTGRES_DB=${POSTGRES_DB}
|
||||||
psql_db:
|
- POSTGRES_USER=${POSTGRES_USER}
|
||||||
container_name: psql_db
|
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||||
image: postgres:16.4-alpine
|
ports:
|
||||||
volumes:
|
- ${POSTGRES_PORT}:${POSTGRES_PORT}
|
||||||
- ./psql_data:/var/lib/postgresql/data
|
expose:
|
||||||
|
- ${POSTGRES_PORT}
|
||||||
|
healthcheck:
|
||||||
|
test:
|
||||||
|
['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}']
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 10s
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
ems_db:
|
||||||
|
container_name: ems_db
|
||||||
|
image: postgres:16.4-alpine
|
||||||
|
volumes:
|
||||||
|
- ./ems_db:/var/lib/postgresql/data
|
||||||
environment:
|
environment:
|
||||||
- POSTGRES_DB=${POSTGRES_DB}
|
- POSTGRES_DB=${POSTGRES_DB}
|
||||||
- POSTGRES_USER=${POSTGRES_USER}
|
- POSTGRES_USER=${POSTGRES_USER}
|
||||||
|
|||||||
@ -0,0 +1,23 @@
|
|||||||
|
# Environment variables declared in this file are automatically made available to Prisma.
|
||||||
|
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema
|
||||||
|
|
||||||
|
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
|
||||||
|
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
|
||||||
|
|
||||||
|
GENERAL_DATABASE_URL=""
|
||||||
|
|
||||||
|
DATABASE_URL=""
|
||||||
|
EMS_PORT=
|
||||||
|
|
||||||
|
MSSQL_HOST=
|
||||||
|
#MSSQL_HOST=localhost
|
||||||
|
MSSQL_LOGIN=
|
||||||
|
MSSQL_PASSWORD=
|
||||||
|
MSSQL_DB=
|
||||||
|
MSSQL_PORT=
|
||||||
|
|
||||||
|
PG_HOST=
|
||||||
|
PG_PORT=
|
||||||
|
PG_USER=
|
||||||
|
PG_PASSWORD=
|
||||||
|
PG_DB=
|
||||||
35
ems/DATABASE.md
Normal file
35
ems/DATABASE.md
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
Make sure to use PostGIS
|
||||||
|
|
||||||
|
Create tables first:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE IF NOT EXISTS bounds (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
entity_id INT NOT NULL,
|
||||||
|
entity_type TEXT NOT NULL,
|
||||||
|
geometry GEOMETRY(MULTIPOLYGON, 3857) NOT NULL,
|
||||||
|
UNIQUE (entity_id, entity_type)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE IF NOT EXISTS lines (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
object_id UUID NOT NULL,
|
||||||
|
geometry GEOMETRY(LINESTRING, 3857) NOT NULL,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP DEFAULT NOW(),
|
||||||
|
schema TEXT NOT NULL
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE IF NOT EXISTS shapes (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
object_id UUID NOT NULL,
|
||||||
|
geometry GEOMETRY(POLYGON, 3857) NOT NULL,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP DEFAULT NOW(),
|
||||||
|
schema TEXT NOT NULL
|
||||||
|
);
|
||||||
|
```
|
||||||
546
ems/package-lock.json
generated
546
ems/package-lock.json
generated
@ -19,7 +19,7 @@
|
|||||||
"ioredis": "^5.4.1",
|
"ioredis": "^5.4.1",
|
||||||
"md5": "^2.3.0",
|
"md5": "^2.3.0",
|
||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
"pg": "^8.13.0",
|
"pg": "^8.13.1",
|
||||||
"pump": "^3.0.0",
|
"pump": "^3.0.0",
|
||||||
"sharp": "^0.33.5",
|
"sharp": "^0.33.5",
|
||||||
"tedious": "^18.6.1"
|
"tedious": "^18.6.1"
|
||||||
@ -31,6 +31,7 @@
|
|||||||
"@types/md5": "^2.3.5",
|
"@types/md5": "^2.3.5",
|
||||||
"@types/multer": "^1.4.12",
|
"@types/multer": "^1.4.12",
|
||||||
"@types/node": "^22.4.1",
|
"@types/node": "^22.4.1",
|
||||||
|
"@types/pg": "^8.11.10",
|
||||||
"@types/pump": "^1.1.3",
|
"@types/pump": "^1.1.3",
|
||||||
"@types/redis": "^4.0.11",
|
"@types/redis": "^4.0.11",
|
||||||
"nodemon": "^3.1.4",
|
"nodemon": "^3.1.4",
|
||||||
@ -682,48 +683,53 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/debug": {
|
"node_modules/@prisma/debug": {
|
||||||
"version": "5.19.1",
|
"version": "5.22.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.22.0.tgz",
|
||||||
"integrity": "sha512-lAG6A6QnG2AskAukIEucYJZxxcSqKsMK74ZFVfCTOM/7UiyJQi48v6TQ47d6qKG3LbMslqOvnTX25dj/qvclGg==",
|
"integrity": "sha512-AUt44v3YJeggO2ZU5BkXI7M4hu9BF2zzH2iF2V5pyXT/lRTyWiElZ7It+bRH1EshoMRxHgpYg4VB6rCM+mG5jQ==",
|
||||||
"devOptional": true
|
"devOptional": true,
|
||||||
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/engines": {
|
"node_modules/@prisma/engines": {
|
||||||
"version": "5.19.1",
|
"version": "5.22.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.22.0.tgz",
|
||||||
"integrity": "sha512-kR/PoxZDrfUmbbXqqb8SlBBgCjvGaJYMCOe189PEYzq9rKqitQ2fvT/VJ8PDSe8tTNxhc2KzsCfCAL+Iwm/7Cg==",
|
"integrity": "sha512-UNjfslWhAt06kVL3CjkuYpHAWSO6L4kDCVPegV6itt7nD1kSJavd3vhgAEhjglLJJKEdJ7oIqDJ+yHk6qO8gPA==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/debug": "5.19.1",
|
"@prisma/debug": "5.22.0",
|
||||||
"@prisma/engines-version": "5.19.1-2.69d742ee20b815d88e17e54db4a2a7a3b30324e3",
|
"@prisma/engines-version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2",
|
||||||
"@prisma/fetch-engine": "5.19.1",
|
"@prisma/fetch-engine": "5.22.0",
|
||||||
"@prisma/get-platform": "5.19.1"
|
"@prisma/get-platform": "5.22.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/engines-version": {
|
"node_modules/@prisma/engines-version": {
|
||||||
"version": "5.19.1-2.69d742ee20b815d88e17e54db4a2a7a3b30324e3",
|
"version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.19.1-2.69d742ee20b815d88e17e54db4a2a7a3b30324e3.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2.tgz",
|
||||||
"integrity": "sha512-xR6rt+z5LnNqTP5BBc+8+ySgf4WNMimOKXRn6xfNRDSpHvbOEmd7+qAOmzCrddEc4Cp8nFC0txU14dstjH7FXA==",
|
"integrity": "sha512-2PTmxFR2yHW/eB3uqWtcgRcgAbG1rwG9ZriSvQw+nnb7c4uCr3RAcGMb6/zfE88SKlC1Nj2ziUvc96Z379mHgQ==",
|
||||||
"devOptional": true
|
"devOptional": true,
|
||||||
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/fetch-engine": {
|
"node_modules/@prisma/fetch-engine": {
|
||||||
"version": "5.19.1",
|
"version": "5.22.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.22.0.tgz",
|
||||||
"integrity": "sha512-pCq74rtlOVJfn4pLmdJj+eI4P7w2dugOnnTXpRilP/6n5b2aZiA4ulJlE0ddCbTPkfHmOL9BfaRgA8o+1rfdHw==",
|
"integrity": "sha512-bkrD/Mc2fSvkQBV5EpoFcZ87AvOgDxbG99488a5cexp5Ccny+UM6MAe/UFkUC0wLYD9+9befNOqGiIJhhq+HbA==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/debug": "5.19.1",
|
"@prisma/debug": "5.22.0",
|
||||||
"@prisma/engines-version": "5.19.1-2.69d742ee20b815d88e17e54db4a2a7a3b30324e3",
|
"@prisma/engines-version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2",
|
||||||
"@prisma/get-platform": "5.19.1"
|
"@prisma/get-platform": "5.22.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/get-platform": {
|
"node_modules/@prisma/get-platform": {
|
||||||
"version": "5.19.1",
|
"version": "5.22.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.22.0.tgz",
|
||||||
"integrity": "sha512-sCeoJ+7yt0UjnR+AXZL7vXlg5eNxaFOwC23h0KvW1YIXUoa7+W2ZcAUhoEQBmJTW4GrFqCuZ8YSP0mkDa4k3Zg==",
|
"integrity": "sha512-pHhpQdr1UPFpt+zFfnPazhulaZYCUqeIcPpJViYoq9R+D/yw4fjE+CtnsnKzPYm0ddUbeXUzjGVGIRVgPDCk4Q==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/debug": "5.19.1"
|
"@prisma/debug": "5.22.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@redis/bloom": {
|
"node_modules/@redis/bloom": {
|
||||||
@ -896,6 +902,74 @@
|
|||||||
"undici-types": "~6.19.2"
|
"undici-types": "~6.19.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/pg": {
|
||||||
|
"version": "8.11.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.11.10.tgz",
|
||||||
|
"integrity": "sha512-LczQUW4dbOQzsH2RQ5qoeJ6qJPdrcM/DcMLoqWQkMLMsq83J5lAX3LXjdkWdpscFy67JSOWDnh7Ny/sPFykmkg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*",
|
||||||
|
"pg-protocol": "*",
|
||||||
|
"pg-types": "^4.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/pg/node_modules/pg-types": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"pg-int8": "1.0.1",
|
||||||
|
"pg-numeric": "1.0.2",
|
||||||
|
"postgres-array": "~3.0.1",
|
||||||
|
"postgres-bytea": "~3.0.0",
|
||||||
|
"postgres-date": "~2.1.0",
|
||||||
|
"postgres-interval": "^3.0.0",
|
||||||
|
"postgres-range": "^1.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/pg/node_modules/postgres-array": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/pg/node_modules/postgres-bytea": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"obuf": "~1.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/pg/node_modules/postgres-date": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/pg/node_modules/postgres-interval": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/pump": {
|
"node_modules/@types/pump": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/pump/-/pump-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/pump/-/pump-1.1.3.tgz",
|
||||||
@ -1076,9 +1150,10 @@
|
|||||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||||
},
|
},
|
||||||
"node_modules/axios": {
|
"node_modules/axios": {
|
||||||
"version": "1.7.4",
|
"version": "1.8.4",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz",
|
||||||
"integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==",
|
"integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"follow-redirects": "^1.15.6",
|
"follow-redirects": "^1.15.6",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
@ -1157,9 +1232,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/body-parser": {
|
"node_modules/body-parser": {
|
||||||
"version": "1.20.2",
|
"version": "1.20.3",
|
||||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
|
||||||
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
|
"integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bytes": "3.1.2",
|
"bytes": "3.1.2",
|
||||||
"content-type": "~1.0.5",
|
"content-type": "~1.0.5",
|
||||||
@ -1169,7 +1245,7 @@
|
|||||||
"http-errors": "2.0.0",
|
"http-errors": "2.0.0",
|
||||||
"iconv-lite": "0.4.24",
|
"iconv-lite": "0.4.24",
|
||||||
"on-finished": "2.4.1",
|
"on-finished": "2.4.1",
|
||||||
"qs": "6.11.0",
|
"qs": "6.13.0",
|
||||||
"raw-body": "2.5.2",
|
"raw-body": "2.5.2",
|
||||||
"type-is": "~1.6.18",
|
"type-is": "~1.6.18",
|
||||||
"unpipe": "1.0.0"
|
"unpipe": "1.0.0"
|
||||||
@ -1253,16 +1329,27 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/call-bind": {
|
"node_modules/call-bind-apply-helpers": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||||
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
|
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-define-property": "^1.0.0",
|
|
||||||
"es-errors": "^1.3.0",
|
"es-errors": "^1.3.0",
|
||||||
"function-bind": "^1.1.2",
|
"function-bind": "^1.1.2"
|
||||||
"get-intrinsic": "^1.2.4",
|
},
|
||||||
"set-function-length": "^1.2.1"
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/call-bound": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind-apply-helpers": "^1.0.2",
|
||||||
|
"get-intrinsic": "^1.3.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@ -1399,9 +1486,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cookie": {
|
"node_modules/cookie": {
|
||||||
"version": "0.6.0",
|
"version": "0.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
|
||||||
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
|
"integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
@ -1450,22 +1538,6 @@
|
|||||||
"ms": "2.0.0"
|
"ms": "2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/define-data-property": {
|
|
||||||
"version": "1.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
|
||||||
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
|
|
||||||
"dependencies": {
|
|
||||||
"es-define-property": "^1.0.0",
|
|
||||||
"es-errors": "^1.3.0",
|
|
||||||
"gopd": "^1.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/define-lazy-prop": {
|
"node_modules/define-lazy-prop": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
|
||||||
@ -1535,6 +1607,20 @@
|
|||||||
"url": "https://dotenvx.com"
|
"url": "https://dotenvx.com"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dunder-proto": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind-apply-helpers": "^1.0.1",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"gopd": "^1.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ecdsa-sig-formatter": {
|
"node_modules/ecdsa-sig-formatter": {
|
||||||
"version": "1.0.11",
|
"version": "1.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||||
@ -1549,9 +1635,10 @@
|
|||||||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
|
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
|
||||||
},
|
},
|
||||||
"node_modules/encodeurl": {
|
"node_modules/encodeurl": {
|
||||||
"version": "1.0.2",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
|
||||||
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
@ -1565,12 +1652,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/es-define-property": {
|
"node_modules/es-define-property": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||||
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
|
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||||
"dependencies": {
|
"license": "MIT",
|
||||||
"get-intrinsic": "^1.2.4"
|
|
||||||
},
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
@ -1579,6 +1664,19 @@
|
|||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es-object-atoms": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0"
|
||||||
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
@ -1586,12 +1684,14 @@
|
|||||||
"node_modules/escape-html": {
|
"node_modules/escape-html": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||||
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
|
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/etag": {
|
"node_modules/etag": {
|
||||||
"version": "1.8.1",
|
"version": "1.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||||
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
|
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
@ -1613,36 +1713,37 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/express": {
|
"node_modules/express": {
|
||||||
"version": "4.19.2",
|
"version": "4.21.2",
|
||||||
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
|
||||||
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
|
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"accepts": "~1.3.8",
|
"accepts": "~1.3.8",
|
||||||
"array-flatten": "1.1.1",
|
"array-flatten": "1.1.1",
|
||||||
"body-parser": "1.20.2",
|
"body-parser": "1.20.3",
|
||||||
"content-disposition": "0.5.4",
|
"content-disposition": "0.5.4",
|
||||||
"content-type": "~1.0.4",
|
"content-type": "~1.0.4",
|
||||||
"cookie": "0.6.0",
|
"cookie": "0.7.1",
|
||||||
"cookie-signature": "1.0.6",
|
"cookie-signature": "1.0.6",
|
||||||
"debug": "2.6.9",
|
"debug": "2.6.9",
|
||||||
"depd": "2.0.0",
|
"depd": "2.0.0",
|
||||||
"encodeurl": "~1.0.2",
|
"encodeurl": "~2.0.0",
|
||||||
"escape-html": "~1.0.3",
|
"escape-html": "~1.0.3",
|
||||||
"etag": "~1.8.1",
|
"etag": "~1.8.1",
|
||||||
"finalhandler": "1.2.0",
|
"finalhandler": "1.3.1",
|
||||||
"fresh": "0.5.2",
|
"fresh": "0.5.2",
|
||||||
"http-errors": "2.0.0",
|
"http-errors": "2.0.0",
|
||||||
"merge-descriptors": "1.0.1",
|
"merge-descriptors": "1.0.3",
|
||||||
"methods": "~1.1.2",
|
"methods": "~1.1.2",
|
||||||
"on-finished": "2.4.1",
|
"on-finished": "2.4.1",
|
||||||
"parseurl": "~1.3.3",
|
"parseurl": "~1.3.3",
|
||||||
"path-to-regexp": "0.1.7",
|
"path-to-regexp": "0.1.12",
|
||||||
"proxy-addr": "~2.0.7",
|
"proxy-addr": "~2.0.7",
|
||||||
"qs": "6.11.0",
|
"qs": "6.13.0",
|
||||||
"range-parser": "~1.2.1",
|
"range-parser": "~1.2.1",
|
||||||
"safe-buffer": "5.2.1",
|
"safe-buffer": "5.2.1",
|
||||||
"send": "0.18.0",
|
"send": "0.19.0",
|
||||||
"serve-static": "1.15.0",
|
"serve-static": "1.16.2",
|
||||||
"setprototypeof": "1.2.0",
|
"setprototypeof": "1.2.0",
|
||||||
"statuses": "2.0.1",
|
"statuses": "2.0.1",
|
||||||
"type-is": "~1.6.18",
|
"type-is": "~1.6.18",
|
||||||
@ -1651,6 +1752,10 @@
|
|||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.10.0"
|
"node": ">= 0.10.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/express"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/express-validator": {
|
"node_modules/express-validator": {
|
||||||
@ -1678,12 +1783,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/finalhandler": {
|
"node_modules/finalhandler": {
|
||||||
"version": "1.2.0",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
|
||||||
"integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
|
"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "2.6.9",
|
"debug": "2.6.9",
|
||||||
"encodeurl": "~1.0.2",
|
"encodeurl": "~2.0.0",
|
||||||
"escape-html": "~1.0.3",
|
"escape-html": "~1.0.3",
|
||||||
"on-finished": "2.4.1",
|
"on-finished": "2.4.1",
|
||||||
"parseurl": "~1.3.3",
|
"parseurl": "~1.3.3",
|
||||||
@ -1738,6 +1844,7 @@
|
|||||||
"version": "0.5.2",
|
"version": "0.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
||||||
"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
|
"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
@ -1760,6 +1867,7 @@
|
|||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||||
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
@ -1774,15 +1882,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/get-intrinsic": {
|
"node_modules/get-intrinsic": {
|
||||||
"version": "1.2.4",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||||
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
|
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"call-bind-apply-helpers": "^1.0.2",
|
||||||
|
"es-define-property": "^1.0.1",
|
||||||
"es-errors": "^1.3.0",
|
"es-errors": "^1.3.0",
|
||||||
|
"es-object-atoms": "^1.1.1",
|
||||||
"function-bind": "^1.1.2",
|
"function-bind": "^1.1.2",
|
||||||
"has-proto": "^1.0.1",
|
"get-proto": "^1.0.1",
|
||||||
"has-symbols": "^1.0.3",
|
"gopd": "^1.2.0",
|
||||||
"hasown": "^2.0.0"
|
"has-symbols": "^1.1.0",
|
||||||
|
"hasown": "^2.0.2",
|
||||||
|
"math-intrinsics": "^1.1.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@ -1791,6 +1905,19 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/get-proto": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"dunder-proto": "^1.0.1",
|
||||||
|
"es-object-atoms": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/glob-parent": {
|
"node_modules/glob-parent": {
|
||||||
"version": "5.1.2",
|
"version": "5.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||||
@ -1804,11 +1931,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/gopd": {
|
"node_modules/gopd": {
|
||||||
"version": "1.0.1",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||||
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
|
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||||
"dependencies": {
|
"license": "MIT",
|
||||||
"get-intrinsic": "^1.1.3"
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
@ -1823,32 +1951,11 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/has-property-descriptors": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
|
|
||||||
"dependencies": {
|
|
||||||
"es-define-property": "^1.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/has-proto": {
|
|
||||||
"version": "1.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
|
|
||||||
"integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/has-symbols": {
|
"node_modules/has-symbols": {
|
||||||
"version": "1.0.3",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||||
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
|
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
},
|
},
|
||||||
@ -1860,6 +1967,7 @@
|
|||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"function-bind": "^1.1.2"
|
"function-bind": "^1.1.2"
|
||||||
},
|
},
|
||||||
@ -2248,6 +2356,15 @@
|
|||||||
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/math-intrinsics": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/md5": {
|
"node_modules/md5": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
|
||||||
@ -2267,9 +2384,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/merge-descriptors": {
|
"node_modules/merge-descriptors": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
|
||||||
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
|
"integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/methods": {
|
"node_modules/methods": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
@ -2283,6 +2404,7 @@
|
|||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
||||||
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"mime": "cli.js"
|
"mime": "cli.js"
|
||||||
},
|
},
|
||||||
@ -2444,9 +2566,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/object-inspect": {
|
"node_modules/object-inspect": {
|
||||||
"version": "1.13.2",
|
"version": "1.13.4",
|
||||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
|
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
||||||
"integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
|
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
},
|
},
|
||||||
@ -2454,6 +2577,12 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/obuf": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/on-finished": {
|
"node_modules/on-finished": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
||||||
@ -2493,19 +2622,21 @@
|
|||||||
"version": "1.3.3",
|
"version": "1.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||||
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
|
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/path-to-regexp": {
|
"node_modules/path-to-regexp": {
|
||||||
"version": "0.1.7",
|
"version": "0.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
|
||||||
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
|
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/pg": {
|
"node_modules/pg": {
|
||||||
"version": "8.13.0",
|
"version": "8.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/pg/-/pg-8.13.1.tgz",
|
||||||
"integrity": "sha512-34wkUTh3SxTClfoHB3pQ7bIMvw9dpFU1audQQeZG837fmHfHpr14n/AELVDoOYVDW2h5RDWU78tFjkD+erSBsw==",
|
"integrity": "sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pg-connection-string": "^2.7.0",
|
"pg-connection-string": "^2.7.0",
|
||||||
"pg-pool": "^3.7.0",
|
"pg-pool": "^3.7.0",
|
||||||
@ -2547,6 +2678,15 @@
|
|||||||
"node": ">=4.0.0"
|
"node": ">=4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pg-numeric": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/pg-pool": {
|
"node_modules/pg-pool": {
|
||||||
"version": "3.7.0",
|
"version": "3.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.7.0.tgz",
|
||||||
@ -2630,14 +2770,21 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/postgres-range": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/prisma": {
|
"node_modules/prisma": {
|
||||||
"version": "5.19.1",
|
"version": "5.22.0",
|
||||||
"resolved": "https://registry.npmjs.org/prisma/-/prisma-5.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/prisma/-/prisma-5.22.0.tgz",
|
||||||
"integrity": "sha512-c5K9MiDaa+VAAyh1OiYk76PXOme9s3E992D7kvvIOhCrNsBQfy2mP2QAQtX0WNj140IgG++12kwZpYB9iIydNQ==",
|
"integrity": "sha512-vtpjW3XuYCSnMsNVBjLMNkTj6OZbudcPPTPYHqX0CJfpcdWciI1dM8uHETwmDxxiqEwCIE6WvXucWUetJgfu/A==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/engines": "5.19.1"
|
"@prisma/engines": "5.22.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"prisma": "build/index.js"
|
"prisma": "build/index.js"
|
||||||
@ -2695,11 +2842,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/qs": {
|
"node_modules/qs": {
|
||||||
"version": "6.11.0",
|
"version": "6.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
||||||
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
|
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"side-channel": "^1.0.4"
|
"side-channel": "^1.0.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.6"
|
"node": ">=0.6"
|
||||||
@ -2712,6 +2860,7 @@
|
|||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||||
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
|
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
@ -2833,9 +2982,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/send": {
|
"node_modules/send": {
|
||||||
"version": "0.18.0",
|
"version": "0.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
|
||||||
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
|
"integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "2.6.9",
|
"debug": "2.6.9",
|
||||||
"depd": "2.0.0",
|
"depd": "2.0.0",
|
||||||
@ -2855,41 +3005,36 @@
|
|||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/send/node_modules/encodeurl": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/send/node_modules/ms": {
|
"node_modules/send/node_modules/ms": {
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/serve-static": {
|
"node_modules/serve-static": {
|
||||||
"version": "1.15.0",
|
"version": "1.16.2",
|
||||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
|
||||||
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
|
"integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"encodeurl": "~1.0.2",
|
"encodeurl": "~2.0.0",
|
||||||
"escape-html": "~1.0.3",
|
"escape-html": "~1.0.3",
|
||||||
"parseurl": "~1.3.3",
|
"parseurl": "~1.3.3",
|
||||||
"send": "0.18.0"
|
"send": "0.19.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/set-function-length": {
|
|
||||||
"version": "1.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
|
||||||
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
|
|
||||||
"dependencies": {
|
|
||||||
"define-data-property": "^1.1.4",
|
|
||||||
"es-errors": "^1.3.0",
|
|
||||||
"function-bind": "^1.1.2",
|
|
||||||
"get-intrinsic": "^1.2.4",
|
|
||||||
"gopd": "^1.0.1",
|
|
||||||
"has-property-descriptors": "^1.0.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/setprototypeof": {
|
"node_modules/setprototypeof": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||||
@ -2934,14 +3079,69 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/side-channel": {
|
"node_modules/side-channel": {
|
||||||
"version": "1.0.6",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
|
||||||
"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
|
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"call-bind": "^1.0.7",
|
|
||||||
"es-errors": "^1.3.0",
|
"es-errors": "^1.3.0",
|
||||||
"get-intrinsic": "^1.2.4",
|
"object-inspect": "^1.13.3",
|
||||||
"object-inspect": "^1.13.1"
|
"side-channel-list": "^1.0.0",
|
||||||
|
"side-channel-map": "^1.0.1",
|
||||||
|
"side-channel-weakmap": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/side-channel-list": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"object-inspect": "^1.13.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/side-channel-map": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bound": "^1.0.2",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"get-intrinsic": "^1.2.5",
|
||||||
|
"object-inspect": "^1.13.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/side-channel-weakmap": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bound": "^1.0.2",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"get-intrinsic": "^1.2.5",
|
||||||
|
"object-inspect": "^1.13.3",
|
||||||
|
"side-channel-map": "^1.0.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
"ioredis": "^5.4.1",
|
"ioredis": "^5.4.1",
|
||||||
"md5": "^2.3.0",
|
"md5": "^2.3.0",
|
||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
"pg": "^8.13.0",
|
"pg": "^8.13.1",
|
||||||
"pump": "^3.0.0",
|
"pump": "^3.0.0",
|
||||||
"sharp": "^0.33.5",
|
"sharp": "^0.33.5",
|
||||||
"tedious": "^18.6.1"
|
"tedious": "^18.6.1"
|
||||||
@ -35,6 +35,7 @@
|
|||||||
"@types/md5": "^2.3.5",
|
"@types/md5": "^2.3.5",
|
||||||
"@types/multer": "^1.4.12",
|
"@types/multer": "^1.4.12",
|
||||||
"@types/node": "^22.4.1",
|
"@types/node": "^22.4.1",
|
||||||
|
"@types/pg": "^8.11.10",
|
||||||
"@types/pump": "^1.1.3",
|
"@types/pump": "^1.1.3",
|
||||||
"@types/redis": "^4.0.11",
|
"@types/redis": "^4.0.11",
|
||||||
"nodemon": "^3.1.4",
|
"nodemon": "^3.1.4",
|
||||||
|
|||||||
143
ems/src/api/db/index.ts
Normal file
143
ems/src/api/db/index.ts
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import express, { Request, Response } from 'express';
|
||||||
|
import { pgQuery } from '../../utils/postgres';
|
||||||
|
const router = express.Router()
|
||||||
|
|
||||||
|
router.get('/rows/:table_name', async (req: Request, res: Response) => {
|
||||||
|
try {
|
||||||
|
const { table_name } = req.params
|
||||||
|
const { offset, limit } = req.query
|
||||||
|
|
||||||
|
const result = await pgQuery(
|
||||||
|
`
|
||||||
|
SELECT * FROM ${table_name}
|
||||||
|
OFFSET ${offset || 0} LIMIT ${limit || 10}
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(result)) {
|
||||||
|
if (result.length > 0) {
|
||||||
|
res.status(200).json(result)
|
||||||
|
} else {
|
||||||
|
res.status(404).json('not found')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.status(404).json('not found')
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
res.status(500)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get('/columns/:table_name', async (req: Request, res: Response) => {
|
||||||
|
try {
|
||||||
|
const { table_name } = req.params
|
||||||
|
|
||||||
|
const result = await pgQuery(
|
||||||
|
`
|
||||||
|
SELECT column_name, data_type
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_name = '${table_name}'
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(result)) {
|
||||||
|
if (result.length > 0) {
|
||||||
|
res.status(200).json(result)
|
||||||
|
} else {
|
||||||
|
res.status(404).json('not found')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.status(404).json('not found')
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
res.status(500)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get('/tables', async (req: Request, res: Response) => {
|
||||||
|
try {
|
||||||
|
const result = await pgQuery(
|
||||||
|
`
|
||||||
|
SELECT tablename FROM pg_tables WHERE schemaname = 'public';
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(result)) {
|
||||||
|
if (result.length > 0) {
|
||||||
|
res.status(200).json(result)
|
||||||
|
} else {
|
||||||
|
res.status(404).json('not found')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.status(404).json('not found')
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
res.status(500)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get('/figures/import', async (req: Request, res: Response) => {
|
||||||
|
try {
|
||||||
|
const { entity_type } = req.params
|
||||||
|
|
||||||
|
const result = await pgQuery(
|
||||||
|
`
|
||||||
|
SELECT * FROM bounds
|
||||||
|
WHERE entity_type = $1
|
||||||
|
`,
|
||||||
|
[entity_type]
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(result)) {
|
||||||
|
if (result.length > 0) {
|
||||||
|
const geometries = result.map((bound: { id: number, entity_id: number, entity_type: string, geometry: JSON, published_at: string, deleted_at: string | null }) => {
|
||||||
|
return {
|
||||||
|
...bound.geometry,
|
||||||
|
properties: {
|
||||||
|
id: bound.id,
|
||||||
|
entity_id: bound.entity_id,
|
||||||
|
entity_type: bound.entity_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
res.status(200).json(geometries)
|
||||||
|
} else {
|
||||||
|
res.status(404).json('not found')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.status(404).json('not found')
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
res.status(500)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get('/bounds/:entity_type/:entity_id', async (req: Request, res: Response) => {
|
||||||
|
try {
|
||||||
|
const { entity_type, entity_id } = req.params
|
||||||
|
|
||||||
|
const result = await pgQuery(
|
||||||
|
`
|
||||||
|
SELECT * FROM bounds
|
||||||
|
WHERE entity_type = $1
|
||||||
|
AND entity_id = $2
|
||||||
|
`,
|
||||||
|
[entity_type, entity_id]
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(result)) {
|
||||||
|
if (result.length > 0) {
|
||||||
|
res.status(200).json(result[0].geometry)
|
||||||
|
} else {
|
||||||
|
res.status(404).json('not found')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.status(404).json('not found')
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
res.status(500)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default router
|
||||||
@ -3,6 +3,7 @@ import { tediousQuery } from '../../utils/tedious';
|
|||||||
import { GeneralDB, GisDB } from '../../constants/db';
|
import { GeneralDB, GisDB } from '../../constants/db';
|
||||||
const router = express.Router()
|
const router = express.Router()
|
||||||
|
|
||||||
|
// ✅
|
||||||
router.get('/regions/all', async (req: Request, res: Response) => {
|
router.get('/regions/all', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const result = await tediousQuery(
|
const result = await tediousQuery(
|
||||||
@ -16,6 +17,7 @@ router.get('/regions/all', async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ✅
|
||||||
router.get('/districts/all', async (req: Request, res: Response) => {
|
router.get('/districts/all', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const { region_id } = req.query
|
const { region_id } = req.query
|
||||||
@ -34,6 +36,7 @@ router.get('/districts/all', async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ✅
|
||||||
router.get('/cities/all', async (req: Request, res: Response) => {
|
router.get('/cities/all', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const { offset, limit, search, id } = req.query
|
const { offset, limit, search, id } = req.query
|
||||||
@ -54,6 +57,7 @@ router.get('/cities/all', async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ✅
|
||||||
router.get('/types/all', async (req: Request, res: Response) => {
|
router.get('/types/all', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const result = await tediousQuery(
|
const result = await tediousQuery(
|
||||||
@ -68,6 +72,7 @@ router.get('/types/all', async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ✅
|
||||||
router.get('/objects/all', async (req: Request, res: Response) => {
|
router.get('/objects/all', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const { offset, limit, city_id } = req.query
|
const { offset, limit, city_id } = req.query
|
||||||
@ -87,31 +92,13 @@ router.get('/objects/all', async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ✅
|
||||||
router.get('/objects/list', async (req: Request, res: Response) => {
|
router.get('/objects/list', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const { city_id, year, planning, type } = req.query
|
const { city_id, year, planning, type } = req.query
|
||||||
|
|
||||||
if (type) {
|
if (type) {
|
||||||
const result = await tediousQuery(
|
const result = await tediousQuery(
|
||||||
// `
|
|
||||||
// SELECT
|
|
||||||
// *
|
|
||||||
// FROM
|
|
||||||
// vObjects
|
|
||||||
// WHERE
|
|
||||||
// vObjects.id_city = ${city_id}
|
|
||||||
// AND vObjects.year = ${year}
|
|
||||||
// AND type = ${type}
|
|
||||||
// AND
|
|
||||||
// (
|
|
||||||
// CASE
|
|
||||||
// WHEN TRY_CAST(vObjects.planning AS BIT) IS NOT NULL THEN TRY_CAST(vObjects.planning AS BIT)
|
|
||||||
// WHEN vObjects.planning = 'TRUE' THEN 1
|
|
||||||
// WHEN vObjects.planning = 'FALSE' THEN 0
|
|
||||||
// ELSE NULL
|
|
||||||
// END
|
|
||||||
// ) = ${planning};
|
|
||||||
// `
|
|
||||||
`
|
`
|
||||||
WITH cte_split(type_id, split_value, caption_params) AS
|
WITH cte_split(type_id, split_value, caption_params) AS
|
||||||
(
|
(
|
||||||
@ -171,27 +158,34 @@ router.get('/objects/list', async (req: Request, res: Response) => {
|
|||||||
const result = await tediousQuery(
|
const result = await tediousQuery(
|
||||||
`
|
`
|
||||||
SELECT
|
SELECT
|
||||||
tTypes.id AS id,
|
${GeneralDB}..tTypes.id AS id,
|
||||||
tTypes.name AS name,
|
${GeneralDB}..tTypes.name AS name,
|
||||||
COUNT(vObjects.type) AS count
|
COUNT(vo.type) AS count,
|
||||||
|
tr.r,
|
||||||
|
tr.g,
|
||||||
|
tr.b
|
||||||
FROM
|
FROM
|
||||||
vObjects
|
${GeneralDB}..vObjects vo
|
||||||
JOIN
|
JOIN
|
||||||
tTypes ON vObjects.type = tTypes.id
|
${GeneralDB}..tTypes ON vo.type = ${GeneralDB}..tTypes.id
|
||||||
|
LEFT JOIN ${GisDB}..TypeRoles tr ON tr.id = ${GeneralDB}..tTypes.id
|
||||||
WHERE
|
WHERE
|
||||||
vObjects.id_city = ${city_id} AND vObjects.year = ${year}
|
vo.id_city = ${city_id} AND vo.year = ${year}
|
||||||
AND
|
AND
|
||||||
(
|
(
|
||||||
CASE
|
CASE
|
||||||
WHEN TRY_CAST(vObjects.planning AS BIT) IS NOT NULL THEN TRY_CAST(vObjects.planning AS BIT)
|
WHEN TRY_CAST(vo.planning AS BIT) IS NOT NULL THEN TRY_CAST(vo.planning AS BIT)
|
||||||
WHEN vObjects.planning = 'TRUE' THEN 1
|
WHEN vo.planning = 'TRUE' THEN 1
|
||||||
WHEN vObjects.planning = 'FALSE' THEN 0
|
WHEN vo.planning = 'FALSE' THEN 0
|
||||||
ELSE NULL
|
ELSE NULL
|
||||||
END
|
END
|
||||||
) = ${planning}
|
) = ${planning}
|
||||||
GROUP BY
|
GROUP BY
|
||||||
tTypes.id,
|
${GeneralDB}..tTypes.id,
|
||||||
tTypes.name;
|
${GeneralDB}..tTypes.name,
|
||||||
|
tr.r,
|
||||||
|
tr.g,
|
||||||
|
tr.b;
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
res.status(200).json(result)
|
res.status(200).json(result)
|
||||||
@ -219,6 +213,7 @@ router.get('/objects/:id([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ✅
|
||||||
router.get('/values/all', async (req: Request, res: Response) => {
|
router.get('/values/all', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const { object_id } = req.query
|
const { object_id } = req.query
|
||||||
@ -250,6 +245,7 @@ router.get('/values/all', async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ✅
|
||||||
router.get('/params/all', async (req: Request, res: Response) => {
|
router.get('/params/all', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const { param_id } = req.query
|
const { param_id } = req.query
|
||||||
@ -282,6 +278,7 @@ const tcbParamQuery = (vtable: string, id_city: string) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ✅
|
||||||
// Get value from TCB parameter
|
// Get value from TCB parameter
|
||||||
router.get('/params/tcb', async (req: Request, res: Response) => {
|
router.get('/params/tcb', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
@ -316,6 +313,7 @@ router.get('/params/tcb', async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ✅
|
||||||
router.get('/search/objects', async (req: Request, res: Response) => {
|
router.get('/search/objects', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const { q, id_city, year } = req.query
|
const { q, id_city, year } = req.query
|
||||||
|
|||||||
@ -1,8 +1,104 @@
|
|||||||
import express, { Request, Response } from 'express';
|
import express, { Request, Response } from 'express';
|
||||||
import { tediousQuery } from '../../utils/tedious';
|
import { tediousQuery } from '../../utils/tedious';
|
||||||
import { GeneralDB, GisDB } from '../../constants/db';
|
import { GeneralDB, GisDB } from '../../constants/db';
|
||||||
|
import { pgQuery } from '../../utils/postgres';
|
||||||
|
|
||||||
const router = express.Router()
|
const router = express.Router()
|
||||||
|
|
||||||
|
router.get('/migrate/lines', async (req: Request, res: Response) => {
|
||||||
|
try {
|
||||||
|
const result = await tediousQuery(
|
||||||
|
`
|
||||||
|
SELECT * FROM ${GisDB}..lines
|
||||||
|
`
|
||||||
|
)
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// ✅
|
||||||
|
router.get('/type-roles', async (req: Request, res: Response) => {
|
||||||
|
try {
|
||||||
|
const result = await tediousQuery(
|
||||||
|
`
|
||||||
|
SELECT * FROM ${GisDB}..TypeRoles;
|
||||||
|
`
|
||||||
|
)
|
||||||
|
res.status(200).json(result)
|
||||||
|
} catch (err) {
|
||||||
|
res.status(500)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// ✅
|
||||||
|
router.get('/bounds/:entity_type', async (req: Request, res: Response) => {
|
||||||
|
try {
|
||||||
|
const { entity_type } = req.params
|
||||||
|
|
||||||
|
const result = await pgQuery(
|
||||||
|
`
|
||||||
|
SELECT entity_id, entity_type, ST_AsGeoJSON(geometry)::JSON AS geometry FROM bounds
|
||||||
|
WHERE entity_type = $1
|
||||||
|
`,
|
||||||
|
[entity_type]
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(result)) {
|
||||||
|
if (result.length > 0) {
|
||||||
|
const geometries = result.map((bound: { id: string, entity_id: number, entity_type: string, geometry: JSON, published_at: string, deleted_at: string | null }) => {
|
||||||
|
return {
|
||||||
|
...bound.geometry,
|
||||||
|
properties: {
|
||||||
|
id: bound.id,
|
||||||
|
entity_id: bound.entity_id,
|
||||||
|
entity_type: bound.entity_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
res.status(200).json(geometries)
|
||||||
|
} else {
|
||||||
|
res.status(404).json('not found')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.status(404).json('not found')
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
res.status(500)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// ✅
|
||||||
|
router.get('/bounds/:entity_type/:entity_id', async (req: Request, res: Response) => {
|
||||||
|
try {
|
||||||
|
const { entity_type, entity_id } = req.params
|
||||||
|
|
||||||
|
const result = await pgQuery(
|
||||||
|
`
|
||||||
|
SELECT entity_id, entity_type, ST_AsGeoJSON(geometry)::JSON AS geometry FROM bounds
|
||||||
|
WHERE entity_type = $1
|
||||||
|
AND entity_id = $2
|
||||||
|
`,
|
||||||
|
[entity_type, entity_id]
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(result)) {
|
||||||
|
if (result.length > 0) {
|
||||||
|
res.status(200).json(result[0].geometry)
|
||||||
|
} else {
|
||||||
|
res.status(404).json('not found')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.status(404).json('not found')
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
res.status(500)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// ✅
|
||||||
router.get('/images/all', async (req: Request, res: Response) => {
|
router.get('/images/all', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const { offset, limit, city_id } = req.query
|
const { offset, limit, city_id } = req.query
|
||||||
@ -22,7 +118,7 @@ router.get('/images/all', async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ✅
|
||||||
// Get figures by year and city id
|
// Get figures by year and city id
|
||||||
router.get('/figures/all', async (req: Request, res: Response) => {
|
router.get('/figures/all', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
@ -43,6 +139,7 @@ router.get('/figures/all', async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ✅
|
||||||
// Get lines by year and city id
|
// Get lines by year and city id
|
||||||
router.get('/lines/all', async (req: Request, res: Response) => {
|
router.get('/lines/all', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
@ -60,6 +157,7 @@ router.get('/lines/all', async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ✅
|
||||||
router.get('/regions/borders', async (req: Request, res: Response) => {
|
router.get('/regions/borders', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const result = await tediousQuery(
|
const result = await tediousQuery(
|
||||||
|
|||||||
@ -3,70 +3,70 @@ import { query, validationResult } from 'express-validator';
|
|||||||
import { PrismaClient } from '@prisma/client';
|
import { PrismaClient } from '@prisma/client';
|
||||||
const router = express.Router()
|
const router = express.Router()
|
||||||
|
|
||||||
const prisma = new PrismaClient()
|
//const prisma = new PrismaClient()
|
||||||
|
|
||||||
router.get('/all', async (req: Request, res: Response) => {
|
// router.get('/all', async (req: Request, res: Response) => {
|
||||||
try {
|
// try {
|
||||||
const nodes = await prisma.nodes.findMany()
|
// const nodes = await prisma.nodes.findMany()
|
||||||
|
|
||||||
res.json(nodes)
|
// res.json(nodes)
|
||||||
} catch (error) {
|
// } catch (error) {
|
||||||
console.error('Error getting node:', error);
|
// console.error('Error getting node:', error);
|
||||||
res.status(500).json({ error: 'Failed to get node' });
|
// res.status(500).json({ error: 'Failed to get node' });
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
|
|
||||||
router.get('/', query('id').isString().isUUID(), async (req: Request, res: Response) => {
|
// router.get('/', query('id').isString().isUUID(), async (req: Request, res: Response) => {
|
||||||
try {
|
// try {
|
||||||
const result = validationResult(req)
|
// const result = validationResult(req)
|
||||||
if (!result.isEmpty()) {
|
// if (!result.isEmpty()) {
|
||||||
return res.send({ errors: result.array() })
|
// return res.send({ errors: result.array() })
|
||||||
}
|
// }
|
||||||
|
|
||||||
const { id } = req.params
|
// const { id } = req.params
|
||||||
|
|
||||||
const node = await prisma.nodes.findFirst({
|
// const node = await prisma.nodes.findFirst({
|
||||||
where: {
|
// where: {
|
||||||
id: id
|
// id: id
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
|
|
||||||
res.json(node)
|
// res.json(node)
|
||||||
|
|
||||||
} catch (error) {
|
// } catch (error) {
|
||||||
console.error('Error getting node:', error);
|
// console.error('Error getting node:', error);
|
||||||
res.status(500).json({ error: 'Failed to get node' });
|
// res.status(500).json({ error: 'Failed to get node' });
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
|
|
||||||
router.post('/', async (req: Request, res: Response) => {
|
// router.post('/', async (req: Request, res: Response) => {
|
||||||
try {
|
// try {
|
||||||
const { coordinates, object_id, type } = req.body;
|
// const { coordinates, object_id, type } = req.body;
|
||||||
|
|
||||||
// Convert the incoming array of coordinates into the shape structure
|
// // Convert the incoming array of coordinates into the shape structure
|
||||||
const shape = coordinates.map((point: number[]) => ({
|
// const shape = coordinates.map((point: number[]) => ({
|
||||||
object_id: object_id || null,
|
// object_id: object_id || null,
|
||||||
x: point[0],
|
// x: point[0],
|
||||||
y: point[1]
|
// y: point[1]
|
||||||
}));
|
// }));
|
||||||
|
|
||||||
console.log(shape)
|
// console.log(shape)
|
||||||
|
|
||||||
// Create a new node in the database
|
// // Create a new node in the database
|
||||||
const node = await prisma.nodes.create({
|
// const node = await prisma.nodes.create({
|
||||||
data: {
|
// data: {
|
||||||
object_id: object_id || null, // Nullable if object_id is not provided
|
// object_id: object_id || null, // Nullable if object_id is not provided
|
||||||
shape_type: type, // You can adjust this dynamically
|
// shape_type: type, // You can adjust this dynamically
|
||||||
shape: shape, // Store the shape array as Json[]
|
// shape: shape, // Store the shape array as Json[]
|
||||||
label: 'Default'
|
// label: 'Default'
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
|
|
||||||
res.status(201).json(node);
|
// res.status(201).json(node);
|
||||||
} catch (error) {
|
// } catch (error) {
|
||||||
console.error('Error creating node:', error);
|
// console.error('Error creating node:', error);
|
||||||
res.status(500).json({ error: 'Failed to create node' });
|
// res.status(500).json({ error: 'Failed to create node' });
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
@ -10,7 +10,7 @@ const router = express.Router()
|
|||||||
|
|
||||||
const storage = multer.diskStorage({
|
const storage = multer.diskStorage({
|
||||||
destination: function (req, file, cb) {
|
destination: function (req, file, cb) {
|
||||||
cb(null, path.join(__dirname, '..', 'public', 'temp'))
|
cb(null, path.join(__dirname, '..', '..', '..', 'public', 'temp'))
|
||||||
},
|
},
|
||||||
filename: function (req, file, cb) {
|
filename: function (req, file, cb) {
|
||||||
cb(null, Date.now() + path.extname(file.originalname))
|
cb(null, Date.now() + path.extname(file.originalname))
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import express from 'express'
|
import express from 'express'
|
||||||
import bodyParser from 'body-parser'
|
import bodyParser from 'body-parser'
|
||||||
import cors from 'cors'
|
import cors from 'cors'
|
||||||
|
import dbRouter from './api/db'
|
||||||
import generalRouter from './api/general'
|
import generalRouter from './api/general'
|
||||||
import gisRouter from './api/gis'
|
import gisRouter from './api/gis'
|
||||||
import nodesRouter from './api/nodes'
|
import nodesRouter from './api/nodes'
|
||||||
@ -17,6 +18,7 @@ app.use(bodyParser.json())
|
|||||||
|
|
||||||
app.use(bodyParser.urlencoded({ extended: true }))
|
app.use(bodyParser.urlencoded({ extended: true }))
|
||||||
|
|
||||||
|
app.use('/db', dbRouter)
|
||||||
app.use('/general', generalRouter)
|
app.use('/general', generalRouter)
|
||||||
app.use('/gis', gisRouter)
|
app.use('/gis', gisRouter)
|
||||||
app.use('/nodes', nodesRouter)
|
app.use('/nodes', nodesRouter)
|
||||||
|
|||||||
37
ems/src/utils/postgres.ts
Normal file
37
ems/src/utils/postgres.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { Pool } from 'pg';
|
||||||
|
import 'dotenv/config';
|
||||||
|
|
||||||
|
// Environment variables for database configuration
|
||||||
|
const PG_HOST = process.env.PG_HOST || 'localhost';
|
||||||
|
const PG_PORT = Number(process.env.PG_PORT) || 5432;
|
||||||
|
const PG_USER = process.env.PG_USER || 'postgres';
|
||||||
|
const PG_PASSWORD = process.env.PG_PASSWORD || '';
|
||||||
|
const PG_DB = process.env.PG_DB || 'postgres';
|
||||||
|
|
||||||
|
// Create a connection pool
|
||||||
|
const pool = new Pool({
|
||||||
|
host: PG_HOST,
|
||||||
|
port: PG_PORT,
|
||||||
|
user: PG_USER,
|
||||||
|
password: PG_PASSWORD,
|
||||||
|
database: PG_DB,
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function pgQuery(query: string, params: any[] = []) {
|
||||||
|
try {
|
||||||
|
// Get a client from the pool
|
||||||
|
const client = await pool.connect();
|
||||||
|
try {
|
||||||
|
// Execute the query with parameters
|
||||||
|
const result = await client.query(query, params);
|
||||||
|
return result.rows; // Return only the rows
|
||||||
|
} finally {
|
||||||
|
// Release the client back to the pool
|
||||||
|
client.release();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// Log error and rethrow it
|
||||||
|
console.error(`Error executing query: ${query}`, err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
22
server/.env.example
Normal file
22
server/.env.example
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
GENERAL_DB_USER=
|
||||||
|
GENERAL_DB_PASSWORD=
|
||||||
|
GENERAL_DB_HOST=
|
||||||
|
GENERAL_DB_NAME=
|
||||||
|
GENERAL_DB_PORT=
|
||||||
|
|
||||||
|
EMS_DB_HOST=
|
||||||
|
#MSSQL_HOST=localhost
|
||||||
|
EMS_DB_USER=
|
||||||
|
EMS_DB_PASSWORD=
|
||||||
|
EMS_DB_NAME=
|
||||||
|
EMS_DB_PORT=
|
||||||
|
|
||||||
|
FUEL_DB_USER=
|
||||||
|
FUEL_DB_PASSWORD=
|
||||||
|
FUEL_DB_HOST=
|
||||||
|
|
||||||
|
PG_HOST=
|
||||||
|
PG_PORT=
|
||||||
|
PG_USER=
|
||||||
|
PG_PASSWORD=
|
||||||
|
PG_DB=
|
||||||
56
server/.gitignore
vendored
Normal file
56
server/.gitignore
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
# compiled output
|
||||||
|
/dist
|
||||||
|
/node_modules
|
||||||
|
/build
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
/coverage
|
||||||
|
/.nyc_output
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
/.idea
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# IDE - VSCode
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# temp directory
|
||||||
|
.temp
|
||||||
|
.tmp
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
4
server/.prettierrc
Normal file
4
server/.prettierrc
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "all"
|
||||||
|
}
|
||||||
98
server/README.md
Normal file
98
server/README.md
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
<p align="center">
|
||||||
|
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
|
||||||
|
[circleci-url]: https://circleci.com/gh/nestjs/nest
|
||||||
|
|
||||||
|
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
|
||||||
|
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
|
||||||
|
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
|
||||||
|
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
|
||||||
|
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
|
||||||
|
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
|
||||||
|
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
|
||||||
|
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg" alt="Donate us"/></a>
|
||||||
|
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
|
||||||
|
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow" alt="Follow us on Twitter"></a>
|
||||||
|
</p>
|
||||||
|
<!--[](https://opencollective.com/nest#backer)
|
||||||
|
[](https://opencollective.com/nest#sponsor)-->
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
|
||||||
|
|
||||||
|
## Project setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Compile and run the project
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# development
|
||||||
|
$ npm run start
|
||||||
|
|
||||||
|
# watch mode
|
||||||
|
$ npm run start:dev
|
||||||
|
|
||||||
|
# production mode
|
||||||
|
$ npm run start:prod
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# unit tests
|
||||||
|
$ npm run test
|
||||||
|
|
||||||
|
# e2e tests
|
||||||
|
$ npm run test:e2e
|
||||||
|
|
||||||
|
# test coverage
|
||||||
|
$ npm run test:cov
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
When you're ready to deploy your NestJS application to production, there are some key steps you can take to ensure it runs as efficiently as possible. Check out the [deployment documentation](https://docs.nestjs.com/deployment) for more information.
|
||||||
|
|
||||||
|
If you are looking for a cloud-based platform to deploy your NestJS application, check out [Mau](https://mau.nestjs.com), our official platform for deploying NestJS applications on AWS. Mau makes deployment straightforward and fast, requiring just a few simple steps:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ npm install -g @nestjs/mau
|
||||||
|
$ mau deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
With Mau, you can deploy your application in just a few clicks, allowing you to focus on building features rather than managing infrastructure.
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
Check out a few resources that may come in handy when working with NestJS:
|
||||||
|
|
||||||
|
- Visit the [NestJS Documentation](https://docs.nestjs.com) to learn more about the framework.
|
||||||
|
- For questions and support, please visit our [Discord channel](https://discord.gg/G7Qnnhy).
|
||||||
|
- To dive deeper and get more hands-on experience, check out our official video [courses](https://courses.nestjs.com/).
|
||||||
|
- Deploy your application to AWS with the help of [NestJS Mau](https://mau.nestjs.com) in just a few clicks.
|
||||||
|
- Visualize your application graph and interact with the NestJS application in real-time using [NestJS Devtools](https://devtools.nestjs.com).
|
||||||
|
- Need help with your project (part-time to full-time)? Check out our official [enterprise support](https://enterprise.nestjs.com).
|
||||||
|
- To stay in the loop and get updates, follow us on [X](https://x.com/nestframework) and [LinkedIn](https://linkedin.com/company/nestjs).
|
||||||
|
- Looking for a job, or have a job to offer? Check out our official [Jobs board](https://jobs.nestjs.com).
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
|
||||||
|
|
||||||
|
## Stay in touch
|
||||||
|
|
||||||
|
- Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec)
|
||||||
|
- Website - [https://nestjs.com](https://nestjs.com/)
|
||||||
|
- Twitter - [@nestframework](https://twitter.com/nestframework)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE).
|
||||||
BIN
server/ems.db
Normal file
BIN
server/ems.db
Normal file
Binary file not shown.
34
server/eslint.config.mjs
Normal file
34
server/eslint.config.mjs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// @ts-check
|
||||||
|
import eslint from '@eslint/js';
|
||||||
|
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
|
||||||
|
import globals from 'globals';
|
||||||
|
import tseslint from 'typescript-eslint';
|
||||||
|
|
||||||
|
export default tseslint.config(
|
||||||
|
{
|
||||||
|
ignores: ['eslint.config.mjs'],
|
||||||
|
},
|
||||||
|
eslint.configs.recommended,
|
||||||
|
...tseslint.configs.recommendedTypeChecked,
|
||||||
|
eslintPluginPrettierRecommended,
|
||||||
|
{
|
||||||
|
languageOptions: {
|
||||||
|
globals: {
|
||||||
|
...globals.node,
|
||||||
|
...globals.jest,
|
||||||
|
},
|
||||||
|
sourceType: 'commonjs',
|
||||||
|
parserOptions: {
|
||||||
|
projectService: true,
|
||||||
|
tsconfigRootDir: import.meta.dirname,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
'@typescript-eslint/no-floating-promises': 'warn',
|
||||||
|
'@typescript-eslint/no-unsafe-argument': 'warn'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
8
server/nest-cli.json
Normal file
8
server/nest-cli.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/nest-cli",
|
||||||
|
"collection": "@nestjs/schematics",
|
||||||
|
"sourceRoot": "src",
|
||||||
|
"compilerOptions": {
|
||||||
|
"deleteOutDir": true
|
||||||
|
}
|
||||||
|
}
|
||||||
15089
server/package-lock.json
generated
Normal file
15089
server/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
86
server/package.json
Normal file
86
server/package.json
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
{
|
||||||
|
"name": "server",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "",
|
||||||
|
"author": "",
|
||||||
|
"private": true,
|
||||||
|
"license": "UNLICENSED",
|
||||||
|
"scripts": {
|
||||||
|
"build": "nest build",
|
||||||
|
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||||
|
"start": "nest start",
|
||||||
|
"start:dev": "nest start --watch",
|
||||||
|
"start:debug": "nest start --debug --watch",
|
||||||
|
"start:prod": "node dist/main",
|
||||||
|
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
||||||
|
"test": "jest",
|
||||||
|
"test:watch": "jest --watch",
|
||||||
|
"test:cov": "jest --coverage",
|
||||||
|
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
||||||
|
"test:e2e": "jest --config ./test/jest-e2e.json"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@nestjs/axios": "^4.0.0",
|
||||||
|
"@nestjs/common": "^11.0.1",
|
||||||
|
"@nestjs/config": "^4.0.2",
|
||||||
|
"@nestjs/core": "^11.0.1",
|
||||||
|
"@nestjs/platform-express": "^11.0.1",
|
||||||
|
"@nestjs/swagger": "^11.2.0",
|
||||||
|
"@nestjs/typeorm": "^11.0.0",
|
||||||
|
"axios": "^1.9.0",
|
||||||
|
"class-transformer": "^0.5.1",
|
||||||
|
"class-validator": "^0.14.2",
|
||||||
|
"mssql": "^11.0.1",
|
||||||
|
"pg": "^8.16.0",
|
||||||
|
"reflect-metadata": "^0.2.2",
|
||||||
|
"rxjs": "^7.8.1",
|
||||||
|
"sharp": "^0.34.2",
|
||||||
|
"sqlite3": "^5.1.7",
|
||||||
|
"typeorm": "^0.3.24"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@eslint/eslintrc": "^3.2.0",
|
||||||
|
"@eslint/js": "^9.18.0",
|
||||||
|
"@nestjs/cli": "^11.0.0",
|
||||||
|
"@nestjs/schematics": "^11.0.0",
|
||||||
|
"@nestjs/testing": "^11.0.1",
|
||||||
|
"@swc/cli": "^0.6.0",
|
||||||
|
"@swc/core": "^1.10.7",
|
||||||
|
"@types/express": "^5.0.0",
|
||||||
|
"@types/jest": "^29.5.14",
|
||||||
|
"@types/multer": "^1.4.13",
|
||||||
|
"@types/node": "^22.10.7",
|
||||||
|
"@types/supertest": "^6.0.2",
|
||||||
|
"eslint": "^9.18.0",
|
||||||
|
"eslint-config-prettier": "^10.0.1",
|
||||||
|
"eslint-plugin-prettier": "^5.2.2",
|
||||||
|
"globals": "^16.0.0",
|
||||||
|
"jest": "^29.7.0",
|
||||||
|
"prettier": "^3.4.2",
|
||||||
|
"source-map-support": "^0.5.21",
|
||||||
|
"supertest": "^7.0.0",
|
||||||
|
"ts-jest": "^29.2.5",
|
||||||
|
"ts-loader": "^9.5.2",
|
||||||
|
"ts-node": "^10.9.2",
|
||||||
|
"tsconfig-paths": "^4.2.0",
|
||||||
|
"typescript": "^5.7.3",
|
||||||
|
"typescript-eslint": "^8.20.0"
|
||||||
|
},
|
||||||
|
"jest": {
|
||||||
|
"moduleFileExtensions": [
|
||||||
|
"js",
|
||||||
|
"json",
|
||||||
|
"ts"
|
||||||
|
],
|
||||||
|
"rootDir": "src",
|
||||||
|
"testRegex": ".*\\.spec\\.ts$",
|
||||||
|
"transform": {
|
||||||
|
"^.+\\.(t|j)s$": "ts-jest"
|
||||||
|
},
|
||||||
|
"collectCoverageFrom": [
|
||||||
|
"**/*.(t|j)s"
|
||||||
|
],
|
||||||
|
"coverageDirectory": "../coverage",
|
||||||
|
"testEnvironment": "node"
|
||||||
|
}
|
||||||
|
}
|
||||||
22
server/src/app.controller.spec.ts
Normal file
22
server/src/app.controller.spec.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { AppController } from './app.controller';
|
||||||
|
import { AppService } from './app.service';
|
||||||
|
|
||||||
|
describe('AppController', () => {
|
||||||
|
let appController: AppController;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const app: TestingModule = await Test.createTestingModule({
|
||||||
|
controllers: [AppController],
|
||||||
|
providers: [AppService],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
appController = app.get<AppController>(AppController);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('root', () => {
|
||||||
|
it('should return "Hello World!"', () => {
|
||||||
|
expect(appController.getHello()).toBe('Hello World!');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
12
server/src/app.controller.ts
Normal file
12
server/src/app.controller.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { Controller, Get } from '@nestjs/common';
|
||||||
|
import { AppService } from './app.service';
|
||||||
|
|
||||||
|
@Controller()
|
||||||
|
export class AppController {
|
||||||
|
constructor(private readonly appService: AppService) {}
|
||||||
|
|
||||||
|
@Get()
|
||||||
|
getHello(): string {
|
||||||
|
return this.appService.getHello();
|
||||||
|
}
|
||||||
|
}
|
||||||
86
server/src/app.module.ts
Normal file
86
server/src/app.module.ts
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { AppController } from './app.controller';
|
||||||
|
import { AppService } from './app.service';
|
||||||
|
import { ConfigModule } from '@nestjs/config';
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
import { FuelModule } from './fuel/fuel.module';
|
||||||
|
import { GeneralModule } from './general/general.module';
|
||||||
|
import { EmsModule } from './ems/ems.module';
|
||||||
|
import { TilesModule } from './tiles/tiles.module';
|
||||||
|
import { GisModule } from './gis/gis.module';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
ConfigModule.forRoot(),
|
||||||
|
TypeOrmModule.forRoot({
|
||||||
|
type: 'sqlite',
|
||||||
|
database: 'ems.db',
|
||||||
|
synchronize: true,
|
||||||
|
name: 'sqliteConnection'
|
||||||
|
}),
|
||||||
|
TypeOrmModule.forRoot({
|
||||||
|
type: 'mssql',
|
||||||
|
host: process.env.FUEL_DB_HOST,
|
||||||
|
port: 1433,
|
||||||
|
username: process.env.FUEL_DB_USER,
|
||||||
|
password: process.env.FUEL_DB_PASSWORD,
|
||||||
|
database: 'isFuels',
|
||||||
|
options: {
|
||||||
|
encrypt: false,
|
||||||
|
trustServerCertificate: true
|
||||||
|
},
|
||||||
|
synchronize: false,
|
||||||
|
autoLoadEntities: true,
|
||||||
|
name: 'fuelConnection'
|
||||||
|
}),
|
||||||
|
TypeOrmModule.forRoot({
|
||||||
|
type: 'mssql',
|
||||||
|
host: process.env.EMS_DB_HOST,
|
||||||
|
port: Number(process.env.EMS_DB_PORT) || 1433,
|
||||||
|
username: process.env.EMS_DB_USER,
|
||||||
|
password: process.env.EMS_DB_PASSWORD,
|
||||||
|
database: process.env.EMS_DB_NAME,
|
||||||
|
options: {
|
||||||
|
encrypt: false,
|
||||||
|
trustServerCertificate: true
|
||||||
|
},
|
||||||
|
synchronize: false,
|
||||||
|
autoLoadEntities: true,
|
||||||
|
name: 'emsConnection'
|
||||||
|
}),
|
||||||
|
TypeOrmModule.forRoot({
|
||||||
|
type: 'mssql',
|
||||||
|
host: process.env.GENERAL_DB_HOST,
|
||||||
|
port: Number(process.env.GENERAL_DB_PORT) || 1433,
|
||||||
|
username: process.env.GENERAL_DB_USER,
|
||||||
|
password: process.env.GENERAL_DB_PASSWORD,
|
||||||
|
database: process.env.GENERAL_DB_NAME,
|
||||||
|
options: {
|
||||||
|
encrypt: false,
|
||||||
|
trustServerCertificate: true
|
||||||
|
},
|
||||||
|
synchronize: false,
|
||||||
|
autoLoadEntities: true,
|
||||||
|
name: 'generalConnection'
|
||||||
|
}),
|
||||||
|
// TypeOrmModule.forRoot({
|
||||||
|
// type: 'postgres',
|
||||||
|
// host: process.env.PG_HOST,
|
||||||
|
// port: Number(process.env.PG_PORT) || 5432,
|
||||||
|
// username: process.env.PG_USER,
|
||||||
|
// password: process.env.PG_PASSWORD,
|
||||||
|
// database: process.env.PG_DB,
|
||||||
|
// synchronize: false,
|
||||||
|
// autoLoadEntities: true,
|
||||||
|
// name: 'pgConnection'
|
||||||
|
// }),
|
||||||
|
FuelModule,
|
||||||
|
GeneralModule,
|
||||||
|
EmsModule,
|
||||||
|
TilesModule,
|
||||||
|
GisModule,
|
||||||
|
],
|
||||||
|
controllers: [AppController],
|
||||||
|
providers: [AppService],
|
||||||
|
})
|
||||||
|
export class AppModule { }
|
||||||
8
server/src/app.service.ts
Normal file
8
server/src/app.service.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AppService {
|
||||||
|
getHello(): string {
|
||||||
|
return 'Hello World!';
|
||||||
|
}
|
||||||
|
}
|
||||||
12
server/src/constants/ems.ts
Normal file
12
server/src/constants/ems.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { Extent } from "../interfaces/map"
|
||||||
|
|
||||||
|
const epsg3857extent = [
|
||||||
|
-20037508.342789244,
|
||||||
|
-20037508.342789244,
|
||||||
|
20037508.342789244,
|
||||||
|
20037508.342789244
|
||||||
|
] as Extent
|
||||||
|
|
||||||
|
export {
|
||||||
|
epsg3857extent
|
||||||
|
}
|
||||||
22
server/src/ems/dto/get-figures.ts
Normal file
22
server/src/ems/dto/get-figures.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger"
|
||||||
|
import { IsNumberString, IsOptional } from "class-validator"
|
||||||
|
|
||||||
|
export class GetFiguresDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumberString()
|
||||||
|
city_id: number
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
|
@IsNumberString()
|
||||||
|
@IsOptional()
|
||||||
|
offset?: number
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
|
@IsNumberString()
|
||||||
|
@IsOptional()
|
||||||
|
limit?: number
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumberString()
|
||||||
|
year: number
|
||||||
|
}
|
||||||
19
server/src/ems/dto/get-images.ts
Normal file
19
server/src/ems/dto/get-images.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { ApiPropertyOptional } from "@nestjs/swagger"
|
||||||
|
import { IsNumberString, IsOptional } from "class-validator"
|
||||||
|
|
||||||
|
export class GetImagesDTO {
|
||||||
|
@ApiPropertyOptional()
|
||||||
|
@IsNumberString()
|
||||||
|
@IsOptional()
|
||||||
|
city_id?: number
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
|
@IsNumberString()
|
||||||
|
@IsOptional()
|
||||||
|
offset?: number
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
|
@IsNumberString()
|
||||||
|
@IsOptional()
|
||||||
|
limit?: number
|
||||||
|
}
|
||||||
18
server/src/ems/ems.controller.spec.ts
Normal file
18
server/src/ems/ems.controller.spec.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { EmsController } from './ems.controller';
|
||||||
|
|
||||||
|
describe('EmsController', () => {
|
||||||
|
let controller: EmsController;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
controllers: [EmsController],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
controller = module.get<EmsController>(EmsController);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(controller).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
26
server/src/ems/ems.controller.ts
Normal file
26
server/src/ems/ems.controller.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { Controller, Get, Query } from '@nestjs/common';
|
||||||
|
import { EmsService } from './ems.service';
|
||||||
|
import { GetImagesDTO } from './dto/get-images';
|
||||||
|
import { GetFiguresDTO } from './dto/get-figures';
|
||||||
|
|
||||||
|
@Controller('ems')
|
||||||
|
export class EmsController {
|
||||||
|
constructor(private readonly emsService: EmsService) { }
|
||||||
|
|
||||||
|
@Get('/regions')//✅
|
||||||
|
async getRegions() {
|
||||||
|
return this.emsService.getTypeRoles()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('/images')//✅
|
||||||
|
async getImages(@Query() getImagesDTO: GetImagesDTO) {
|
||||||
|
const { city_id, limit, offset } = getImagesDTO
|
||||||
|
return this.emsService.getImages(city_id, offset, limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('/figures')
|
||||||
|
async getFigures(@Query() getFiguresDTO: GetFiguresDTO) {
|
||||||
|
const { offset, limit, year, city_id } = getFiguresDTO
|
||||||
|
return this.emsService.getFigures(year, city_id, offset, limit)
|
||||||
|
}
|
||||||
|
}
|
||||||
9
server/src/ems/ems.module.ts
Normal file
9
server/src/ems/ems.module.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { EmsController } from './ems.controller';
|
||||||
|
import { EmsService } from './ems.service';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
controllers: [EmsController],
|
||||||
|
providers: [EmsService]
|
||||||
|
})
|
||||||
|
export class EmsModule {}
|
||||||
18
server/src/ems/ems.service.spec.ts
Normal file
18
server/src/ems/ems.service.spec.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { EmsService } from './ems.service';
|
||||||
|
|
||||||
|
describe('EmsService', () => {
|
||||||
|
let service: EmsService;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [EmsService],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
service = module.get<EmsService>(EmsService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(service).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
40
server/src/ems/ems.service.ts
Normal file
40
server/src/ems/ems.service.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { InjectDataSource } from '@nestjs/typeorm';
|
||||||
|
import { DataSource } from 'typeorm';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class EmsService {
|
||||||
|
constructor(
|
||||||
|
@InjectDataSource('emsConnection')
|
||||||
|
private dataSource: DataSource
|
||||||
|
) { }
|
||||||
|
|
||||||
|
async getTypeRoles(): Promise<any[]> {
|
||||||
|
const result = await this.dataSource.query(`
|
||||||
|
SELECT * FROM "TypeRoles";
|
||||||
|
`)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
async getImages(city_id?: number, offset?: number, limit?: number): Promise<any[]> {
|
||||||
|
const result = await this.dataSource.query(`
|
||||||
|
SELECT * FROM "images"
|
||||||
|
${city_id ? `WHERE city_id = ${city_id}` : ''}
|
||||||
|
ORDER BY city_id
|
||||||
|
OFFSET ${offset || 0} ROWS
|
||||||
|
FETCH NEXT ${limit || 10} ROWS ONLY;
|
||||||
|
`)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
async getFigures(year: number, city_id: number, offset?: number, limit?: number): Promise<any[]> {
|
||||||
|
const result = await this.dataSource.query(`
|
||||||
|
SELECT * FROM figures f
|
||||||
|
JOIN vObjects o ON f.object_id = o.object_id WHERE o.id_city = ${city_id} AND f.year = ${year}
|
||||||
|
ORDER BY f.year
|
||||||
|
OFFSET ${Number(offset) || 0} ROWS
|
||||||
|
FETCH NEXT ${Number(limit) || 10} ROWS ONLY;
|
||||||
|
`)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
22
server/src/fuel/dto/create-expense.ts
Normal file
22
server/src/fuel/dto/create-expense.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { ApiProperty } from "@nestjs/swagger"
|
||||||
|
import { Type } from "class-transformer"
|
||||||
|
import { IsDate, IsNumber, IsUUID } from "class-validator"
|
||||||
|
|
||||||
|
export class CreateExpenseDto {
|
||||||
|
@ApiProperty({ format: 'uuid' })
|
||||||
|
@IsUUID()
|
||||||
|
id_boiler: string
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
id_fuel: number
|
||||||
|
|
||||||
|
@ApiProperty({ type: String, format: 'date-time' })
|
||||||
|
@Type(() => Date)
|
||||||
|
@IsDate()
|
||||||
|
date: Date
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
value: number
|
||||||
|
}
|
||||||
24
server/src/fuel/dto/create-limit.ts
Normal file
24
server/src/fuel/dto/create-limit.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { ApiProperty } from "@nestjs/swagger";
|
||||||
|
import { IsNumber, IsUUID } from "class-validator";
|
||||||
|
|
||||||
|
export class CreateLimitDto {
|
||||||
|
@ApiProperty({ format: 'uuid' })
|
||||||
|
@IsUUID()
|
||||||
|
id_boiler: string
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
id_fuel: number
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
month: Date
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
year: number
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
value: number
|
||||||
|
}
|
||||||
26
server/src/fuel/dto/create-transfer.ts
Normal file
26
server/src/fuel/dto/create-transfer.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { ApiProperty } from "@nestjs/swagger"
|
||||||
|
import { Type } from "class-transformer"
|
||||||
|
import { IsDate, IsNumber, IsUUID } from "class-validator"
|
||||||
|
|
||||||
|
export class CreateTransferDto {
|
||||||
|
@ApiProperty({ format: 'uuid' })
|
||||||
|
@IsUUID()
|
||||||
|
id_out: string
|
||||||
|
|
||||||
|
@ApiProperty({ format: 'uuid' })
|
||||||
|
@IsUUID()
|
||||||
|
id_in: string
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
id_fuel: number
|
||||||
|
|
||||||
|
@ApiProperty({ type: String, format: 'date-time' })
|
||||||
|
@Type(() => Date)
|
||||||
|
@IsDate()
|
||||||
|
date: Date
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
value: number
|
||||||
|
}
|
||||||
22
server/src/fuel/dto/expense.ts
Normal file
22
server/src/fuel/dto/expense.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { ApiProperty } from "@nestjs/swagger"
|
||||||
|
import { Type } from "class-transformer"
|
||||||
|
import { IsDate, IsNumber, IsUUID } from "class-validator"
|
||||||
|
|
||||||
|
export class FuelExpenseDto {
|
||||||
|
@ApiProperty({ format: 'uuid' })
|
||||||
|
@IsUUID()
|
||||||
|
id_boiler: string
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
id_fuel: number
|
||||||
|
|
||||||
|
@ApiProperty({ type: String, format: 'date-time' })
|
||||||
|
@Type(() => Date)
|
||||||
|
@IsDate()
|
||||||
|
date: Date
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
value: number
|
||||||
|
}
|
||||||
24
server/src/fuel/dto/limit.ts
Normal file
24
server/src/fuel/dto/limit.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { ApiProperty } from "@nestjs/swagger"
|
||||||
|
import { IsNumber, IsUUID } from "class-validator"
|
||||||
|
|
||||||
|
export class FuelLimitDto {
|
||||||
|
@ApiProperty({ format: 'uuid' })
|
||||||
|
@IsUUID()
|
||||||
|
id_boiler: string
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
id_fuel: number
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
month: Date
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
year: number
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
value: number
|
||||||
|
}
|
||||||
26
server/src/fuel/dto/transfer.ts
Normal file
26
server/src/fuel/dto/transfer.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { ApiProperty } from "@nestjs/swagger"
|
||||||
|
import { Type } from "class-transformer"
|
||||||
|
import { IsDate, IsNumber, IsUUID } from "class-validator"
|
||||||
|
|
||||||
|
export class FuelTransferDto {
|
||||||
|
@ApiProperty({ format: 'uuid' })
|
||||||
|
@IsUUID()
|
||||||
|
id_out: string
|
||||||
|
|
||||||
|
@ApiProperty({ format: 'uuid' })
|
||||||
|
@IsUUID()
|
||||||
|
id_in: string
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
id_fuel: number
|
||||||
|
|
||||||
|
@ApiProperty({ type: String, format: 'date-time' })
|
||||||
|
@Type(() => Date)
|
||||||
|
@IsDate()
|
||||||
|
date: Date
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
value: number
|
||||||
|
}
|
||||||
18
server/src/fuel/fuel.controller.spec.ts
Normal file
18
server/src/fuel/fuel.controller.spec.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { FuelController } from './fuel.controller';
|
||||||
|
|
||||||
|
describe('FuelController', () => {
|
||||||
|
let controller: FuelController;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
controllers: [FuelController],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
controller = module.get<FuelController>(FuelController);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(controller).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
73
server/src/fuel/fuel.controller.ts
Normal file
73
server/src/fuel/fuel.controller.ts
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import { Body, Controller, Get, Post } from '@nestjs/common'
|
||||||
|
import { FuelService } from './fuel.service'
|
||||||
|
import { CreateExpenseDto } from './dto/create-expense'
|
||||||
|
import { CreateLimitDto } from './dto/create-limit'
|
||||||
|
import { CreateTransferDto } from './dto/create-transfer'
|
||||||
|
import { FuelLimitDto } from './dto/limit'
|
||||||
|
import { ApiOkResponse } from '@nestjs/swagger'
|
||||||
|
import { FuelExpenseDto } from './dto/expense'
|
||||||
|
import { FuelTransferDto } from './dto/transfer'
|
||||||
|
|
||||||
|
@Controller('fuel')
|
||||||
|
export class FuelController {
|
||||||
|
constructor(private readonly fuelService: FuelService) { }
|
||||||
|
|
||||||
|
@Get('/columns')
|
||||||
|
async getColumnDataTypes() {
|
||||||
|
return this.fuelService.getColumnDataTypes('BoilersFuelsExpenses')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Fuel limits
|
||||||
|
@Get('/limits')
|
||||||
|
@ApiOkResponse({
|
||||||
|
description: 'List of fuel expenses',
|
||||||
|
type: FuelLimitDto,
|
||||||
|
isArray: true,
|
||||||
|
})
|
||||||
|
async getBoilersFuelsLimits(): Promise<FuelLimitDto[]> {
|
||||||
|
return this.fuelService.getBoilersFuelsLimits()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/limits')
|
||||||
|
async addBoilersFuelsLimit(@Body() createLimitDto: CreateLimitDto) {
|
||||||
|
return this.fuelService.addBoilersFuelsLimit(createLimitDto)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Fuel expenses
|
||||||
|
@Get('/expenses')
|
||||||
|
@ApiOkResponse({
|
||||||
|
description: 'List of fuel expenses',
|
||||||
|
type: FuelExpenseDto,
|
||||||
|
isArray: true,
|
||||||
|
})
|
||||||
|
async getBoilersFuelsExpenses(): Promise<FuelExpenseDto[]> {
|
||||||
|
return this.fuelService.getBoilersFuelsExpenses()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/expenses')
|
||||||
|
async addBoilersFuelsExpense(@Body() createExpenseDto: CreateExpenseDto) {
|
||||||
|
return this.fuelService.addBoilersFuelsExpense(createExpenseDto)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Fuel transfer
|
||||||
|
@Get('/transfer')
|
||||||
|
@ApiOkResponse({
|
||||||
|
description: 'List of fuel expenses',
|
||||||
|
type: FuelTransferDto,
|
||||||
|
isArray: true,
|
||||||
|
})
|
||||||
|
async getFuelsTransfer(): Promise<FuelTransferDto[]> {
|
||||||
|
return this.fuelService.getFuelsTransfer()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/transfer')
|
||||||
|
async addFuelTransfer(@Body() createTransferDto: CreateTransferDto) {
|
||||||
|
return this.fuelService.addFuelsTransfer(createTransferDto)
|
||||||
|
}
|
||||||
|
}
|
||||||
9
server/src/fuel/fuel.module.ts
Normal file
9
server/src/fuel/fuel.module.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { FuelController } from './fuel.controller';
|
||||||
|
import { FuelService } from './fuel.service';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
controllers: [FuelController],
|
||||||
|
providers: [FuelService]
|
||||||
|
})
|
||||||
|
export class FuelModule {}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user