@opengis/gis 0.2.2 → 0.2.4
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.css +1 -1
- package/dist/index.js +3277 -3229
- package/dist/index.umd.cjs +51 -36
- package/module/test/layer/individual.yml +54 -0
- package/package.json +1 -1
- package/plugin.js +4 -2
- package/server/routes/gis/services/get.services.col.js +19 -18
- package/server/routes/gis/services/get.services.js +60 -55
- package/server/routes/map/controllers/layerList.js +42 -32
- package/server/routes/map/controllers/mapFormat.js +76 -116
- package/server/routes/map/index.mjs +9 -9
- package/server/routes/map/maps/get.map.js +54 -50
- package/server/routes/map/vtile1.js +76 -81
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Title: Parcel Polygon
|
|
2
|
+
|
|
3
|
+
name: ФОП
|
|
4
|
+
source_path: economy_profile.individual
|
|
5
|
+
query: 1=1
|
|
6
|
+
|
|
7
|
+
style:
|
|
8
|
+
type: point
|
|
9
|
+
color: orange
|
|
10
|
+
width: 1
|
|
11
|
+
border: 1
|
|
12
|
+
opacity: 0.6
|
|
13
|
+
stroke: "#eee"
|
|
14
|
+
|
|
15
|
+
popup:
|
|
16
|
+
- name: registration_date
|
|
17
|
+
meta: title
|
|
18
|
+
- ua: Назва замовника
|
|
19
|
+
name: bp_customer_name
|
|
20
|
+
meta: title
|
|
21
|
+
- label: Реєстраційний номер БП
|
|
22
|
+
name: bp_code
|
|
23
|
+
format: badge
|
|
24
|
+
- label: Адреса
|
|
25
|
+
name: address
|
|
26
|
+
|
|
27
|
+
card:
|
|
28
|
+
- label: Адреса
|
|
29
|
+
name: address
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
filters:
|
|
33
|
+
- name: registration_date
|
|
34
|
+
label: Дата реєстрації
|
|
35
|
+
type: date
|
|
36
|
+
- name: fop_status
|
|
37
|
+
label: Статус
|
|
38
|
+
type: Autocomplete
|
|
39
|
+
data: fop_status
|
|
40
|
+
|
|
41
|
+
- name: address_id
|
|
42
|
+
label: Адреса
|
|
43
|
+
type: Autocomplete
|
|
44
|
+
data: reg_address_id
|
|
45
|
+
- name: kved_main
|
|
46
|
+
label: КВЕД (основний)
|
|
47
|
+
type: Autocomplete
|
|
48
|
+
data: kved_main
|
|
49
|
+
- name: before_local_budget
|
|
50
|
+
label: Податковий борг перед місцевим бюджетом
|
|
51
|
+
type: Range
|
|
52
|
+
- name: before_state_budget
|
|
53
|
+
label: Податковий борг перед державним бюджетом
|
|
54
|
+
type: Range
|
package/package.json
CHANGED
package/plugin.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import fp from 'fastify-plugin';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
config, addHook, getMeta, pgClients, execMigrations,
|
|
5
|
+
} from '@opengis/fastify-table/utils.js';
|
|
4
6
|
|
|
5
7
|
config.prefix = config.prefix || '/api';
|
|
6
8
|
|
|
@@ -38,4 +40,4 @@ async function plugin(app, opts = config) {
|
|
|
38
40
|
Object.assign(payload, { fields: columns?.map?.(({ name, title, dataTypeID }) => ({ name, title: title || name, type: columnType[pg?.pgType?.[dataTypeID] || 'text'] })).filter(el => el.type) });
|
|
39
41
|
});
|
|
40
42
|
}
|
|
41
|
-
export default fp(plugin)
|
|
43
|
+
export default fp(plugin);
|
|
@@ -1,32 +1,33 @@
|
|
|
1
|
-
import { metaFormat, pgClients } from
|
|
1
|
+
import { metaFormat, pgClients, getTemplate } from '@opengis/fastify-table/utils.js';
|
|
2
2
|
|
|
3
3
|
export default async function getServicesCol({ params = {}, pg = pgClients.client }, reply) {
|
|
4
|
-
|
|
4
|
+
const row = await getTemplate('layer', params.id) || await pg.query(`
|
|
5
5
|
SELECT
|
|
6
6
|
service_id, source_path, attributes
|
|
7
7
|
FROM gis.services where ${params.id ? 'service_id=$1' : '1=1'}
|
|
8
8
|
`, [params.id].filter(Boolean)).then(el => el.rows[0] || {});
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
if (!row.source_path) {
|
|
11
|
+
return reply.status(404).send({ code: 404, message: 'source not found' });
|
|
12
|
+
}
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
const fields = await pg.query(` SELECT * FROM ${row.source_path} limit 0`).then(el => el.fields);
|
|
15
|
+
const field = fields.find(el => el.name === params.col);
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
if (!field) {
|
|
18
|
+
return reply.status(404).send({ message: { error: 'column not found', fields }, code: 404 });
|
|
19
|
+
}
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
where ${params.col} is not null group by ${params.col} order by count(*) desc limit 10`
|
|
23
|
-
).then(el => el.rows || []);
|
|
21
|
+
const rows = await pg.query(`SELECT ${params.col}::text as id, ${params.col}, count(*) FROM ${row.source_path}
|
|
22
|
+
where ${params.col} is not null group by ${params.col} order by count(*) desc limit 10`).then(el => el.rows || []);
|
|
24
23
|
|
|
25
|
-
|
|
24
|
+
const cls = row.attributes?.filter?.((col) => col.name && col.data && ['select', 'badge', 'tags'].includes(col.format)).reduce((acc, curr) => ({ ...acc, [curr.name]: curr.data }), {}) || {};
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
await metaFormat({ rows, table: row.source_path, cls });
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
const rows1 = rows.map(row => ({
|
|
29
|
+
...row[`${params.col}_data`], ...row, [`${params.col}_data`]: undefined, [params.col]: undefined,
|
|
30
|
+
}));
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
}
|
|
32
|
+
return reply.status(200).send({ rows: rows1, field, fields });
|
|
33
|
+
}
|
|
@@ -1,17 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
dataUpdate, getMeta, pgClients, yml2json, getTemplate,
|
|
3
|
+
} from '@opengis/fastify-table/utils.js';
|
|
2
4
|
|
|
3
5
|
const columnType = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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',
|
|
11
13
|
};
|
|
12
14
|
|
|
13
15
|
export default async function getServices({ params = {}, pg = pgClients.client }, reply) {
|
|
14
|
-
|
|
16
|
+
const t = await getTemplate('layer', params.id);
|
|
17
|
+
if (t) return t;
|
|
18
|
+
if (!pg.tlist.includes('gis.services')) return { status: 404, message: 'not found' };
|
|
19
|
+
const rows = await pg.query(`
|
|
15
20
|
SELECT
|
|
16
21
|
service_id, service_key, name, description, keywords, category, holder, group_id, b.group_name, service_type,
|
|
17
22
|
source_type, service_url, source_path, query, geom_type, geometry_column, sql_list, attributes, filters,
|
|
@@ -22,58 +27,58 @@ export default async function getServices({ params = {}, pg = pgClients.client }
|
|
|
22
27
|
where ${params.id ? 'service_id=$1' : '1=1'}
|
|
23
28
|
`, [params.id].filter(Boolean)).then(el => el.rows || []);
|
|
24
29
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
if (params.id && !rows.length) {
|
|
31
|
+
return reply.status(404).send('service not found');
|
|
32
|
+
}
|
|
28
33
|
|
|
34
|
+
const totals = pg.queryCache ? await pg.queryCache('select json_object_agg(oid::regclass, reltuples) from pg_class')
|
|
35
|
+
.then(el => el.rows?.[0]?.json_object_agg || {}) : {};
|
|
29
36
|
|
|
30
|
-
|
|
31
|
-
|
|
37
|
+
if (params.id) {
|
|
38
|
+
const html = await pg.query('select body from admin.templates where template_id=$1', [params.id]).then(el => el.rows?.[0]?.body);
|
|
39
|
+
Object.assign(rows[0], { html });
|
|
40
|
+
}
|
|
32
41
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
42
|
+
rows.filter(row => row.source_path).forEach(row => {
|
|
43
|
+
Object.assign(row, { count: totals[row.source_path] || 0 });
|
|
44
|
+
});
|
|
37
45
|
|
|
38
|
-
|
|
39
|
-
Object.assign(row, { count: totals[row.source_path] || 0 });
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
const { columns = [] } = await getMeta({ pg, table: rows[0].source_path }) || {};
|
|
43
|
-
|
|
44
|
-
const fields = columns.map(({ name, dataTypeID, title }) => ({ name, type: columnType[pg.pgType?.[dataTypeID] || 'text'], label: title || name }));
|
|
45
|
-
|
|
46
|
-
const noCenterIds = rows.filter(row => !row.center && row.bbox).map(row => row.service_id);
|
|
47
|
-
|
|
48
|
-
const centers = noCenterIds.length ? await pg.query(`SELECT json_object_agg(service_id, st_pointonsurface(bbox)::json) FROM gis.services where service_id=any($1)`, [noCenterIds].filter(Boolean)).then(el => el.rows?.[0]?.json_object_agg || {}) : {};
|
|
49
|
-
|
|
50
|
-
await Promise.all(rows.filter(row => centers[row.service_id]).map(async (row) => {
|
|
51
|
-
// console.log('update service center', row.service_id, JSON.stringify(centers[row.service_id]));
|
|
52
|
-
await dataUpdate({ pg, id: row.service_id, table: 'gis.services', data: { center: centers[row.service_id] } });
|
|
53
|
-
Object.assign(row, { center: centers[row.service_id] });
|
|
54
|
-
}));
|
|
55
|
-
|
|
56
|
-
rows.forEach(row => Object.assign(row, {
|
|
57
|
-
center: row.center?.coordinates,
|
|
58
|
-
style: row.style ? yml2json(row.style) : undefined
|
|
59
|
-
}));
|
|
60
|
-
rows.filter(row => row.extent).forEach(row => Object.assign(row, {
|
|
61
|
-
extent: row.extent.match(/BOX\(([^)]+)\)/)?.[1]
|
|
62
|
-
?.replace?.(/ /g, ",")
|
|
63
|
-
?.split?.(",")
|
|
64
|
-
}));
|
|
46
|
+
const { columns = [] } = await getMeta({ pg, table: rows[0].source_path }) || {};
|
|
65
47
|
|
|
48
|
+
const fields = columns.map(({ name, dataTypeID, title }) => ({ name, type: columnType[pg.pgType?.[dataTypeID] || 'text'], label: title || name }));
|
|
66
49
|
|
|
67
|
-
|
|
68
|
-
filters: row.filters.map(filter => ({ ...filter, api: '/api/suggest/' + row.source_path + ':' + filter.name + (filter.data && filter.name !== filter.data ? `?sel=${filter.data}` : '') }))
|
|
69
|
-
}));
|
|
50
|
+
const noCenterIds = rows.filter(row => !row.center && row.bbox).map(row => row.service_id);
|
|
70
51
|
|
|
71
|
-
|
|
72
|
-
return reply.status(200).send({ ...rows[0], fields });
|
|
73
|
-
}
|
|
52
|
+
const centers = noCenterIds.length ? await pg.query('SELECT json_object_agg(service_id, st_pointonsurface(bbox)::json) FROM gis.services where service_id=any($1)', [noCenterIds].filter(Boolean)).then(el => el.rows?.[0]?.json_object_agg || {}) : {};
|
|
74
53
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
54
|
+
await Promise.all(rows.filter(row => centers[row.service_id]).map(async (row) => {
|
|
55
|
+
// console.log('update service center', row.service_id, JSON.stringify(centers[row.service_id]));
|
|
56
|
+
await dataUpdate({
|
|
57
|
+
pg, id: row.service_id, table: 'gis.services', data: { center: centers[row.service_id] },
|
|
78
58
|
});
|
|
79
|
-
}
|
|
59
|
+
Object.assign(row, { center: centers[row.service_id] });
|
|
60
|
+
}));
|
|
61
|
+
|
|
62
|
+
rows.forEach(row => Object.assign(row, {
|
|
63
|
+
center: row.center?.coordinates,
|
|
64
|
+
style: row.style ? yml2json(row.style) : undefined,
|
|
65
|
+
}));
|
|
66
|
+
rows.filter(row => row.extent).forEach(row => Object.assign(row, {
|
|
67
|
+
extent: row.extent.match(/BOX\(([^)]+)\)/)?.[1]
|
|
68
|
+
?.replace?.(/ /g, ',')
|
|
69
|
+
?.split?.(','),
|
|
70
|
+
}));
|
|
71
|
+
|
|
72
|
+
rows.filter(row => row.filters).forEach(row => Object.assign(row, {
|
|
73
|
+
filters: row.filters.map(filter => ({ ...filter, api: `/api/suggest/${row.source_path}:${filter.name}${filter.data && filter.name !== filter.data ? `?sel=${filter.data}` : ''}` })),
|
|
74
|
+
}));
|
|
75
|
+
|
|
76
|
+
if (params.id) {
|
|
77
|
+
return reply.status(200).send({ ...rows[0], fields });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return reply.status(200).send({
|
|
81
|
+
rows,
|
|
82
|
+
fields,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
@@ -1,15 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
config, pgClients, yml2json, getTemplates, getTemplate,
|
|
3
|
+
} from '@opengis/fastify-table/utils.js';
|
|
2
4
|
|
|
3
5
|
export default async function layerList({
|
|
4
|
-
|
|
6
|
+
pg = pgClients.client, query = {}, user = {},
|
|
5
7
|
}, reply) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
const { sql } = query;
|
|
9
|
+
const layers = getTemplates('layer');
|
|
10
|
+
const files = Promise.all(layers.map(async (el) => {
|
|
11
|
+
const layer = await getTemplate('layer', el[0]);
|
|
12
|
+
return layer;
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
if (!pg.pk?.['gis.services']) {
|
|
16
|
+
return files;
|
|
17
|
+
// return reply.status(404).send('services table not found');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const q = `
|
|
13
21
|
select service_id as id, name, category, style, bbox::box2d as extent, st_asgeojson(bbox)::json as geom, null as url, coalesce(service_type, 'vtile') as service, group_id,
|
|
14
22
|
popup, card, filters, style, source_path
|
|
15
23
|
from gis.services where is_active and ${!user.uid ? 'is_public' : '1=1'}
|
|
@@ -19,32 +27,34 @@ export default async function layerList({
|
|
|
19
27
|
from gis.ogc_service where enabled and ${!user.uid ? 'ispublic' : '1=1'}
|
|
20
28
|
`;
|
|
21
29
|
|
|
22
|
-
|
|
30
|
+
if (user.uid && sql) return q;
|
|
31
|
+
|
|
32
|
+
const rows = await pg.query(q).then(el => el.rows || []);
|
|
23
33
|
|
|
24
|
-
|
|
34
|
+
const totals = pg.queryCache ? await pg.queryCache('select json_object_agg(oid::regclass, reltuples) from pg_class')
|
|
35
|
+
.then(el => el.rows?.[0]?.json_object_agg || {}) : {};
|
|
36
|
+
rows.filter(row => row.source_path).forEach(row => Object.assign(row, { count: totals[row.source_path] || 0 }));
|
|
25
37
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
38
|
+
const groupIds = rows.map(el => el.group_id).filter(Boolean);
|
|
39
|
+
const groupNames = groupIds.length ? await pg.query('select json_object_agg(group_id,group_name) from gis.group_list where group_id=any($1)', [groupIds]).then(el => el.rows?.[0]?.json_object_agg || {}) : {};
|
|
40
|
+
rows.filter(el => el.group_id).forEach(row => Object.assign(row, { group_name: groupNames[row.group_id] }));
|
|
29
41
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
42
|
+
if (!rows.length) {
|
|
43
|
+
return reply.status(200).send([]);
|
|
44
|
+
}
|
|
33
45
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
46
|
+
// parse service style
|
|
47
|
+
rows.forEach(row => Object.assign(row, { style: row.style ? yml2json(row.style) : null }));
|
|
48
|
+
// assign service url
|
|
49
|
+
rows.filter(row => row.service !== 'ogc').forEach(row => Object.assign(row, { url: `${config.prefix || '/api'}/vtile/${row.id}/ua/{z}/{x}/{y}.vmt` }));
|
|
50
|
+
// parse extent string to number[]
|
|
51
|
+
rows.filter(row => row.extent).forEach(row => Object.assign(row, {
|
|
52
|
+
extent: row.extent.match(/BOX\(([^)]+)\)/)?.[1]
|
|
53
|
+
?.replace?.(/ /g, ',')
|
|
54
|
+
?.split?.(','),
|
|
55
|
+
}));
|
|
37
56
|
|
|
38
|
-
|
|
39
|
-
rows.forEach(row => Object.assign(row, { style: row.style ? yml2json(row.style) : null }));
|
|
40
|
-
// assign service url
|
|
41
|
-
rows.filter(row => row.service !== 'ogc').forEach(row => Object.assign(row, { url: `${config.prefix || '/api'}/vtile/${row.id}/ua/{z}/{x}/{y}.vmt` }));
|
|
42
|
-
// parse extent string to number[]
|
|
43
|
-
rows.filter(row => row.extent).forEach(row => Object.assign(row, {
|
|
44
|
-
extent: row.extent.match(/BOX\(([^)]+)\)/)?.[1]
|
|
45
|
-
?.replace?.(/ /g, ",")
|
|
46
|
-
?.split?.(",")
|
|
47
|
-
}));
|
|
57
|
+
// return files;
|
|
48
58
|
|
|
49
|
-
|
|
50
|
-
}
|
|
59
|
+
return reply.status(200).send(rows.concat(files));
|
|
60
|
+
}
|
|
@@ -1,125 +1,85 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
pgClients, getTemplate, handlebars, metaFormat,
|
|
3
|
+
} from '@opengis/fastify-table/utils.js';
|
|
2
4
|
|
|
3
5
|
export default async function mapFormat(req, reply) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const columns = card;
|
|
54
|
-
if (!source_path) return reply.status(404).send('missing source_path');
|
|
55
|
-
|
|
56
|
-
const pk = pg.pk?.[source_path];
|
|
57
|
-
if (!pk) return reply.status(404).send('missing pk');
|
|
58
|
-
|
|
59
|
-
if (!columns) return reply.status(404).send('columns setting not found');
|
|
60
|
-
|
|
61
|
-
const columnNames = columns.map(col => col.name);
|
|
62
|
-
const excluded = ["created_by", "created_at", "updated_by", "geom", "id", "uid", "updated_at", "cdate", "editor_date", "editor_id"];
|
|
63
|
-
const filteredColumns = columnNames.filter(name => !excluded.includes(name));
|
|
64
|
-
|
|
65
|
-
const rows = await pg.query(
|
|
66
|
-
`SELECT ${pk} as "id", geom::json, ${filteredColumns.map(n => `"${n}"`).join(", ")} FROM ${source_path} WHERE ${pk} = $1`,
|
|
67
|
-
[id]
|
|
68
|
-
).then(el => el.rows || []);
|
|
69
|
-
|
|
70
|
-
if (!rows.length) return reply.status(404).send('object not found');
|
|
71
|
-
|
|
72
|
-
const classifiers = columns
|
|
73
|
-
.filter(col => col.data && ["select", "badge", "tags"].includes(col.format))
|
|
74
|
-
.reduce((acc, curr) => ({ ...acc, [curr.name]: curr.data }), {});
|
|
75
|
-
|
|
76
|
-
await metaFormat({ rows, table: source_path, cls: classifiers, sufix: false });
|
|
77
|
-
const fullRow = rows[0];
|
|
78
|
-
|
|
79
|
-
const result = [];
|
|
80
|
-
for await (const col of columns) {
|
|
81
|
-
if (excluded.includes(col.name)) continue;
|
|
82
|
-
if (col.hidden_card === true) continue;
|
|
83
|
-
|
|
84
|
-
const name = col.label || col.ua || col.name;
|
|
85
|
-
let value;
|
|
86
|
-
value = fullRow[`${col.name}_data`]?.text
|
|
6
|
+
const { pg = pgClients.client, query = {} } = req;
|
|
7
|
+
const { layer, id } = query;
|
|
8
|
+
const time = Date.now();
|
|
9
|
+
|
|
10
|
+
if (!layer || !id) return reply.status(404).send('not enough params: layer,id,map is required');
|
|
11
|
+
|
|
12
|
+
const service = await getTemplate('layer', layer) || (pg.tlist.includes('gis.services') ? await pg.query('SELECT * FROM gis.services WHERE service_id = $1', [layer]).then(res => res.rows[0]) : null);
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
source_path: tname, cardInterface, card, template,
|
|
16
|
+
} = service;
|
|
17
|
+
|
|
18
|
+
const columns = card;
|
|
19
|
+
if (!tname) return reply.status(404).send('missing source_path');
|
|
20
|
+
|
|
21
|
+
const pk = pg.pk?.[tname];
|
|
22
|
+
if (!pk) return reply.status(404).send('missing pk');
|
|
23
|
+
|
|
24
|
+
if (!columns) return reply.status(404).send('columns setting not found');
|
|
25
|
+
|
|
26
|
+
const columnNames = columns.map(col => col.name);
|
|
27
|
+
const excluded = ['created_by', 'created_at', 'updated_by', 'geom', 'id', 'uid', 'updated_at', 'cdate', 'editor_date', 'editor_id'];
|
|
28
|
+
const filteredColumns = columnNames.filter(name => !excluded.includes(name));
|
|
29
|
+
|
|
30
|
+
const rows = await pg.query(
|
|
31
|
+
`SELECT ${pk} as "id", geom::json, ${filteredColumns.map(n => `"${n}"`).join(', ')} FROM ${tname} WHERE ${pk} = $1`,
|
|
32
|
+
[id],
|
|
33
|
+
).then(el => el.rows || []);
|
|
34
|
+
|
|
35
|
+
if (!rows.length) return reply.status(404).send('object not found');
|
|
36
|
+
|
|
37
|
+
const classifiers = columns
|
|
38
|
+
.filter(col => col.data && ['select', 'badge', 'tags'].includes(col.format))
|
|
39
|
+
.reduce((acc, curr) => ({ ...acc, [curr.name]: curr.data }), {});
|
|
40
|
+
|
|
41
|
+
await metaFormat({
|
|
42
|
+
rows, table: tname, cls: classifiers, sufix: false,
|
|
43
|
+
});
|
|
44
|
+
const fullRow = rows[0];
|
|
45
|
+
|
|
46
|
+
const result = [];
|
|
47
|
+
const filtered = columns.filter(col => !excluded.includes(col.name));
|
|
48
|
+
for (let i = 0; i < filtered.length; i += 1) {
|
|
49
|
+
const col = filtered[i];
|
|
50
|
+
|
|
51
|
+
const name = col.label || col.ua || col.name;
|
|
52
|
+
const value = (col.format === 'date' ? new Date(fullRow[col.name]).toLocaleDateString('uk-UA') : null) || fullRow[`${col.name}_data`]?.text
|
|
87
53
|
|| fullRow[`${col.name}_text`]
|
|
88
54
|
|| fullRow[col.name];
|
|
89
55
|
|
|
90
|
-
|
|
91
|
-
// const dt = formatDate(fullRow[col.name], { hash: { format: 'dd.mm.yy' } });
|
|
92
|
-
const dt = await handlebars.compile(`{{formatDate "${fullRow[col.name]}"}}`)({ format: 'dd.mm.yy' });
|
|
93
|
-
value = dt;
|
|
94
|
-
}
|
|
95
|
-
if (!value) continue;
|
|
96
|
-
result.push(`<div class="grid grid-cols-1 gap-1 py-3 sm:grid-cols-3 sm:gap-4 even:bg-gray-50 text-[12px]">
|
|
56
|
+
result.push(`<div class="grid grid-cols-1 gap-1 py-3 sm:grid-cols-3 sm:gap-4 even:bg-gray-50 text-[12px]">
|
|
97
57
|
<dt class="text-gray-900">${name}</dt>
|
|
98
58
|
<dd class="text-gray-700 sm:col-span-2">${value || '-'}</dd>
|
|
99
59
|
</div>`);
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const htmlTemplate = pg?.pk?.['admin.template']
|
|
63
|
+
? await pg.query('select body from admin.templates where name=$1 limit 1', [template || id]).then(el => el.rows?.[0]?.body)
|
|
64
|
+
: null;
|
|
65
|
+
|
|
66
|
+
const html1 = await handlebars.compile(htmlTemplate || 'template not found')(fullRow);
|
|
67
|
+
|
|
68
|
+
const html = template
|
|
69
|
+
? html1
|
|
70
|
+
: `<dl class="divide-y divide-gray-100 py-[5px]">${result.join('')}</dl>`;
|
|
71
|
+
|
|
72
|
+
const res = {
|
|
73
|
+
time: Date.now() - time,
|
|
74
|
+
id,
|
|
75
|
+
rows: fullRow,
|
|
76
|
+
columns,
|
|
77
|
+
template,
|
|
78
|
+
html,
|
|
79
|
+
};
|
|
80
|
+
if (service) {
|
|
81
|
+
res.cardInterface = cardInterface;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return res;
|
|
125
85
|
}
|
|
@@ -29,18 +29,18 @@ const schemaInfo = {
|
|
|
29
29
|
type: 'string',
|
|
30
30
|
},
|
|
31
31
|
z: {
|
|
32
|
-
type: 'number'
|
|
32
|
+
type: 'number',
|
|
33
33
|
},
|
|
34
34
|
y: {
|
|
35
|
-
type: 'number'
|
|
35
|
+
type: 'number',
|
|
36
36
|
},
|
|
37
37
|
x: {
|
|
38
38
|
type: 'string',
|
|
39
|
-
pattern: '^\\d+\\.(pbf|vmt)$'
|
|
39
|
+
pattern: '^\\d+\\.(pbf|vmt)$',
|
|
40
40
|
},
|
|
41
41
|
id: {
|
|
42
|
-
type: 'string'
|
|
43
|
-
}
|
|
42
|
+
type: 'string',
|
|
43
|
+
},
|
|
44
44
|
},
|
|
45
45
|
},
|
|
46
46
|
};
|
|
@@ -70,12 +70,12 @@ export default async function route(app) {
|
|
|
70
70
|
app.get('/layer-rtile/:id/:z/:y/:x', publicParams, rtile);
|
|
71
71
|
app.get('/layer-vtile/:id/:z/:y/:x', publicParams, vtile);
|
|
72
72
|
|
|
73
|
-
if (!app.hasRoute({ method: 'GET', url: '/api/vtile/:layer/:lang/:z/:y/:x'
|
|
74
|
-
console.log(
|
|
73
|
+
if (!app.hasRoute({ method: 'GET', url: '/api/vtile/:layer/:lang/:z/:y/:x' })) {
|
|
74
|
+
console.log('\x1b[34m%s\x1b[0m', 'add vtile from gis');
|
|
75
75
|
app.get('/vtile/:layer/:lang/:z/:y/:x', publicParams, vtile1);
|
|
76
76
|
}
|
|
77
|
-
if (!app.hasRoute({ method: 'GET', url: '/api/gis-layer-list'
|
|
78
|
-
console.log(
|
|
77
|
+
if (!app.hasRoute({ method: 'GET', url: '/api/gis-layer-list' })) {
|
|
78
|
+
console.log('\x1b[34m%s\x1b[0m', 'add gis-layer-list from gis');
|
|
79
79
|
app.get('/gis-layer-list', publicParams, layerList);
|
|
80
80
|
}
|
|
81
81
|
|