@opengis/admin 0.3.105 → 0.3.107
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/{add-page-BtME1JJf.js → add-page-DELwNBs9.js} +1 -1
- package/dist/{admin-interface-mIo1_gE2.js → admin-interface-ChLQ5JCd.js} +1 -1
- package/dist/{admin-view-URsx4MBX.js → admin-view-DnD5gBsl.js} +1 -1
- package/dist/admin.js +1 -1
- package/dist/admin.umd.cjs +1 -1
- package/dist/{card-view-BPUveYDd.js → card-view-Cb3j5eXY.js} +1 -1
- package/dist/{edit-page-DVyHgdP0.js → edit-page-DGjs4jeh.js} +1 -1
- package/dist/{import-file-Bs86FUW3.js → import-file-DIAYCDNH.js} +10 -9
- package/dist/{profile-page-DHRxyJA_.js → profile-page-CaQqFoqe.js} +1 -1
- package/package.json +2 -2
- package/server/routes/report/controllers/list.js +2 -0
- package/server/routes/report/controllers/tableData.js +46 -17
- package/server/routes/report/controllers/widgetData.js +34 -31
- package/server/routes/report/utils/getFilterQuery.js +10 -9
@@ -1,4 +1,4 @@
|
|
1
|
-
import { _ as $, s as k, u as V, g as d } from "./import-file-
|
1
|
+
import { _ as $, s as k, u as V, g as d } from "./import-file-DIAYCDNH.js";
|
2
2
|
import { resolveComponent as j, openBlock as p, createElementBlock as g, createElementVNode as m, normalizeClass as b, createCommentVNode as x, normalizeStyle as y, createBlock as E } from "vue";
|
3
3
|
const O = {
|
4
4
|
data() {
|
@@ -3705,27 +3705,27 @@ const Z4 = [
|
|
3705
3705
|
{
|
3706
3706
|
name: "edit",
|
3707
3707
|
path: "/edit",
|
3708
|
-
component: () => import("./edit-page-
|
3708
|
+
component: () => import("./edit-page-DGjs4jeh.js")
|
3709
3709
|
},
|
3710
3710
|
{
|
3711
3711
|
name: "add",
|
3712
3712
|
path: "/add",
|
3713
|
-
component: () => import("./add-page-
|
3713
|
+
component: () => import("./add-page-DELwNBs9.js")
|
3714
3714
|
},
|
3715
3715
|
{
|
3716
3716
|
path: "/profile",
|
3717
3717
|
name: "profile",
|
3718
|
-
component: () => import("./profile-page-
|
3718
|
+
component: () => import("./profile-page-CaQqFoqe.js")
|
3719
3719
|
},
|
3720
3720
|
{
|
3721
3721
|
name: "card-view",
|
3722
3722
|
path: "/card",
|
3723
|
-
component: () => import("./card-view-
|
3723
|
+
component: () => import("./card-view-Cb3j5eXY.js"),
|
3724
3724
|
children: [
|
3725
3725
|
{
|
3726
3726
|
name: "table",
|
3727
3727
|
path: ":table",
|
3728
|
-
component: () => import("./card-view-
|
3728
|
+
component: () => import("./card-view-Cb3j5eXY.js"),
|
3729
3729
|
children: [
|
3730
3730
|
{
|
3731
3731
|
name: "card",
|
@@ -3786,14 +3786,14 @@ const eB = /* @__PURE__ */ ft(X4, [["render", Q4]]), tB = (t) => {
|
|
3786
3786
|
{
|
3787
3787
|
path: "/",
|
3788
3788
|
name: "home",
|
3789
|
-
component: () => import("./admin-view-
|
3789
|
+
component: () => import("./admin-view-DnD5gBsl.js"),
|
3790
3790
|
children: [
|
3791
3791
|
...t,
|
3792
3792
|
...e,
|
3793
3793
|
// { path: '/', redirect: '/home' },
|
3794
3794
|
{
|
3795
3795
|
path: "/:catchAll(.*)",
|
3796
|
-
component: () => import("./admin-interface-
|
3796
|
+
component: () => import("./admin-interface-ChLQ5JCd.js")
|
3797
3797
|
}
|
3798
3798
|
]
|
3799
3799
|
}
|
@@ -61180,7 +61180,8 @@ const Jce = /* @__PURE__ */ ft(Zce, [["render", Kce]]), Qce = async (t, e, n, i
|
|
61180
61180
|
__name: "admin-info-popover",
|
61181
61181
|
props: {
|
61182
61182
|
table: { type: String, default: () => "" },
|
61183
|
-
id: { type: String, default: () => "" }
|
61183
|
+
id: { type: String, default: () => "" },
|
61184
|
+
api: { type: String, default: () => "" }
|
61184
61185
|
},
|
61185
61186
|
setup(t) {
|
61186
61187
|
var _, k;
|
@@ -61193,7 +61194,7 @@ const Jce = /* @__PURE__ */ ft(Zce, [["render", Kce]]), Qce = async (t, e, n, i
|
|
61193
61194
|
const f = async () => {
|
61194
61195
|
try {
|
61195
61196
|
const { data: C } = await lt.get(
|
61196
|
-
|
61197
|
+
`${n.api}/${n.table}/${n.id}`
|
61197
61198
|
);
|
61198
61199
|
i.value = C;
|
61199
61200
|
} catch {
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { _ as n, g as m } from "./import-file-
|
1
|
+
import { _ as n, g as m } from "./import-file-DIAYCDNH.js";
|
2
2
|
import { u as p } from "./user-B_2kh6ic.js";
|
3
3
|
import { resolveComponent as d, openBlock as u, createElementBlock as f, createElementVNode as o, createBlock as h, createCommentVNode as b } from "vue";
|
4
4
|
const x = {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@opengis/admin",
|
3
|
-
"version": "0.3.
|
3
|
+
"version": "0.3.107",
|
4
4
|
"description": "This project Softpro Admin",
|
5
5
|
"main": "dist/admin.js",
|
6
6
|
"type": "module",
|
@@ -47,7 +47,7 @@
|
|
47
47
|
"@fullcalendar/timegrid": "^6.1.15",
|
48
48
|
"@fullcalendar/vue3": "^6.1.15",
|
49
49
|
"@opengis/fastify-auth": "1.0.86",
|
50
|
-
"@opengis/fastify-file": "1.0.
|
50
|
+
"@opengis/fastify-file": "1.0.83",
|
51
51
|
"@opengis/fastify-table": "^1.3.52",
|
52
52
|
"@opengis/v3-core": "^0.3.161",
|
53
53
|
"@opengis/v3-filter": "^0.1.3",
|
@@ -14,6 +14,8 @@ export default async function reportList({
|
|
14
14
|
name: el[0],
|
15
15
|
filters: item?.filters || [],
|
16
16
|
title: item?.title || el[0],
|
17
|
+
subtitle: item?.subtitle,
|
18
|
+
category: item?.category,
|
17
19
|
sql: user.user_type?.includes('admin') ? item?.sql : undefined,
|
18
20
|
};
|
19
21
|
}));
|
@@ -1,14 +1,26 @@
|
|
1
1
|
import path from 'node:path';
|
2
2
|
|
3
|
-
import { pgClients, getTemplate, metaFormat
|
3
|
+
import { pgClients, getTemplate, metaFormat } from '@opengis/fastify-table/utils.js';
|
4
4
|
|
5
5
|
import getFilterQuery from '../utils/getFilterQuery.js';
|
6
|
+
import { downloadFile, getExport, getMimeType } from '@opengis/fastify-file/utils.js';
|
6
7
|
|
7
8
|
const maxLimit = 100;
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
const matches = {
|
11
|
+
16: 'yes/no', // boolean
|
12
|
+
701: 'number', // double precision
|
13
|
+
1082: 'date', // date
|
14
|
+
1184: 'date', // timestamp w/ time zone
|
15
|
+
1114: 'date', // timestamp w/o time zone
|
16
|
+
1700: 'number', // numeric
|
17
|
+
};
|
18
|
+
|
19
|
+
export default async function tableData(req, reply) {
|
20
|
+
const {
|
21
|
+
pg = pgClients.client, params = {}, query = {}, user = {}, host, unittest,
|
22
|
+
} = req;
|
23
|
+
|
12
24
|
if (!params?.name) {
|
13
25
|
return { message: 'not enough params: name', status: 400 };
|
14
26
|
}
|
@@ -31,11 +43,12 @@ export default async function tableData({
|
|
31
43
|
});
|
32
44
|
}
|
33
45
|
|
34
|
-
const { title, subtitle, widgets = [], kpi, sql = `select * from ${loadTemplate.table} where ${loadTemplate.query || 'true'}`, meta, filters } = loadTemplate;
|
46
|
+
const { title, subtitle, category, widgets = [], kpi, sql = `select * from ${loadTemplate.table} where ${loadTemplate.query || 'true'}`, meta, filters } = loadTemplate;
|
35
47
|
const { date, columns: metaColumns } = meta || {};
|
36
48
|
|
37
49
|
const granularity = query.granularity && date && false ? `date_trunc('${query.granularity}',${date})::date::text` : null;
|
38
50
|
const groupby = [meta?.groupby, granularity].filter(el => el).join(',');
|
51
|
+
const [orderby, ord] = (query.order || loadTemplate.orderby || '').replace(/ /, '-').split('-');
|
39
52
|
|
40
53
|
const period = query.period && date ? `${date}=${query.period}` : null;
|
41
54
|
const filter = [query.filter, period].filter(el => el).join(';');
|
@@ -45,14 +58,38 @@ export default async function tableData({
|
|
45
58
|
|
46
59
|
const { fields = [] } = await pg.query(`select * from (${sql.replace(/{{uid}}/g, user?.uid)})q limit 0`);
|
47
60
|
|
48
|
-
const where =
|
61
|
+
const where = getFilterQuery({ pg, filter, fields, filterList: filters, searchColumns: meta.search, search: query.search });
|
49
62
|
|
50
|
-
const
|
63
|
+
const orderbyColumnExists = fields?.find?.(el => el.name === orderby);
|
64
|
+
const q = `select ${metaColumns || '*'} from (${sql.replace(/{{uid}}/g, user?.uid)})q where ${where || '1=1'} ${groupby ? `group by ${groupby}` : ''} ${orderby && orderbyColumnExists ? `order by ${orderby} ${['asc', 'desc'].includes(ord) ? ord : 'desc'} nulls last` : ''} limit ${limit} offset ${offset}`;
|
51
65
|
|
52
66
|
if (query.sql && user?.user_type?.includes('admin')) {
|
53
67
|
return q;
|
54
68
|
}
|
55
69
|
|
70
|
+
if (query.export) {
|
71
|
+
const resp = await getExport({
|
72
|
+
pg,
|
73
|
+
host,
|
74
|
+
unittest,
|
75
|
+
nocache: query.nocache,
|
76
|
+
tableSql: `select ${metaColumns || '*'} from (${sql.replace(/{{uid}}/g, user?.uid)})q where ${where || '1=1'}`,
|
77
|
+
sourceName: title || 'report',
|
78
|
+
columns: fields.map(({ name }) => ({ name, title: meta?.titles?.[name] || name })),
|
79
|
+
cls: meta?.cls,
|
80
|
+
format: ['xlsx', 'csv'].find(el => (req.query.format || 'xlsx') === el) || 'xlsx',
|
81
|
+
formatAnswer: 'filepath',
|
82
|
+
}, reply);
|
83
|
+
if (resp?.filePath) {
|
84
|
+
const buffer = await downloadFile(resp.filePath, { buffer: true });
|
85
|
+
const headers = {};
|
86
|
+
headers['Content-Type'] = `attachment; filename=${getMimeType(resp.filePath)}`;
|
87
|
+
headers['Content-Disposition'] = `attachment; filename=${path.basename(resp.filePath)}`;
|
88
|
+
return reply.status(200).headers(headers).send(buffer);
|
89
|
+
}
|
90
|
+
return resp;
|
91
|
+
}
|
92
|
+
|
56
93
|
if (kpi?.length) {
|
57
94
|
await Promise.all(kpi.map(async (el) => {
|
58
95
|
if (!el.sql && !el.table) {
|
@@ -73,8 +110,6 @@ export default async function tableData({
|
|
73
110
|
sql: user?.user_type === 'admin' ? el.sql : undefined
|
74
111
|
}));
|
75
112
|
|
76
|
-
const types = fields.reduce((acc, curr) => ({ ...acc, [curr.name]: pg.pgType?.[curr.dataTypeID] }), {});
|
77
|
-
|
78
113
|
const { rows = [] } = await pg.query(q).catch(err => {
|
79
114
|
return reply.status(500).send('query error: ' + err.toString());
|
80
115
|
});
|
@@ -84,14 +119,7 @@ export default async function tableData({
|
|
84
119
|
const columns = fields.map(el => ({
|
85
120
|
name: el.name,
|
86
121
|
title: meta?.titles?.[el.name] || el.name,
|
87
|
-
|
88
|
-
? 'Autocomplete'
|
89
|
-
: (
|
90
|
-
['date', 'timestamp with time zone', 'timestamp without time zone'].includes(types[el.name])
|
91
|
-
? 'Date'
|
92
|
-
: null
|
93
|
-
) || 'Text',
|
94
|
-
format: pg.pgType?.[el.dataTypeID],
|
122
|
+
format: meta?.cls?.[el.name] ? 'select' : (matches[el.dataTypeID] || 'text'),
|
95
123
|
data: meta?.cls?.[el.name],
|
96
124
|
}));
|
97
125
|
|
@@ -101,6 +129,7 @@ export default async function tableData({
|
|
101
129
|
data: rows,
|
102
130
|
title,
|
103
131
|
subtitle,
|
132
|
+
category,
|
104
133
|
widgets,
|
105
134
|
columns,
|
106
135
|
};
|
@@ -4,6 +4,37 @@ import { pgClients, getTemplate, metaFormat } from '@opengis/fastify-table/utils
|
|
4
4
|
|
5
5
|
const maxLimit = 100;
|
6
6
|
|
7
|
+
const matches = {
|
8
|
+
16: 'yes/no', // boolean
|
9
|
+
701: 'number', // double precision
|
10
|
+
1082: 'date', // date
|
11
|
+
1184: 'date', // timestamp w/ time zone
|
12
|
+
1114: 'date', // timestamp w/o time zone
|
13
|
+
1700: 'number', // numeric
|
14
|
+
};
|
15
|
+
|
16
|
+
function normalizeData(widget, limit = maxLimit, offset = 0) {
|
17
|
+
const groupby = typeof widget.groupby === 'string'
|
18
|
+
? { name: widget.groupby }
|
19
|
+
: (widget.groupby?.[0] || widget.groupby);
|
20
|
+
|
21
|
+
const agg = groupby.name
|
22
|
+
? `${widget.granularity ? `date_trunc('${widget.granularity}', ${groupby.name})` : `${groupby.name}`}`
|
23
|
+
: 'count(*)';
|
24
|
+
|
25
|
+
const xCol = widget.granularity
|
26
|
+
? `date_trunc('${widget.granularity}', ${groupby.name})`
|
27
|
+
: groupby.name;
|
28
|
+
|
29
|
+
const sql = `select * from ${widget.table} where ${widget.query || 'true'} limit ${limit} offset ${offset}`;
|
30
|
+
|
31
|
+
const q = `select ${agg} as ${groupby.name}, ${widget.agg} as metric from (${sql}) t
|
32
|
+
${groupby.name ? `group by ${xCol}` : ''}
|
33
|
+
${widget.orderby || xCol ? `order by ${widget.orderby || xCol}` : ''}`;
|
34
|
+
|
35
|
+
return { groupby, agg, xCol, q };
|
36
|
+
}
|
37
|
+
|
7
38
|
export default async function widgetData({
|
8
39
|
pg = pgClients.client, params = {}, query = {}, user = {},
|
9
40
|
}, reply) {
|
@@ -43,34 +74,15 @@ export default async function widgetData({
|
|
43
74
|
|
44
75
|
const { cls = {}, titles = {} } = widget.meta || {};
|
45
76
|
|
77
|
+
const limit = Math.min(query.limit || maxLimit, maxLimit);
|
46
78
|
const offset = query.page && query.page > 0 ? (query.page - 1) * limit : 0;
|
47
|
-
const sql = widget.sql || `select * from ${widget.table} where ${widget.query || 'true'} limit ${maxLimit} offset ${offset}`;
|
48
79
|
|
49
|
-
const groupby =
|
50
|
-
? { name: widget.groupby }
|
51
|
-
: (widget.groupby?.[0] || widget.groupby);
|
80
|
+
const { groupby, q } = normalizeData(widget, limit, offset);
|
52
81
|
|
53
82
|
if (groupby.cls) {
|
54
83
|
Object.assign(cls, { [groupby.name]: groupby.cls });
|
55
84
|
}
|
56
85
|
|
57
|
-
const xCol = widget.granularity
|
58
|
-
? `date_trunc('${widget.granularity}', ${groupby.name})`
|
59
|
-
: groupby.name;
|
60
|
-
|
61
|
-
const q = widget.agg
|
62
|
-
? `select ${widget.agg} as metric ${groupby.name
|
63
|
-
? `${widget.granularity
|
64
|
-
? `,date_trunc('${widget.granularity}', ${groupby.name})`
|
65
|
-
: `,${groupby.name}`}`
|
66
|
-
: ''
|
67
|
-
} as ${groupby.name} from (${sql}) t ${groupby.name
|
68
|
-
? `group by ${xCol}`
|
69
|
-
: ''
|
70
|
-
}
|
71
|
-
${widget.orderby || xCol ? `order by ${widget.orderby || xCol}` : ''}`
|
72
|
-
: sql;
|
73
|
-
|
74
86
|
if (query.sql) return q;
|
75
87
|
|
76
88
|
const { rows = [], fields = [] } = await pg.query(q).catch(err => {
|
@@ -78,19 +90,10 @@ export default async function widgetData({
|
|
78
90
|
}) || {};
|
79
91
|
await metaFormat({ rows, cls, sufix: false }, pg);
|
80
92
|
|
81
|
-
const types = fields.reduce((acc, curr) => ({ ...acc, [curr.name]: pg.pgType?.[curr.dataTypeID] }), {});
|
82
|
-
|
83
93
|
const columns = fields.map(el => ({
|
84
94
|
name: el.name,
|
85
95
|
title: titles?.[el.name] || el.name,
|
86
|
-
|
87
|
-
? 'Autocomplete'
|
88
|
-
: (
|
89
|
-
['date', 'timestamp with time zone', 'timestamp without time zone'].includes(types[el.name])
|
90
|
-
? 'Date'
|
91
|
-
: null
|
92
|
-
) || 'Text',
|
93
|
-
format: pg.pgType?.[el.dataTypeID],
|
96
|
+
format: cls?.[el.name] ? 'select' : (matches[el.dataTypeID] || 'text'),
|
94
97
|
data: cls?.[el.name],
|
95
98
|
}));
|
96
99
|
|
@@ -1,21 +1,21 @@
|
|
1
1
|
/* eslint-disable no-continue */
|
2
2
|
|
3
|
-
|
4
|
-
* @param {Number} opt.json - (1|0) 1 - Результат - Object, 0 - String
|
5
|
-
* @param {String} opt.query - запит до таблиці
|
6
|
-
* @param {String} opt.hash - інформація з хешу по запиту
|
7
|
-
*/
|
3
|
+
import { pgClients } from '@opengis/fastify-table/utils.js';
|
8
4
|
|
9
5
|
import formatValue from './formatValue.js';
|
10
6
|
|
11
|
-
function getFilterQuery({ pg, filter: filterStr, fields, filterList }) {
|
12
|
-
if (!filterStr) return null;
|
7
|
+
export default function getFilterQuery({ pg = pgClients.client, filter: filterStr, fields, filterList, searchColumns, search }) {
|
8
|
+
if (!filterStr && !search) return null;
|
13
9
|
|
14
10
|
const mainOperators = ['=', '~', '>', '<'];
|
15
11
|
|
16
12
|
const filterQueryArray = decodeURIComponent(filterStr?.replace(/%/g, '%25').replace(/%/g, '\\%')?.replace(/(^,)|(,$)/g, '')).replace(/'/g, '').split(/[;|]/);
|
17
13
|
|
18
14
|
const resultList = [];
|
15
|
+
const searchwith = searchColumns || fields?.filter?.((el) => pg.pgType?.[el.dataTypeID] === 'text')?.map?.((el) => el.name)?.join?.(',');
|
16
|
+
|
17
|
+
const sval = `ilike '%${decodeURIComponent(search?.replace(/%/g, '%25')).replace(/'/g, "''").replace(/%/g, '\\%')}%'`;
|
18
|
+
const searchQuery = search && searchwith ? ` (${searchwith.split(',')?.map((name) => `${name} ${sval}`).join(' or ')} )` : '';
|
19
19
|
|
20
20
|
for (let i = 0; i < filterQueryArray.length; i += 1) {
|
21
21
|
const item = filterQueryArray[i];
|
@@ -61,7 +61,8 @@ function getFilterQuery({ pg, filter: filterStr, fields, filterList }) {
|
|
61
61
|
});
|
62
62
|
}
|
63
63
|
|
64
|
-
|
64
|
+
const where = [searchQuery].concat(resultList?.map?.(el => el.query) || []).filter(el => el).join(' and ');
|
65
|
+
|
66
|
+
return where;
|
65
67
|
}
|
66
68
|
|
67
|
-
export default getFilterQuery;
|