@opengis/gis 0.1.76 → 0.1.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +577 -577
- package/dist/index.umd.cjs +4 -4
- package/module/cls.json +6 -0
- package/module/test/cls/bp_build_type.json +37 -0
- package/module/test/cls/doc_status.json +32 -0
- package/module/test/select/core.user_uid.sql +1 -0
- package/package.json +14 -5
- package/server/routes/gis/index.mjs +13 -1
- package/server/routes/gis/registers/funcs/classifiers.js +47 -1
- package/server/routes/gis/registers/funcs/handleRegistryRequest.js +10 -2
- package/server/routes/gis/services/add.service.js +30 -0
- package/server/routes/gis/services/del.service.js +13 -0
- package/server/routes/gis/services/get.services.js +43 -0
- package/server/routes/map/controllers/vtile.js +20 -2
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "1",
|
|
4
|
+
"text": "Нове будівництво",
|
|
5
|
+
"color": "#34c0ea"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"id": "2",
|
|
9
|
+
"text": "Реконструкція",
|
|
10
|
+
"color": "#b54aa2"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"id": "3",
|
|
14
|
+
"text": "Реставрація",
|
|
15
|
+
"color": "#7f74da"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "4",
|
|
19
|
+
"text": "Капітальний ремонт",
|
|
20
|
+
"color": "#f8ac59"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"id": "5",
|
|
24
|
+
"text": "Реконструкція без зміни зовнішніх геометричних розмірів",
|
|
25
|
+
"color": "#17a2b8"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "6",
|
|
29
|
+
"text": "Реставрація без зміни зовнішніх геометричних розмірів",
|
|
30
|
+
"color": "#F08FA1"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"id": "7",
|
|
34
|
+
"text": "Існуюча забудова",
|
|
35
|
+
"color": "green"
|
|
36
|
+
}
|
|
37
|
+
]
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "1",
|
|
4
|
+
"text": "Діючий",
|
|
5
|
+
"color": "#1ab394"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"id": "2",
|
|
9
|
+
"text": "Зупинений",
|
|
10
|
+
"color": "#ed82c8"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"id": "3",
|
|
14
|
+
"text": "Скасований",
|
|
15
|
+
"color": "#4a4a4a"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "5",
|
|
19
|
+
"text": "Проектний",
|
|
20
|
+
"color": "#6495ed"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"id": "7",
|
|
24
|
+
"text": "Очікує розгляду",
|
|
25
|
+
"color": "#92b8ef"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "10",
|
|
29
|
+
"text": "Архівний",
|
|
30
|
+
"color": "#d48428"
|
|
31
|
+
}
|
|
32
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
select uid, coalesce(coalesce(sur_name,'')||coalesce(' '||user_name,'') ||coalesce(' '||father_name,''),login) as text from admin.users
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengis/gis",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.78",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "Softpro",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -31,12 +31,17 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@mapbox/sphericalmercator": "1.2.0",
|
|
34
|
-
"carto": "0.16.3"
|
|
34
|
+
"carto": "0.16.3",
|
|
35
|
+
"yaml": "2.8.1",
|
|
36
|
+
"@opengis/form": "^0.0.28"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"@opengis/fastify-table": "^1.5.4"
|
|
35
40
|
},
|
|
36
41
|
"devDependencies": {
|
|
37
|
-
"@opengis/core": "^0.0.
|
|
42
|
+
"@opengis/core": "^0.0.23",
|
|
38
43
|
"@opengis/fastify-auth": "^1.1.22",
|
|
39
|
-
"@opengis/fastify-table": "^1.4
|
|
44
|
+
"@opengis/fastify-table": "^1.5.4",
|
|
40
45
|
"@opengis/filter": "^0.1.7",
|
|
41
46
|
"@vitejs/plugin-vue": "^5.2.3",
|
|
42
47
|
"axios": "^1.11.0",
|
|
@@ -45,8 +50,12 @@
|
|
|
45
50
|
"lucide-vue-next": "^0.514.0",
|
|
46
51
|
"sass-embedded": "1.86.3",
|
|
47
52
|
"vite": "^6.3.5",
|
|
53
|
+
"vitest": "^3.2.4",
|
|
48
54
|
"vue": "^3.5.13",
|
|
49
55
|
"vue-router": "4.5.1",
|
|
50
|
-
"vuedraggable": "^4.1.0"
|
|
56
|
+
"vuedraggable": "^4.1.0",
|
|
57
|
+
"yaml": "^2.8.1",
|
|
58
|
+
"typescript": "^5.9.2",
|
|
59
|
+
"@opengis/table": "^0.0.27"
|
|
51
60
|
}
|
|
52
61
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import fp from 'fastify-plugin';
|
|
2
|
+
|
|
1
3
|
import insertColumns from './registers/insert.columns.js';
|
|
2
4
|
import insertFilters from './registers/insert.filters.js';
|
|
3
5
|
import metadataXML from './metadata/metadataXML.js';
|
|
@@ -6,8 +8,11 @@ import gisRegistry from './registers/gis.registry.js';
|
|
|
6
8
|
import gisRegistryList from './registers/gis.registry.list.js';
|
|
7
9
|
import mapRegistry from './registers/map.registry.js';
|
|
8
10
|
import gisExport from './registers/gis.export.js';
|
|
11
|
+
import getServices from './services/get.services.js';
|
|
12
|
+
import deleteService from './services/del.service.js';
|
|
13
|
+
import addService from './services/add.service.js';
|
|
9
14
|
|
|
10
|
-
|
|
15
|
+
async function route(app) {
|
|
11
16
|
app.put('/insert-columns/:token', insertColumns);
|
|
12
17
|
app.put('/insert-filters/:token', insertFilters);
|
|
13
18
|
app.get('/gis-registry/:slug', { config: { policy: ['public'] } }, gisRegistry);
|
|
@@ -20,4 +25,11 @@ export default async function route(app) {
|
|
|
20
25
|
app.get('/get-layer-geom/:id', { config: { policy: ['public'] } }, getLayerGeom);
|
|
21
26
|
|
|
22
27
|
app.get('/gis-export/:type/:slug', { config: { policy: ['public'] } }, gisExport);
|
|
28
|
+
|
|
29
|
+
app.get('/gis-service/:id?', { config: { policy: ['public'] } }, getServices);
|
|
30
|
+
app.post('/gis-service/:id?', { config: { policy: ['public'] } }, addService);
|
|
31
|
+
app.put('/gis-service/:id', { config: { policy: ['public'] } }, addService);
|
|
32
|
+
app.delete('/gis-service/:id', { config: { policy: ['public'] } }, deleteService);
|
|
23
33
|
}
|
|
34
|
+
|
|
35
|
+
export default route;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getSelectVal } from '@opengis/fastify-table/utils.js';
|
|
1
|
+
import { getSelectVal, getSelect } from '@opengis/fastify-table/utils.js';
|
|
2
2
|
|
|
3
3
|
export async function attachClassifiers(rowOrRows, classifiers = []) {
|
|
4
4
|
const rows = Array.isArray(rowOrRows) ? rowOrRows : [rowOrRows];
|
|
@@ -35,3 +35,49 @@ export async function attachClassifiers(rowOrRows, classifiers = []) {
|
|
|
35
35
|
|
|
36
36
|
return rowOrRows;
|
|
37
37
|
}
|
|
38
|
+
|
|
39
|
+
export async function populateFilterOptions({ pg, table, filters, columns, whereConditions }) {
|
|
40
|
+
if (!filters?.length || !table || !columns?.length) return;
|
|
41
|
+
|
|
42
|
+
const optimizedSQL = `select * from ${table} where ${whereConditions || '1=1'}`;
|
|
43
|
+
|
|
44
|
+
await Promise.all(
|
|
45
|
+
filters
|
|
46
|
+
.filter(
|
|
47
|
+
(el) =>
|
|
48
|
+
el.id &&
|
|
49
|
+
el.type !== "Autocomplete" &&
|
|
50
|
+
!el.sql &&
|
|
51
|
+
!el.options?.find?.((item) => item.sql)
|
|
52
|
+
)
|
|
53
|
+
.map(async (el) => {
|
|
54
|
+
const cls = el.data ? await getSelect(el.data, pg) : null;
|
|
55
|
+
|
|
56
|
+
if (!cls && !el.type?.includes?.("Check")) return;
|
|
57
|
+
const { dataTypeID } = (columns || []).find((item) => item.name === el.id) || {};
|
|
58
|
+
|
|
59
|
+
const q = pg.pgType[dataTypeID || '']?.includes("[]")
|
|
60
|
+
? `select unnest(${el.id})::text as id,count(*) from (${optimizedSQL})q group by unnest(${el.id}) limit 100`
|
|
61
|
+
: `select ${el.id}::text as id,count(*) from (${optimizedSQL})q group by ${el.id} limit 100`;
|
|
62
|
+
|
|
63
|
+
const countArr = await pg.queryCache(q, { table });
|
|
64
|
+
|
|
65
|
+
if (countArr.timeout) {
|
|
66
|
+
Object.assign(el, { timeout: countArr.timeout });
|
|
67
|
+
console.warn("timeout filter", table, el.id);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const ids = countArr.rows.map((el1) => el1.id);
|
|
71
|
+
|
|
72
|
+
const clsData = await getSelectVal({ pg, values: ids, name: el.data });
|
|
73
|
+
|
|
74
|
+
const options = countArr.rows.map((cel) => {
|
|
75
|
+
const data = cls?.arr?.find?.(
|
|
76
|
+
(c) => c.id?.toString?.() === cel.id?.toString?.()
|
|
77
|
+
) || { text: clsData?.[cel.id]?.text || clsData?.[cel.id] || cel.id };
|
|
78
|
+
return { ...cel, id: cel.id === null ? "null" : cel.id, ...data };
|
|
79
|
+
});
|
|
80
|
+
Object.assign(el, { options });
|
|
81
|
+
})
|
|
82
|
+
);
|
|
83
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { attachClassifiers } from './classifiers.js';
|
|
1
|
+
import { attachClassifiers, populateFilterOptions } from './classifiers.js';
|
|
2
2
|
import { extractVisibleColumns } from './columns.js';
|
|
3
3
|
import { getMeta, getFilterSQL } from "@opengis/fastify-table/utils.js";
|
|
4
4
|
|
|
@@ -26,7 +26,7 @@ export async function handleRegistryRequest({ settings, query, object_id, offset
|
|
|
26
26
|
|
|
27
27
|
if (object_id) {
|
|
28
28
|
const sql = `
|
|
29
|
-
SELECT "${pk}" as id, ${selectColumns.join(", ")} ${geom ? `, st_asgeojson(${geom})::json as geom` : ''}
|
|
29
|
+
SELECT "${pk}" as id,* , ${selectColumns.join(", ")} ${geom ? `, st_asgeojson(${geom})::json as geom` : ''}
|
|
30
30
|
FROM ${table_name}
|
|
31
31
|
WHERE ${pk} = $1
|
|
32
32
|
`;
|
|
@@ -84,6 +84,14 @@ export async function handleRegistryRequest({ settings, query, object_id, offset
|
|
|
84
84
|
if (col.view_type === 'subtitle') listConfig.subtitle = col.name;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
await populateFilterOptions({
|
|
88
|
+
pg,
|
|
89
|
+
table: table_name,
|
|
90
|
+
filters: activeFilters,
|
|
91
|
+
columns,
|
|
92
|
+
whereConditions
|
|
93
|
+
});
|
|
94
|
+
|
|
87
95
|
return {
|
|
88
96
|
register_id,
|
|
89
97
|
name,
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { dataInsert, dataUpdate, pgClients } from "@opengis/fastify-table/utils.js";
|
|
2
|
+
|
|
3
|
+
export default async function addService({
|
|
4
|
+
method, params = {}, body, pg = pgClients.client, user = {},
|
|
5
|
+
}, reply) {
|
|
6
|
+
if (method === 'PUT' && !params.id) {
|
|
7
|
+
return reply.status(400).send('not enough params: id');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (method === 'POST') {
|
|
11
|
+
const { rows = [] } = await dataInsert({
|
|
12
|
+
pg,
|
|
13
|
+
id: params.id,
|
|
14
|
+
table: 'gis.services',
|
|
15
|
+
data: body,
|
|
16
|
+
uid: user?.uid,
|
|
17
|
+
});
|
|
18
|
+
return reply.status(200).send(rows[0]);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const row = await dataUpdate({
|
|
22
|
+
pg,
|
|
23
|
+
id: params.id,
|
|
24
|
+
table: 'gis.services',
|
|
25
|
+
data: body,
|
|
26
|
+
uid: user?.uid,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return reply.status(200).send(row);
|
|
30
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { dataDelete, pgClients } from "@opengis/fastify-table/utils.js";
|
|
2
|
+
|
|
3
|
+
export default async function deleteService({
|
|
4
|
+
params = {}, pg = pgClients.client, user = {},
|
|
5
|
+
}, reply) {
|
|
6
|
+
const row = await dataDelete({
|
|
7
|
+
pg,
|
|
8
|
+
id: params.id,
|
|
9
|
+
table: 'gis.services',
|
|
10
|
+
uid: user?.uid,
|
|
11
|
+
});
|
|
12
|
+
return reply.status(200).send(row);
|
|
13
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { getMeta, pgClients, yml2json } from "@opengis/fastify-table/utils.js";
|
|
2
|
+
|
|
3
|
+
const table = 'gis.services';
|
|
4
|
+
|
|
5
|
+
const columnType = {
|
|
6
|
+
text: 'text',
|
|
7
|
+
date: 'date',
|
|
8
|
+
bool: 'yes/no',
|
|
9
|
+
numeric: 'number',
|
|
10
|
+
integer: 'number',
|
|
11
|
+
'timestamp without time zone': 'date',
|
|
12
|
+
'timestamp with time zone': 'date',
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default async function getServices({ params = {}, pg = pgClients.client }, reply) {
|
|
16
|
+
const { columns = [] } = await getMeta({ pg, table }) || {};
|
|
17
|
+
|
|
18
|
+
const fields = columns.map(({ name, dataTypeID, title }) => ({ name, type: columnType[pg.pgType?.[dataTypeID] || 'text'], label: title || name }));
|
|
19
|
+
|
|
20
|
+
const rows = await pg.query(`
|
|
21
|
+
SELECT
|
|
22
|
+
service_id, service_key, name, description, keywords, category, holder, group_id, service_type,
|
|
23
|
+
source_type, service_url, source_path, query, geom_type, geometry_column, sql_list, attributes, filters,
|
|
24
|
+
popup, style, legend, card, srid, st_asgeojson(bbox)::json as bbox, st_asgeojson(center)::json as center, is_active as enabled, is_public, is_active, is_downloadable, metadata,
|
|
25
|
+
metadata_url, thumbnail_url, created_by, updated_by, updated_at, created_at
|
|
26
|
+
FROM gis.services where ${params.id ? 'service_id=$1' : '1=1'}
|
|
27
|
+
`, [params.id].filter(Boolean)).then(el => el.rows || []);
|
|
28
|
+
|
|
29
|
+
rows.forEach(row => Object.assign(row, { style: row.style ? yml2json(row.style) : undefined }));
|
|
30
|
+
|
|
31
|
+
if (params.id && !rows.length) {
|
|
32
|
+
return reply.status(404).send('service not found');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (params.id) {
|
|
36
|
+
return reply.status(200).send({ ...rows[0], fields });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return reply.status(200).send({
|
|
40
|
+
rows,
|
|
41
|
+
fields,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -5,7 +5,7 @@ import { readFile, stat, mkdir, writeFile } from 'node:fs/promises';
|
|
|
5
5
|
|
|
6
6
|
import Sphericalmercator from '@mapbox/sphericalmercator';
|
|
7
7
|
|
|
8
|
-
import { getTemplate, pgClients, getFilterSQL, getMeta, yml2json } from '@opengis/fastify-table/utils.js';
|
|
8
|
+
import { getTemplate, pgClients, getFilterSQL, getMeta, yml2json, getColumnCLS, getSelect } from '@opengis/fastify-table/utils.js';
|
|
9
9
|
|
|
10
10
|
import rootFolder from '../../../plugins/mapnik/funcs/rootFolder.mjs';
|
|
11
11
|
|
|
@@ -80,6 +80,8 @@ export default async function vtile({ pg = pgClients.client, params = {}, query
|
|
|
80
80
|
return reply.status(404).send('layer table not found');
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
const cls = await getColumnCLS(table);
|
|
84
|
+
|
|
83
85
|
const meta = await getMeta({ pg, table });
|
|
84
86
|
const { columns = [] } = meta || {};
|
|
85
87
|
|
|
@@ -100,13 +102,29 @@ export default async function vtile({ pg = pgClients.client, params = {}, query
|
|
|
100
102
|
: `${el.name}${['int4'].includes(el.type) ? '::text' : ''}`;
|
|
101
103
|
});
|
|
102
104
|
|
|
105
|
+
const propsColumns = props.length ? await Promise.all(props.map(async colname => {
|
|
106
|
+
if (!cls?.[colname]) return `"${colname}"`;
|
|
107
|
+
const { type, data } = await pg.queryCache('select type, data from admin.cls where parent is null and name=$1 limit 1', { args: [cls[colname]], table: 'admin.cls' })
|
|
108
|
+
.then(el => el.rows?.[0] || {}) || {};
|
|
109
|
+
|
|
110
|
+
if (!type || type === 'sql' && !data) {
|
|
111
|
+
return `"${colname}"`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (type === 'json') {
|
|
115
|
+
return `(select name from admin.cls where parent='${cls[colname]}' and code="${colname}"::text) as "${colname}"`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return `(with c(id,text) as (select * from (${data})q limit 1) select text from c where id::text="${colname}"::text) as "${colname}"`;
|
|
119
|
+
})) : '';
|
|
120
|
+
|
|
103
121
|
const q = `SELECT ST_AsMVT(q, '${id.replace(/'/g, "''")}', 4096, 'geom','row') as tile
|
|
104
122
|
FROM (
|
|
105
123
|
SELECT
|
|
106
124
|
|
|
107
125
|
floor(random() * 100000 + 1)::int + row_number() over() as row,
|
|
108
126
|
|
|
109
|
-
${style?.colorAttr ? `${style.colorAttr},` : ''} ${
|
|
127
|
+
${style?.colorAttr ? `${style.colorAttr},` : ''} ${propsColumns ? `${propsColumns.filter(Boolean).join('\n,') || ''},` : ''}
|
|
110
128
|
|
|
111
129
|
${pk} as id,
|
|
112
130
|
ST_AsMVTGeom(st_transform(${style?.type === 'point' ? `st_pointonsurface(${geomCol})` : geomCol},3857),ST_TileEnvelope(${z},${y},${x})::box2d,4096,256,true) geom
|