@jtandrelevicius/utils-js-library 1.0.6 → 1.0.7
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/index.js +17 -525
- package/lib/export-core.js +64 -0
- package/lib/format-core.js +73 -0
- package/lib/jsk-core.js +251 -0
- package/lib/order-core.js +21 -0
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1,542 +1,34 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* @param {Function} funcaoExecutor Função que aceita (query, params, onSuccess, onError).
|
|
8
|
-
*/
|
|
9
|
-
static definirExecutor(funcaoExecutor) {
|
|
10
|
-
this.executor = funcaoExecutor;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Realiza requisições do tipo POST (Base para salvar/excluir).
|
|
15
|
-
* @param {string} url URL da requisição.
|
|
16
|
-
* @param {Object} corpo Corpo da requisição.
|
|
17
|
-
* @param {Object} opcoes Opções adicionais (headers, raw).
|
|
18
|
-
* @returns {Promise<Object>} Resposta da requisição.
|
|
19
|
-
*/
|
|
20
|
-
static async post(url, corpo, { headers, raw } = { headers: {}, raw: false }) {
|
|
21
|
-
let isJSON = true;
|
|
22
|
-
|
|
23
|
-
if (headers) {
|
|
24
|
-
const cabecalhoTipoOriginal = headers['Content-Type'] ? String(headers['Content-Type']) : 'application/json; charset=UTF-8';
|
|
25
|
-
isJSON = headers['Content-Type'] ? RegExp(/json/i).exec(headers['Content-Type']) : isJSON;
|
|
26
|
-
|
|
27
|
-
if (headers['Content-Type']) delete headers['Content-Type'];
|
|
28
|
-
headers['Content-Type'] = cabecalhoTipoOriginal;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
try {
|
|
32
|
-
let corpoRequisicaoFormatado = corpo;
|
|
33
|
-
|
|
34
|
-
if (corpo && typeof corpo === 'object') {
|
|
35
|
-
corpoRequisicaoFormatado = JSON.stringify(corpo);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (typeof window === 'undefined' || !window.fetch) {
|
|
39
|
-
throw new Error("O método 'post' requer um ambiente de navegador com 'fetch' disponível.");
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const resposta = await window.fetch.bind(window)(url, {
|
|
43
|
-
headers,
|
|
44
|
-
method: 'POST',
|
|
45
|
-
redirect: 'follow',
|
|
46
|
-
credentials: 'include',
|
|
47
|
-
body: corpoRequisicaoFormatado
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
if (raw) {
|
|
51
|
-
return resposta;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return isJSON ? resposta.json() : resposta.text();
|
|
55
|
-
|
|
56
|
-
} catch (erro) {
|
|
57
|
-
console.error("[ServicoDados] Erro no POST:", erro);
|
|
58
|
-
throw erro;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Normaliza a resposta da API (Método auxiliar).
|
|
64
|
-
* @private
|
|
65
|
-
*/
|
|
66
|
-
static normalizarResposta(valorBruto) {
|
|
67
|
-
try {
|
|
68
|
-
const valorParseado = typeof valorBruto === 'string' ? JSON.parse(valorBruto) : valorBruto;
|
|
69
|
-
|
|
70
|
-
if (!valorParseado) return [];
|
|
71
|
-
if (Array.isArray(valorParseado)) return valorParseado;
|
|
72
|
-
|
|
73
|
-
let dadosFinais = null;
|
|
74
|
-
|
|
75
|
-
if (typeof valorParseado === 'object') {
|
|
76
|
-
if (typeof valorParseado.b === 'string') {
|
|
77
|
-
dadosFinais = JSON.parse(valorParseado.b);
|
|
78
|
-
} else if (valorParseado.c?.b && typeof valorParseado.c.b === 'string') {
|
|
79
|
-
dadosFinais = JSON.parse(valorParseado.c.b);
|
|
80
|
-
} else if (valorParseado.data?.responseBody || valorParseado.responseBody) {
|
|
81
|
-
const corpo = valorParseado.data?.responseBody || valorParseado.responseBody;
|
|
82
|
-
dadosFinais = typeof corpo === 'string' ? JSON.parse(corpo) : corpo;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (Array.isArray(dadosFinais)) return dadosFinais;
|
|
87
|
-
throw new Error("Formato de resposta desconhecido ou inválido.");
|
|
88
|
-
} catch (erro) {
|
|
89
|
-
throw new Error(`Falha ao normalizar resposta da query: ${erro.message}`);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Executa uma consulta de dados (Via executor configurado ou executeQuery global).
|
|
95
|
-
* @param {string} query A string da consulta.
|
|
96
|
-
* @param {Object} [params=null] Parâmetros opcionais.
|
|
97
|
-
* @returns {Promise<Array<Object>>} Promise resolvendo com os dados.
|
|
98
|
-
*/
|
|
99
|
-
static async consultar(query, params = null) {
|
|
100
|
-
const executor = this.executor || (typeof window !== 'undefined' ? window.executeQuery : null);
|
|
101
|
-
|
|
102
|
-
if (typeof executor !== 'function') {
|
|
103
|
-
return Promise.reject(new Error("Executor de query não configurado e 'executeQuery' global não encontrado."));
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return new Promise((resolve, reject) => {
|
|
107
|
-
executor(query, params,
|
|
108
|
-
(valorBruto) => {
|
|
109
|
-
try {
|
|
110
|
-
const dados = ServicoDados.normalizarResposta(valorBruto);
|
|
111
|
-
resolve(dados || []);
|
|
112
|
-
} catch (err) {
|
|
113
|
-
reject(err);
|
|
114
|
-
}
|
|
115
|
-
},
|
|
116
|
-
(err) => reject(new Error(`Erro na execução da query: ${err}`))
|
|
117
|
-
);
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Executa uma consulta paginada.
|
|
123
|
-
*/
|
|
124
|
-
static async consultarPaginado(query, params = null, limite, offset) {
|
|
125
|
-
const limiteSeguro = Number(limite);
|
|
126
|
-
const offsetSeguro = Number(offset);
|
|
127
|
-
|
|
128
|
-
if (isNaN(limiteSeguro) || isNaN(offsetSeguro) || limiteSeguro < 0 || offsetSeguro < 0) {
|
|
129
|
-
throw new Error("Parâmetros 'limite' e 'offset' devem ser números positivos válidos.");
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const queryPaginada = `${query} LIMIT ${limiteSeguro} OFFSET ${offsetSeguro}`;
|
|
133
|
-
const dados = await ServicoDados.consultar(queryPaginada, params);
|
|
134
|
-
const paginaAtual = Math.floor(offsetSeguro / limiteSeguro) + 1;
|
|
135
|
-
|
|
136
|
-
return {
|
|
137
|
-
dados,
|
|
138
|
-
meta: { paginaAtual, itensPorPagina: limiteSeguro, totalItens: null, totalPaginas: null }
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Salva (Insert) ou Atualiza (Update) um registro usando DatasetSP.
|
|
144
|
-
* * Lógica Automática:
|
|
145
|
-
* 1. Se 'chavesPrimarias' for informado -> Realiza UPDATE no registro específico.
|
|
146
|
-
* 2. Se 'chavesPrimarias' for NULO/UNDEFINED -> Realiza INSERT de um novo registro.
|
|
147
|
-
* * @param {Object} dados Objeto com os dados a serem gravados { CAMPO: valor }.
|
|
148
|
-
* @param {string} entidade Nome da entidade/tabela (ex: 'Parceiro', 'TGFCAB').
|
|
149
|
-
* @param {Object} [chavesPrimarias=null] Chaves primárias { PK: valor } para edição.
|
|
150
|
-
* @returns {Promise<Object>} Resposta da requisição.
|
|
151
|
-
*/
|
|
152
|
-
static async salvar(dados, entidade, chavesPrimarias = null) {
|
|
153
|
-
const url = `${window.location.origin}/mge/service.sbr?serviceName=DatasetSP.save&outputType=json`;
|
|
154
|
-
|
|
155
|
-
const chavesDados = Object.keys(dados);
|
|
156
|
-
const fields = chavesDados.map(campo => campo.toUpperCase());
|
|
157
|
-
|
|
158
|
-
const values = {};
|
|
159
|
-
chavesDados.forEach((chave, indice) => {
|
|
160
|
-
values[indice.toString()] = String(dados[chave]);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
const record = { values: values };
|
|
164
|
-
|
|
165
|
-
if (chavesPrimarias) {
|
|
166
|
-
const pk = {};
|
|
167
|
-
Object.keys(chavesPrimarias).forEach(chave => {
|
|
168
|
-
pk[chave.toUpperCase()] = String(chavesPrimarias[chave]);
|
|
169
|
-
});
|
|
170
|
-
record.pk = pk;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const dadosEnvio = {
|
|
174
|
-
serviceName: 'DatasetSP.save',
|
|
175
|
-
requestBody: {
|
|
176
|
-
entityName: entidade,
|
|
177
|
-
fields: fields,
|
|
178
|
-
records: [record]
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
return await ServicoDados.post(url, dadosEnvio);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Exclui registros da base de dados.
|
|
187
|
-
* @param {string} entidade Nome da Entidade.
|
|
188
|
-
* @param {Object|Array} chavesPrimarias Objeto PK { COD: 1 } ou Array de PKs.
|
|
189
|
-
* @returns {Promise<Object>} Resposta da exclusão.
|
|
190
|
-
*/
|
|
191
|
-
static async excluir(entidade, chavesPrimarias) {
|
|
192
|
-
const url = `${window.location.origin}/mge/service.sbr?serviceName=DatasetSP.removeRecord&outputType=json`;
|
|
193
|
-
|
|
194
|
-
const dadosEnvio = {
|
|
195
|
-
serviceName: 'DatasetSP.removeRecord',
|
|
196
|
-
requestBody: {
|
|
197
|
-
entityName: entidade,
|
|
198
|
-
pks: Array.isArray(chavesPrimarias) ? chavesPrimarias : [chavesPrimarias]
|
|
199
|
-
}
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
return ServicoDados.post(url, dadosEnvio);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* UtilitariosFormatacao
|
|
208
|
-
*/
|
|
209
|
-
class UtilitariosFormatacao {
|
|
210
|
-
static moeda(valor) {
|
|
211
|
-
const valorNumerico = parseFloat(valor);
|
|
212
|
-
if (isNaN(valorNumerico)) return "R$ 0,00";
|
|
213
|
-
return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(valorNumerico);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
static numerico(valor) {
|
|
217
|
-
const valorNumerico = parseFloat(valor);
|
|
218
|
-
if (isNaN(valorNumerico)) return "0";
|
|
219
|
-
return new Intl.NumberFormat('pt-BR', { maximumFractionDigits: 0 }).format(valorNumerico);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
static decimal(valor) {
|
|
223
|
-
const valorNumerico = parseFloat(valor);
|
|
224
|
-
if (isNaN(valorNumerico)) return "0,00";
|
|
225
|
-
return new Intl.NumberFormat('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(valorNumerico);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
static data() {
|
|
229
|
-
return new Intl.DateTimeFormat('pt-BR').format(new Date());
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
static formatarDataParaDMY(stringDataIso) {
|
|
233
|
-
if (!stringDataIso) return '';
|
|
234
|
-
const partes = stringDataIso.split('-');
|
|
235
|
-
if (partes.length !== 3) return stringDataIso;
|
|
236
|
-
return `${partes[2]}/${partes[1]}/${partes[0]}`;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
static normalizarStringData(entradaData) {
|
|
240
|
-
if (!entradaData) return '01/01/2025';
|
|
241
|
-
let str = String(entradaData).trim();
|
|
242
|
-
|
|
243
|
-
if (str.includes('/')) {
|
|
244
|
-
const partes = str.split('/');
|
|
245
|
-
if (partes.length >= 3) {
|
|
246
|
-
const dia = String(parseInt(partes[0], 10)).padStart(2, '0');
|
|
247
|
-
const mes = String(parseInt(partes[1], 10)).padStart(2, '0');
|
|
248
|
-
const ano = partes[2].substring(0, 4);
|
|
249
|
-
return `${dia}/${mes}/${ano}`;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
if (str.includes('-')) {
|
|
254
|
-
const partes = str.split('-');
|
|
255
|
-
if (partes.length === 3) {
|
|
256
|
-
return `${partes[2].substring(0, 2)}/${partes[1]}/${partes[0]}`;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return str;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
static obterDataAtualISO() {
|
|
264
|
-
return new Date().toISOString().split('T')[0];
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
static dataHora() {
|
|
268
|
-
const agora = new Date();
|
|
269
|
-
const parteData = new Intl.DateTimeFormat('pt-BR').format(agora);
|
|
270
|
-
const parteHora = agora.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' });
|
|
271
|
-
return `${parteData} ${parteHora}`;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* UtilitariosOrdenacao
|
|
277
|
-
*/
|
|
278
|
-
class UtilitariosOrdenacao {
|
|
279
|
-
static ordenar(dados, chave, direcao = 'asc') {
|
|
280
|
-
if (!Array.isArray(dados) || !chave) return dados;
|
|
281
|
-
const multiplicador = direcao === 'asc' ? 1 : -1;
|
|
282
|
-
|
|
283
|
-
return [...dados].sort((a, b) => {
|
|
284
|
-
const valA = a[chave];
|
|
285
|
-
const valB = b[chave];
|
|
286
|
-
if (valA == null) return 1;
|
|
287
|
-
if (valB == null) return -1;
|
|
288
|
-
if (typeof valA === 'string' && typeof valB === 'string') {
|
|
289
|
-
return valA.localeCompare(valB) * multiplicador;
|
|
290
|
-
}
|
|
291
|
-
if (valA < valB) return -1 * multiplicador;
|
|
292
|
-
if (valA > valB) return 1 * multiplicador;
|
|
293
|
-
return 0;
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* ServicoExportacao
|
|
300
|
-
*/
|
|
301
|
-
class ServicoExportacao {
|
|
302
|
-
static CDN_URL = "https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js";
|
|
303
|
-
|
|
304
|
-
static async carregarDependencia() {
|
|
305
|
-
if (typeof window !== 'undefined' && window.XLSX) return;
|
|
306
|
-
return new Promise((resolve, reject) => {
|
|
307
|
-
const script = document.createElement('script');
|
|
308
|
-
script.src = this.CDN_URL;
|
|
309
|
-
script.async = true;
|
|
310
|
-
script.onload = () => resolve();
|
|
311
|
-
script.onerror = () => reject(new Error('Falha ao baixar dependência XLSX.'));
|
|
312
|
-
document.head.appendChild(script);
|
|
313
|
-
});
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
static async paraExcel(dados, colunas, nomeArquivo, nomePlanilha = 'Dados') {
|
|
317
|
-
await this.carregarDependencia();
|
|
318
|
-
const dadosFormatados = dados.map(item => {
|
|
319
|
-
const linha = {};
|
|
320
|
-
colunas.forEach(col => { linha[col.display] = item[col.key]; });
|
|
321
|
-
return linha;
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
const planilha = XLSX.utils.json_to_sheet(dadosFormatados);
|
|
325
|
-
const pastaTrabalho = XLSX.utils.book_new();
|
|
326
|
-
XLSX.utils.book_append_sheet(pastaTrabalho, planilha, nomePlanilha);
|
|
327
|
-
XLSX.writeFile(pastaTrabalho, `${nomeArquivo}.xlsx`);
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
static paraCSV(dados, colunas, nomeArquivo) {
|
|
331
|
-
const linhaCabecalho = colunas.map(c => `"${c.display}"`).join(';');
|
|
332
|
-
const linhasCorpo = dados.map(item => {
|
|
333
|
-
return colunas.map(col => {
|
|
334
|
-
const val = item[col.key] ?? '';
|
|
335
|
-
const valString = String(val).replace(/"/g, '""').replace(/\r?\n|\r/g, ' ');
|
|
336
|
-
return `"${valString}"`;
|
|
337
|
-
}).join(';');
|
|
338
|
-
});
|
|
339
|
-
const conteudoCsv = [linhaCabecalho, ...linhasCorpo].join('\r\n');
|
|
340
|
-
const blob = new Blob([conteudoCsv], { type: 'text/csv;charset=utf-8;' });
|
|
341
|
-
const link = document.createElement('a');
|
|
342
|
-
if (link.download !== undefined) {
|
|
343
|
-
const url = URL.createObjectURL(blob);
|
|
344
|
-
link.setAttribute('href', url);
|
|
345
|
-
link.setAttribute('download', `${nomeArquivo}.csv`);
|
|
346
|
-
link.style.visibility = 'hidden';
|
|
347
|
-
document.body.appendChild(link);
|
|
348
|
-
link.click();
|
|
349
|
-
document.body.removeChild(link);
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
static async exportar(dados, colunas, nomeArquivo = 'exportacao', formato = 'xlsx') {
|
|
354
|
-
if (!dados?.length) throw new Error("Sem dados para exportar.");
|
|
355
|
-
if (!colunas?.length) throw new Error("Colunas não definidas.");
|
|
356
|
-
|
|
357
|
-
const fmt = formato.toLowerCase();
|
|
358
|
-
if (fmt === 'xlsx') await this.paraExcel(dados, colunas, nomeArquivo);
|
|
359
|
-
else if (fmt === 'csv') this.paraCSV(dados, colunas, nomeArquivo);
|
|
360
|
-
else throw new Error(`Formato '${formato}' não suportado.`);
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* ServicoPagina
|
|
366
|
-
* Manipuladores de Página e Navegação Sankhya-W
|
|
367
|
-
*/
|
|
368
|
-
class ServicoPagina {
|
|
369
|
-
/**
|
|
370
|
-
* Retorna a URL atual da pagina com o caminho opcional.
|
|
371
|
-
* @param { String } path Caminho a ser adicionado a URL atual
|
|
372
|
-
* @returns { String } A URL com o protocolo HTTPS ou HTTP
|
|
373
|
-
*/
|
|
374
|
-
static getUrl(path) {
|
|
375
|
-
return `${window.location.origin}${path ? '/' + path.replace('/', '') : ''}`;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
* Remove o frame da página de BI
|
|
380
|
-
* * @param { { instancia: String, paginaInicial: String, opcoes: any } } configuracoes Configuracoes gerais da pagina
|
|
381
|
-
* * **instancia**: Nome exato do componente de BI
|
|
382
|
-
* * **paginaInicial**: URL (a partir da pasta raiz) e nome do arquivo da pagina inicial
|
|
383
|
-
* * **opcoes**: [opcional] Campos com valores a serem recebidos pela pagina
|
|
384
|
-
* * _Padrao_: `{ instancia: '', paginaInicial: 'app.jsp' }`
|
|
385
|
-
* * @example JPSK.removerFrame ({ instancia: 'TELA_HTML5', paginaInicial: 'index.jsp'});
|
|
386
|
-
*/
|
|
387
|
-
static removerFrame({ instancia, paginaInicial, ...opcoes } = { instancia: '', paginaInicial: 'app.jsp' }) {
|
|
388
|
-
|
|
389
|
-
new Promise(resolve => {
|
|
390
|
-
|
|
391
|
-
if (window.parent.document.getElementsByTagName('body').length) {
|
|
392
|
-
|
|
393
|
-
if (window.parent.document.querySelector('div.gwt-PopupPanel.alert-box.box-shadow'))
|
|
394
|
-
window.parent.document.querySelector('div.gwt-PopupPanel.alert-box.box-shadow')
|
|
395
|
-
.style.display = 'none';
|
|
396
|
-
|
|
397
|
-
window.parent.document.getElementsByTagName('body')[0].style.overflow = 'hidden';
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
if (window.parent.parent.document.getElementsByTagName('body').length) {
|
|
401
|
-
|
|
402
|
-
if (window.parent.parent.document.querySelector('div.gwt-PopupPanel.alert-box.box-shadow'))
|
|
403
|
-
window.parent.parent.document.querySelector('div.gwt-PopupPanel.alert-box.box-shadow')
|
|
404
|
-
.style.display = 'none';
|
|
405
|
-
|
|
406
|
-
window.parent.parent.document.getElementsByTagName('body')[0].style.overflow = 'hidden';
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
if (
|
|
410
|
-
window.parent.document
|
|
411
|
-
.querySelector('div.GI-BUHVBPVC > div > div > div > div > div > table > tbody > tr > td > div')
|
|
412
|
-
) {
|
|
413
|
-
instancia = window.parent.document
|
|
414
|
-
.querySelector('div.GI-BUHVBPVC > div > div > div > div > div > table > tbody > tr > td > div')
|
|
415
|
-
.textContent;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
if (instancia && instancia.length > 0) {
|
|
419
|
-
ServicoDados.consultar(`SELECT NUGDG FROM TSIGDG WHERE TITULO = '${instancia}'`).
|
|
420
|
-
then(e => resolve({ gadGetID: 'html5_z6dld', nuGdt: e[0].NUGDG, ...opcoes }));
|
|
421
|
-
}
|
|
422
|
-
else {
|
|
423
|
-
resolve({ gadGetID: 'html5_z6dld', nuGdt: 0, ...opcoes });
|
|
424
|
-
}
|
|
425
|
-
}).
|
|
426
|
-
then(o =>
|
|
427
|
-
setTimeout(() => {
|
|
428
|
-
if (typeof window.parent.document.getElementsByClassName('DashWindow')[0] != 'undefined') {
|
|
429
|
-
|
|
430
|
-
const opcoesUrl =
|
|
431
|
-
Object.
|
|
432
|
-
keys(o).
|
|
433
|
-
filter(item => !['params', 'UID', 'instance', 'nuGdg', 'gadGetID'].includes(item)).
|
|
434
|
-
map(item => `&${item}=${o[item]}`).
|
|
435
|
-
join('');
|
|
436
|
-
|
|
437
|
-
const url = `/mge/html5component.mge?entryPoint=${paginaInicial}&nuGdg=${o.nuGdt}${opcoesUrl}`
|
|
438
|
-
|
|
439
|
-
setTimeout(() =>
|
|
440
|
-
window.parent.document.getElementsByClassName('dyna-gadget')[0].innerHTML =
|
|
441
|
-
`<iframe src="${url}" class="gwt-Frame" style="width: 100%; height: 100%;"></iframe>`
|
|
442
|
-
, 500);
|
|
443
|
-
|
|
444
|
-
setTimeout(() => document.getElementsByClassName('popupContent').length
|
|
445
|
-
? document.getElementsByClassName('popupContent')[0].parentElement.remove()
|
|
446
|
-
: (() => { /**/ })()
|
|
447
|
-
, 20000);
|
|
448
|
-
|
|
449
|
-
setTimeout(() => (document.getElementById('stndz-style').parentElement.parentElement)
|
|
450
|
-
.getElementsByTagName('body')[0].style.overflow = 'hidden'
|
|
451
|
-
, 20000);
|
|
452
|
-
}
|
|
453
|
-
})
|
|
454
|
-
);
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
/**
|
|
458
|
-
* Abre uma nova guia com a pagina atual
|
|
459
|
-
*
|
|
460
|
-
* @param { boolean } forcado - [Opcional] Indica se a abertura da nova guia deve ser forcada
|
|
461
|
-
* * @example JPSK.novaGuia ();
|
|
462
|
-
*/
|
|
463
|
-
static novaGuia(forcado = false) {
|
|
464
|
-
|
|
465
|
-
if ((window.parent.parent.document.querySelector('.Taskbar-container') && !forcado) || forcado) {
|
|
466
|
-
Object.assign(document.createElement('a'), { target: '_blank', href: window.location.href }).click();
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
/**
|
|
472
|
-
* Abre uma pagina dentro do Sankhya-W.
|
|
473
|
-
* * - Se o resourceID nao existir, o sistema informara que a tela nao existe.
|
|
474
|
-
* - Se as chaves primarias nao forem informadas, a tela sera aberta na pagina inicial.
|
|
475
|
-
* - Se existirem chaves primarias, mas nao forem encontradas, a tela ssera aberta como visualizacao de um registro vazio (para inclusao)
|
|
476
|
-
* - Se existirem chaves primarias e forem encontradas, a tela sera aberta no registro encontrado.
|
|
477
|
-
* * @param { String } resourceID ID do recurso a ser aberto
|
|
478
|
-
* @param { Object } chavesPrimarias Chaves de identificacao do registro
|
|
479
|
-
* * @example JPSK.abrirPagina ('br.com.sankhya.core.cad.marcas', { CODIGO: 999 });
|
|
480
|
-
*/
|
|
481
|
-
static abrirPagina(resourceID, chavesPrimarias) {
|
|
482
|
-
|
|
483
|
-
let url = ServicoPagina.getUrl(`/mge/system.jsp#app/%resID`);
|
|
484
|
-
url = url.replace('%resID', btoa(resourceID));
|
|
485
|
-
|
|
486
|
-
if (chavesPrimarias) {
|
|
487
|
-
|
|
488
|
-
let body = {};
|
|
489
|
-
|
|
490
|
-
Object.keys(chavesPrimarias).forEach(function (chave) {
|
|
491
|
-
body[chave] = isNaN(chavesPrimarias[chave])
|
|
492
|
-
? String(chavesPrimarias[chave])
|
|
493
|
-
: Number(chavesPrimarias[chave])
|
|
494
|
-
});
|
|
495
|
-
|
|
496
|
-
url = url.concat(`/${btoa(JSON.stringify(body))}`);
|
|
497
|
-
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
Object.assign(document.createElement('a'), {
|
|
501
|
-
target: '_top',
|
|
502
|
-
href: url
|
|
503
|
-
}).click();
|
|
504
|
-
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
/**
|
|
508
|
-
* Fecha a pagina atual.
|
|
509
|
-
* * Ele verifica se a pagina atual esta dentro do Sankhya-W para fechar, senao ele fecha a aba do navegador.
|
|
510
|
-
*/
|
|
511
|
-
static fecharPagina() {
|
|
512
|
-
if (window.parent.parent.document.querySelector('.Taskbar-container')) {
|
|
513
|
-
window.parent.parent.document.querySelector(
|
|
514
|
-
'li.ListItem.AppItem.AppItem-selected div.Taskbar-icon.icon-close').click();
|
|
515
|
-
} else {
|
|
516
|
-
window.close();
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
}
|
|
3
|
+
import { ServicoDados } from './lib/jsk-core.js';
|
|
4
|
+
import { UtilitariosFormatacao } from './lib/format-core.js';
|
|
5
|
+
import { UtilitariosOrdenacao } from './lib/order-core.js';
|
|
6
|
+
import { ServicoExportacao } from './lib/export-core.js';
|
|
520
7
|
|
|
521
8
|
const lib = {
|
|
522
9
|
ServicoDados,
|
|
523
10
|
UtilitariosFormatacao,
|
|
524
11
|
UtilitariosOrdenacao,
|
|
525
12
|
ServicoExportacao,
|
|
526
|
-
ServicoPagina,
|
|
527
13
|
|
|
528
|
-
// Aliases
|
|
529
|
-
JSK: ServicoDados,
|
|
14
|
+
// Aliases
|
|
15
|
+
JSK: ServicoDados,
|
|
530
16
|
JFSK: UtilitariosFormatacao,
|
|
531
17
|
JOSK: UtilitariosOrdenacao,
|
|
532
|
-
JEXSK: ServicoExportacao
|
|
533
|
-
JPSK: ServicoPagina
|
|
18
|
+
JEXSK: ServicoExportacao
|
|
534
19
|
};
|
|
535
20
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
21
|
+
export {
|
|
22
|
+
ServicoDados,
|
|
23
|
+
UtilitariosFormatacao,
|
|
24
|
+
UtilitariosOrdenacao,
|
|
25
|
+
ServicoExportacao,
|
|
26
|
+
lib as default
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
if (typeof window !== 'undefined') {
|
|
539
30
|
Object.assign(window, lib);
|
|
31
|
+
|
|
540
32
|
if (typeof window.executeQuery === 'function') {
|
|
541
33
|
ServicoDados.definirExecutor(window.executeQuery);
|
|
542
34
|
console.log("[JSK] Executor 'executeQuery' detectado e configurado automaticamente.");
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
export class ServicoExportacao {
|
|
4
|
+
static CDN_URL = "https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js";
|
|
5
|
+
|
|
6
|
+
static async carregarDependencia() {
|
|
7
|
+
if (typeof window !== 'undefined' && window.XLSX) return;
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
const script = document.createElement('script');
|
|
10
|
+
script.src = this.CDN_URL;
|
|
11
|
+
script.async = true;
|
|
12
|
+
script.onload = () => resolve();
|
|
13
|
+
script.onerror = () => reject(new Error('Falha ao baixar dependência XLSX.'));
|
|
14
|
+
document.head.appendChild(script);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static async paraExcel(dados, colunas, nomeArquivo, nomePlanilha = 'Dados') {
|
|
19
|
+
await this.carregarDependencia();
|
|
20
|
+
const dadosFormatados = dados.map(item => {
|
|
21
|
+
const linha = {};
|
|
22
|
+
colunas.forEach(col => { linha[col.display] = item[col.key]; });
|
|
23
|
+
return linha;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const planilha = XLSX.utils.json_to_sheet(dadosFormatados);
|
|
27
|
+
const pastaTrabalho = XLSX.utils.book_new();
|
|
28
|
+
XLSX.utils.book_append_sheet(pastaTrabalho, planilha, nomePlanilha);
|
|
29
|
+
XLSX.writeFile(pastaTrabalho, `${nomeArquivo}.xlsx`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static paraCSV(dados, colunas, nomeArquivo) {
|
|
33
|
+
const linhaCabecalho = colunas.map(c => `"${c.display}"`).join(';');
|
|
34
|
+
const linhasCorpo = dados.map(item => {
|
|
35
|
+
return colunas.map(col => {
|
|
36
|
+
const val = item[col.key] ?? '';
|
|
37
|
+
const valString = String(val).replace(/"/g, '""').replace(/\r?\n|\r/g, ' ');
|
|
38
|
+
return `"${valString}"`;
|
|
39
|
+
}).join(';');
|
|
40
|
+
});
|
|
41
|
+
const conteudoCsv = [linhaCabecalho, ...linhasCorpo].join('\r\n');
|
|
42
|
+
const blob = new Blob([conteudoCsv], { type: 'text/csv;charset=utf-8;' });
|
|
43
|
+
const link = document.createElement('a');
|
|
44
|
+
if (link.download !== undefined) {
|
|
45
|
+
const url = URL.createObjectURL(blob);
|
|
46
|
+
link.setAttribute('href', url);
|
|
47
|
+
link.setAttribute('download', `${nomeArquivo}.csv`);
|
|
48
|
+
link.style.visibility = 'hidden';
|
|
49
|
+
document.body.appendChild(link);
|
|
50
|
+
link.click();
|
|
51
|
+
document.body.removeChild(link);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static async exportar(dados, colunas, nomeArquivo = 'exportacao', formato = 'xlsx') {
|
|
56
|
+
if (!dados?.length) throw new Error("Sem dados para exportar.");
|
|
57
|
+
if (!colunas?.length) throw new Error("Colunas não definidas.");
|
|
58
|
+
|
|
59
|
+
const fmt = formato.toLowerCase();
|
|
60
|
+
if (fmt === 'xlsx') await this.paraExcel(dados, colunas, nomeArquivo);
|
|
61
|
+
else if (fmt === 'csv') this.paraCSV(dados, colunas, nomeArquivo);
|
|
62
|
+
else throw new Error(`Formato '${formato}' não suportado.`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
export class UtilitariosFormatacao {
|
|
4
|
+
static moeda(valor) {
|
|
5
|
+
const valorNumerico = parseFloat(valor);
|
|
6
|
+
if (isNaN(valorNumerico)) return "R$ 0,00";
|
|
7
|
+
return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(valorNumerico);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
static numerico(valor) {
|
|
11
|
+
const valorNumerico = parseFloat(valor);
|
|
12
|
+
if (isNaN(valorNumerico)) return "0";
|
|
13
|
+
return new Intl.NumberFormat('pt-BR', { maximumFractionDigits: 0 }).format(valorNumerico);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static decimal(valor) {
|
|
17
|
+
const valorNumerico = parseFloat(valor);
|
|
18
|
+
if (isNaN(valorNumerico)) return "0,00";
|
|
19
|
+
return new Intl.NumberFormat('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(valorNumerico);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static porcentagem(valor) {
|
|
23
|
+
const valorNumerico = parseFloat(valor);
|
|
24
|
+
if (isNaN(valorNumerico)) return "0,00 %";
|
|
25
|
+
return new Intl.NumberFormat('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(valorNumerico) + ' %';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static data() {
|
|
29
|
+
return new Intl.DateTimeFormat('pt-BR').format(new Date());
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static formatarDataParaDMY(stringDataIso) {
|
|
33
|
+
if (!stringDataIso) return '';
|
|
34
|
+
const partes = stringDataIso.split('-');
|
|
35
|
+
if (partes.length !== 3) return stringDataIso;
|
|
36
|
+
return `${partes[2]}/${partes[1]}/${partes[0]}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static normalizarStringData(entradaData) {
|
|
40
|
+
if (!entradaData) return '01/01/2025';
|
|
41
|
+
let str = String(entradaData).trim();
|
|
42
|
+
|
|
43
|
+
if (str.includes('/')) {
|
|
44
|
+
const partes = str.split('/');
|
|
45
|
+
if (partes.length >= 3) {
|
|
46
|
+
const dia = String(parseInt(partes[0], 10)).padStart(2, '0');
|
|
47
|
+
const mes = String(parseInt(partes[1], 10)).padStart(2, '0');
|
|
48
|
+
const ano = partes[2].substring(0, 4);
|
|
49
|
+
return `${dia}/${mes}/${ano}`;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (str.includes('-')) {
|
|
54
|
+
const partes = str.split('-');
|
|
55
|
+
if (partes.length === 3) {
|
|
56
|
+
return `${partes[2].substring(0, 2)}/${partes[1]}/${partes[0]}`;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return str;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
static obterDataAtualISO() {
|
|
64
|
+
return new Date().toISOString().split('T')[0];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static dataHora() {
|
|
68
|
+
const agora = new Date();
|
|
69
|
+
const parteData = new Intl.DateTimeFormat('pt-BR').format(agora);
|
|
70
|
+
const parteHora = agora.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' });
|
|
71
|
+
return `${parteData} ${parteHora}`;
|
|
72
|
+
}
|
|
73
|
+
}
|
package/lib/jsk-core.js
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
export class ServicoDados {
|
|
4
|
+
|
|
5
|
+
// =========================================================================
|
|
6
|
+
// PARTE 1: MANIPULAÇÃO DE DADOS (Banco de Dados)
|
|
7
|
+
// =========================================================================
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Define o executor de query padrão (Legado).
|
|
11
|
+
*/
|
|
12
|
+
static definirExecutor(funcaoExecutor) {
|
|
13
|
+
this.executor = funcaoExecutor;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Realiza requisições POST.
|
|
18
|
+
*/
|
|
19
|
+
static async post(url, corpo, { headers, raw } = { headers: {}, raw: false }) {
|
|
20
|
+
let isJSON = true;
|
|
21
|
+
|
|
22
|
+
if (headers) {
|
|
23
|
+
const cabecalhoTipoOriginal = headers['Content-Type'] ? String(headers['Content-Type']) : 'application/json; charset=UTF-8';
|
|
24
|
+
isJSON = headers['Content-Type'] ? RegExp(/json/i).exec(headers['Content-Type']) : isJSON;
|
|
25
|
+
if (headers['Content-Type']) delete headers['Content-Type'];
|
|
26
|
+
headers['Content-Type'] = cabecalhoTipoOriginal;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
let corpoRequisicaoFormatado = corpo;
|
|
31
|
+
if (corpo && typeof corpo === 'object') {
|
|
32
|
+
corpoRequisicaoFormatado = JSON.stringify(corpo);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (typeof window === 'undefined' || !window.fetch) {
|
|
36
|
+
throw new Error("Requer ambiente de navegador com 'fetch'.");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const resposta = await window.fetch.bind(window)(url, {
|
|
40
|
+
headers,
|
|
41
|
+
method: 'POST',
|
|
42
|
+
redirect: 'follow',
|
|
43
|
+
credentials: 'include',
|
|
44
|
+
body: corpoRequisicaoFormatado
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
if (raw) return resposta;
|
|
48
|
+
return isJSON ? resposta.json() : resposta.text();
|
|
49
|
+
|
|
50
|
+
} catch (erro) {
|
|
51
|
+
console.error("[JSK] Erro no POST:", erro);
|
|
52
|
+
throw erro;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Normaliza a resposta da API.
|
|
58
|
+
*/
|
|
59
|
+
static normalizarResposta(valorBruto) {
|
|
60
|
+
try {
|
|
61
|
+
const valorParseado = typeof valorBruto === 'string' ? JSON.parse(valorBruto) : valorBruto;
|
|
62
|
+
if (!valorParseado) return [];
|
|
63
|
+
if (Array.isArray(valorParseado)) return valorParseado;
|
|
64
|
+
|
|
65
|
+
let dadosFinais = null;
|
|
66
|
+
if (typeof valorParseado === 'object') {
|
|
67
|
+
if (typeof valorParseado.b === 'string') {
|
|
68
|
+
dadosFinais = JSON.parse(valorParseado.b);
|
|
69
|
+
} else if (valorParseado.c?.b && typeof valorParseado.c.b === 'string') {
|
|
70
|
+
dadosFinais = JSON.parse(valorParseado.c.b);
|
|
71
|
+
} else if (valorParseado.data?.responseBody || valorParseado.responseBody) {
|
|
72
|
+
const corpo = valorParseado.data?.responseBody || valorParseado.responseBody;
|
|
73
|
+
dadosFinais = typeof corpo === 'string' ? JSON.parse(corpo) : corpo;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (Array.isArray(dadosFinais)) return dadosFinais;
|
|
77
|
+
throw new Error("Formato de resposta inválido.");
|
|
78
|
+
} catch (erro) {
|
|
79
|
+
throw new Error(`Erro ao normalizar resposta: ${erro.message}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Executa consulta SQL.
|
|
85
|
+
*/
|
|
86
|
+
static async consultar(query, params = null) {
|
|
87
|
+
const executor = this.executor || (typeof window !== 'undefined' ? window.executeQuery : null);
|
|
88
|
+
|
|
89
|
+
if (typeof executor !== 'function') {
|
|
90
|
+
return Promise.reject(new Error("Executor 'executeQuery' não encontrado."));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return new Promise((resolve, reject) => {
|
|
94
|
+
executor(query, params,
|
|
95
|
+
(valorBruto) => {
|
|
96
|
+
try {
|
|
97
|
+
const dados = ServicoDados.normalizarResposta(valorBruto);
|
|
98
|
+
resolve(dados || []);
|
|
99
|
+
} catch (err) { reject(err); }
|
|
100
|
+
},
|
|
101
|
+
(err) => reject(new Error(`Erro na query: ${err}`))
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Executa consulta paginada.
|
|
108
|
+
*/
|
|
109
|
+
static async consultarPaginado(query, params = null, limite, offset) {
|
|
110
|
+
const limiteSeguro = Number(limite);
|
|
111
|
+
const offsetSeguro = Number(offset);
|
|
112
|
+
if (isNaN(limiteSeguro) || isNaN(offsetSeguro) || limiteSeguro < 0) throw new Error("Parâmetros de paginação inválidos.");
|
|
113
|
+
|
|
114
|
+
const queryPaginada = `${query} LIMIT ${limiteSeguro} OFFSET ${offsetSeguro}`;
|
|
115
|
+
const dados = await ServicoDados.consultar(queryPaginada, params);
|
|
116
|
+
const paginaAtual = Math.floor(offsetSeguro / limiteSeguro) + 1;
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
dados,
|
|
120
|
+
meta: { paginaAtual, itensPorPagina: limiteSeguro, totalItens: null, totalPaginas: null }
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Salva (Insert/Update) via DatasetSP.
|
|
126
|
+
*/
|
|
127
|
+
static async salvar(dados, entidade, chavesPrimarias = null) {
|
|
128
|
+
const url = `${window.location.origin}/mge/service.sbr?serviceName=DatasetSP.save&outputType=json`;
|
|
129
|
+
const chavesDados = Object.keys(dados);
|
|
130
|
+
const fields = chavesDados.map(campo => campo.toUpperCase());
|
|
131
|
+
const values = {};
|
|
132
|
+
|
|
133
|
+
chavesDados.forEach((chave, indice) => {
|
|
134
|
+
values[indice.toString()] = String(dados[chave]);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const record = { values: values };
|
|
138
|
+
if (chavesPrimarias) {
|
|
139
|
+
const pk = {};
|
|
140
|
+
Object.keys(chavesPrimarias).forEach(chave => pk[chave.toUpperCase()] = String(chavesPrimarias[chave]));
|
|
141
|
+
record.pk = pk;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return await ServicoDados.post(url, {
|
|
145
|
+
serviceName: 'DatasetSP.save',
|
|
146
|
+
requestBody: { entityName: entidade, fields: fields, records: [record] }
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Exclui registro via DatasetSP.
|
|
152
|
+
*/
|
|
153
|
+
static async excluir(entidade, chavesPrimarias) {
|
|
154
|
+
const url = `${window.location.origin}/mge/service.sbr?serviceName=DatasetSP.removeRecord&outputType=json`;
|
|
155
|
+
return ServicoDados.post(url, {
|
|
156
|
+
serviceName: 'DatasetSP.removeRecord',
|
|
157
|
+
requestBody: {
|
|
158
|
+
entityName: entidade,
|
|
159
|
+
pks: Array.isArray(chavesPrimarias) ? chavesPrimarias : [chavesPrimarias]
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// =========================================================================
|
|
165
|
+
// PARTE 2: SERVIÇO DE PÁGINA (Interface / Navegação)
|
|
166
|
+
// =========================================================================
|
|
167
|
+
|
|
168
|
+
static getUrl(path) {
|
|
169
|
+
return `${window.location.origin}${path ? '/' + path.replace('/', '') : ''}`;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Remove o frame (Modo Fullscreen).
|
|
174
|
+
* Requer ID (nuGdt) resolvido previamente.
|
|
175
|
+
*/
|
|
176
|
+
static removerFrame({ nuGdt, paginaInicial, ...opcoes } = { nuGdt: 0, paginaInicial: 'app.jsp' }) {
|
|
177
|
+
return new Promise(resolve => {
|
|
178
|
+
// Limpa alertas e scroll do parent
|
|
179
|
+
[window.parent.document, window.parent.parent.document].forEach(doc => {
|
|
180
|
+
if (doc && doc.getElementsByTagName('body').length) {
|
|
181
|
+
const alertBox = doc.querySelector('div.gwt-PopupPanel.alert-box.box-shadow');
|
|
182
|
+
if (alertBox) alertBox.style.display = 'none';
|
|
183
|
+
doc.getElementsByTagName('body')[0].style.overflow = 'hidden';
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
resolve({ gadGetID: 'html5_z6dld', nuGdt: nuGdt || 0, ...opcoes });
|
|
188
|
+
}).then(o =>
|
|
189
|
+
setTimeout(() => {
|
|
190
|
+
if (typeof window.parent.document.getElementsByClassName('DashWindow')[0] != 'undefined') {
|
|
191
|
+
const opcoesUrl = Object.keys(o)
|
|
192
|
+
.filter(item => !['params', 'UID', 'instance', 'nuGdg', 'gadGetID'].includes(item))
|
|
193
|
+
.map(item => `&${item}=${o[item]}`)
|
|
194
|
+
.join('');
|
|
195
|
+
|
|
196
|
+
const url = `/mge/html5component.mge?entryPoint=${paginaInicial}&nuGdg=${o.nuGdt}${opcoesUrl}`;
|
|
197
|
+
|
|
198
|
+
const gadgetDiv = window.parent.document.getElementsByClassName('dyna-gadget')[0];
|
|
199
|
+
if (gadgetDiv) {
|
|
200
|
+
gadgetDiv.innerHTML = `<iframe src="${url}" class="gwt-Frame" style="width: 100%; height: 100%;"></iframe>`;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Limpa popups residuais
|
|
204
|
+
const popup = document.getElementsByClassName('popupContent')[0];
|
|
205
|
+
if (popup && popup.parentElement) popup.parentElement.remove();
|
|
206
|
+
|
|
207
|
+
// Trava scroll local
|
|
208
|
+
const styleEl = document.getElementById('stndz-style');
|
|
209
|
+
if (styleEl && styleEl.parentElement && styleEl.parentElement.parentElement) {
|
|
210
|
+
styleEl.parentElement.parentElement.getElementsByTagName('body')[0].style.overflow = 'hidden';
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}, 500)
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Abre Nova Guia.
|
|
219
|
+
*/
|
|
220
|
+
static novaGuia(forcado = false) {
|
|
221
|
+
const isSankhya = !!window.parent.parent.document.querySelector('.Taskbar-container');
|
|
222
|
+
if ((isSankhya && !forcado) || forcado) {
|
|
223
|
+
Object.assign(document.createElement('a'), { target: '_blank', href: window.location.href }).click();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Abre Pagina no Sankhya-W.
|
|
229
|
+
*/
|
|
230
|
+
static abrirPagina(resourceID, chavesPrimarias) {
|
|
231
|
+
let url = ServicoDados.getUrl(`/mge/system.jsp#app/%resID`);
|
|
232
|
+
url = url.replace('%resID', btoa(resourceID));
|
|
233
|
+
|
|
234
|
+
if (chavesPrimarias) {
|
|
235
|
+
let body = {};
|
|
236
|
+
Object.keys(chavesPrimarias).forEach(k => body[k] = isNaN(chavesPrimarias[k]) ? String(chavesPrimarias[k]) : Number(chavesPrimarias[k]));
|
|
237
|
+
url = url.concat(`/${btoa(JSON.stringify(body))}`);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
Object.assign(document.createElement('a'), { target: '_top', href: url }).click();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Fecha a Pagina atual.
|
|
245
|
+
*/
|
|
246
|
+
static fecharPagina() {
|
|
247
|
+
const closeBtn = window.parent.parent.document.querySelector('li.ListItem.AppItem.AppItem-selected div.Taskbar-icon.icon-close');
|
|
248
|
+
if (closeBtn) closeBtn.click();
|
|
249
|
+
else window.close();
|
|
250
|
+
}
|
|
251
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
export class UtilitariosOrdenacao {
|
|
4
|
+
static ordenar(dados, chave, direcao = 'asc') {
|
|
5
|
+
if (!Array.isArray(dados) || !chave) return dados;
|
|
6
|
+
const multiplicador = direcao === 'asc' ? 1 : -1;
|
|
7
|
+
|
|
8
|
+
return [...dados].sort((a, b) => {
|
|
9
|
+
const valA = a[chave];
|
|
10
|
+
const valB = b[chave];
|
|
11
|
+
if (valA == null) return 1;
|
|
12
|
+
if (valB == null) return -1;
|
|
13
|
+
if (typeof valA === 'string' && typeof valB === 'string') {
|
|
14
|
+
return valA.localeCompare(valB) * multiplicador;
|
|
15
|
+
}
|
|
16
|
+
if (valA < valB) return -1 * multiplicador;
|
|
17
|
+
if (valA > valB) return 1 * multiplicador;
|
|
18
|
+
return 0;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|