This commit is contained in:
2026-04-14 08:37:19 -03:00
parent fb2bec0fd5
commit 54ab21ef3b
91 changed files with 5660 additions and 195 deletions
@@ -0,0 +1,19 @@
application.type=widget
application.code=wdtransf
application.title=wdtransf
application.description=wdtransf
application.fluig.version=null
application.category=SYSTEM
application.renderer=freemarker
developer.code=Andrey Cunha
developer.name=Andrey cunha
developer.url=http://www.fluig.com
application.uiwidget=true
application.mobileapp=false
application.version=${build.version}-${build.revision}
view.file=view.ftl
edit.file=edit.ftl
locale.file.base.name=wdtransf
application.resource.js.1=/resources/js/wdtransf.js
application.resource.css.2=/resources/css/wdtransf.css
hash=4a16315e9e66fa7d797b3f6b1fb365b69f9a4ce2
@@ -0,0 +1,5 @@
<div id="MyWidget_${instanceId}" class="super-widget wcm-widget-class fluig-style-guide" data-params="WdTransfWidget.instance()">
</div>
@@ -0,0 +1,97 @@
<div id="MyWidget_${instanceId}" class="super-widget wcm-widget-class fluig-style-guide wdtransf-widget" data-params="WdTransfWidget.instance()">
<div class="wdtransf-shell">
<div class="wdtransf-head">
<div>
<h3 class="wdtransf-title">Monitor de Transferencias</h3>
<p class="wdtransf-subtitle">Fonte: dataset <strong>transferenciav2</strong></p>
</div>
<span class="wdtransf-updated" data-role="updatedAt">Atualizando...</span>
</div>
<div class="wdtransf-filters row">
<div class="col-md-6 col-sm-12">
<label class="wdtransf-label">Busca</label>
<input type="text" class="form-control" data-role="search" placeholder="WKNumProces, requesterName, ufOrigem, ufDestino..." />
</div>
<div class="col-md-4 col-sm-6">
<label class="wdtransf-label">Atividade</label>
<select class="form-control" data-role="activityFilter"></select>
</div>
<div class="col-md-2 col-sm-12 wdtransf-actions">
<button type="button" class="btn btn-primary" data-action="reload">Atualizar</button>
</div>
</div>
<div class="wdtransf-message" data-role="message" style="display:none;"></div>
<div class="wdtransf-kpis row">
<div class="col-md-3 col-sm-6">
<div class="wdtransf-kpi">
<div class="wdtransf-kpi-label">Total carregado</div>
<div class="wdtransf-kpi-value" data-role="kpiTotal">0</div>
</div>
</div>
<div class="col-md-3 col-sm-6">
<div class="wdtransf-kpi">
<div class="wdtransf-kpi-label">Em transito</div>
<div class="wdtransf-kpi-value" data-role="kpiTransit">0</div>
</div>
</div>
<div class="col-md-2 col-sm-4">
<div class="wdtransf-kpi">
<div class="wdtransf-kpi-label">Aguard. recebimento</div>
<div class="wdtransf-kpi-value" data-role="kpiPendingReceipt">0</div>
</div>
</div>
<div class="col-md-2 col-sm-4">
<div class="wdtransf-kpi">
<div class="wdtransf-kpi-label">Em problema</div>
<div class="wdtransf-kpi-value" data-role="kpiProblem">0</div>
</div>
</div>
<div class="col-md-2 col-sm-4">
<div class="wdtransf-kpi">
<div class="wdtransf-kpi-label">Finalizadas</div>
<div class="wdtransf-kpi-value" data-role="kpiDone">0</div>
</div>
</div>
</div>
<div class="wdtransf-panel">
<div class="wdtransf-panel-title">Funil por etapa</div>
<div class="wdtransf-stage-list" data-role="stageBars"></div>
</div>
<div class="wdtransf-panel">
<div class="wdtransf-panel-title">Detalhes das transferencias</div>
<div class="table-responsive">
<table class="table table-condensed table-striped wdtransf-table">
<thead>
<tr>
<th>Processo</th>
<th>Solicitante</th>
<th>Origem</th>
<th>Destino</th>
<th>Data abertura</th>
<th>Atividade</th>
</tr>
</thead>
<tbody data-role="tableBody">
<tr>
<td colspan="6">Carregando dados...</td>
</tr>
</tbody>
</table>
</div>
<div class="wdtransf-pagination">
<div class="wdtransf-pagination-info" data-role="pageInfo">Exibindo 0 de 0</div>
<div class="wdtransf-pagination-controls">
<button type="button" class="btn btn-default btn-sm" data-action="prevPage">Anterior</button>
<span class="wdtransf-page-status" data-role="pageStatus">Pagina 0 de 0</span>
<button type="button" class="btn btn-default btn-sm" data-action="nextPage">Proxima</button>
</div>
</div>
</div>
</div>
</div>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<context-root>/wdtransf</context-root>
<disable-cross-context>false</disable-cross-context>
</jboss-web>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
</web-app>
@@ -0,0 +1,277 @@
.wdtransf-widget .wdtransf-shell {
background: #f4f7fb;
border: 1px solid #d8e3ee;
border-radius: 12px;
padding: 14px;
}
.wdtransf-widget .wdtransf-head {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 12px;
margin-bottom: 12px;
}
.wdtransf-widget .wdtransf-title {
margin: 0;
color: #0f4a77;
font-size: 22px;
font-weight: 700;
}
.wdtransf-widget .wdtransf-subtitle {
margin: 4px 0 0;
color: #5a6c7f;
font-size: 12px;
}
.wdtransf-widget .wdtransf-updated {
color: #4f6274;
font-size: 11px;
white-space: nowrap;
}
.wdtransf-widget .wdtransf-label {
display: block;
margin-bottom: 4px;
color: #3e5a73;
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
}
.wdtransf-widget .wdtransf-filters {
margin-bottom: 10px;
}
.wdtransf-widget .wdtransf-filters .form-control {
height: 36px;
border-radius: 8px;
}
.wdtransf-widget .wdtransf-actions {
display: flex;
align-items: flex-end;
gap: 6px;
padding-top: 18px;
}
.wdtransf-widget .wdtransf-message {
margin-bottom: 10px;
border-radius: 8px;
padding: 8px 10px;
font-size: 12px;
border: 1px solid transparent;
}
.wdtransf-widget .wdtransf-message.is-info {
background: #e8f1fb;
color: #1d4f7d;
border-color: #bed6ee;
}
.wdtransf-widget .wdtransf-message.is-success {
background: #e8f6ea;
color: #2b6a3b;
border-color: #bde0c3;
}
.wdtransf-widget .wdtransf-message.is-warning {
background: #fff5e8;
color: #8f6219;
border-color: #f0d8b5;
}
.wdtransf-widget .wdtransf-message.is-danger {
background: #fdecec;
color: #9a2f2f;
border-color: #e8b8b8;
}
.wdtransf-widget .wdtransf-kpis {
margin-bottom: 12px;
}
.wdtransf-widget .wdtransf-kpi {
background: #ffffff;
border: 1px solid #dbe6f1;
border-radius: 10px;
padding: 10px 12px;
min-height: 72px;
}
.wdtransf-widget .wdtransf-kpi-label {
color: #4b647b;
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
}
.wdtransf-widget .wdtransf-kpi-value {
margin-top: 4px;
color: #0f4a77;
font-size: 24px;
font-weight: 700;
line-height: 1.1;
}
.wdtransf-widget .wdtransf-panel {
background: #ffffff;
border: 1px solid #dbe6f1;
border-radius: 10px;
padding: 10px 12px;
margin-bottom: 12px;
}
.wdtransf-widget .wdtransf-panel-title {
color: #1a537f;
font-size: 13px;
font-weight: 700;
margin-bottom: 8px;
text-transform: uppercase;
letter-spacing: 0.02em;
}
.wdtransf-widget .wdtransf-stage-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.wdtransf-widget .wdtransf-stage-item {
display: grid;
grid-template-columns: 180px 1fr 62px;
gap: 8px;
align-items: center;
}
.wdtransf-widget .wdtransf-stage-label {
color: #3f5d75;
font-size: 12px;
font-weight: 600;
}
.wdtransf-widget .wdtransf-stage-bar-wrap {
background: #edf2f7;
border: 1px solid #d5e0eb;
border-radius: 999px;
height: 14px;
overflow: hidden;
}
.wdtransf-widget .wdtransf-stage-bar {
background: linear-gradient(90deg, #2f84bf 0%, #0f5b91 100%);
height: 100%;
min-width: 0;
}
.wdtransf-widget .wdtransf-stage-value {
text-align: right;
color: #244d70;
font-size: 12px;
font-weight: 700;
}
.wdtransf-widget .wdtransf-table {
margin-bottom: 0;
}
.wdtransf-widget .wdtransf-table thead th {
background: #eef4fb;
color: #3f5d75;
font-size: 11px;
border-bottom: 1px solid #d6e1ed;
}
.wdtransf-widget .wdtransf-table tbody td {
font-size: 12px;
vertical-align: middle;
}
.wdtransf-widget .wdtransf-pagination {
margin-top: 10px;
padding-top: 8px;
border-top: 1px solid #e1e9f2;
display: flex;
justify-content: space-between;
align-items: center;
gap: 10px;
flex-wrap: wrap;
}
.wdtransf-widget .wdtransf-pagination-info {
color: #536b81;
font-size: 12px;
}
.wdtransf-widget .wdtransf-pagination-controls {
display: flex;
align-items: center;
gap: 6px;
}
.wdtransf-widget .wdtransf-page-status {
min-width: 110px;
text-align: center;
color: #2d5679;
font-size: 12px;
font-weight: 600;
}
.wdtransf-widget .wdtransf-status {
display: inline-block;
padding: 2px 8px;
border-radius: 999px;
font-size: 11px;
font-weight: 700;
border: 1px solid transparent;
}
.wdtransf-widget .wdtransf-status.is-progress {
color: #1d6095;
background: #e8f2fb;
border-color: #c3dbef;
}
.wdtransf-widget .wdtransf-status.is-problem {
color: #a53333;
background: #feecec;
border-color: #efb9b9;
}
.wdtransf-widget .wdtransf-status.is-done {
color: #2f6f41;
background: #e9f8ed;
border-color: #bfe4c7;
}
.wdtransf-widget .wdtransf-status.is-cancel {
color: #8c651f;
background: #fff5e8;
border-color: #f0dcba;
}
.wdtransf-widget.is-loading .wdtransf-panel,
.wdtransf-widget.is-loading .wdtransf-kpi {
opacity: 0.85;
}
@media (max-width: 767px) {
.wdtransf-widget .wdtransf-head {
flex-direction: column;
align-items: flex-start;
}
.wdtransf-widget .wdtransf-actions {
padding-top: 6px;
}
.wdtransf-widget .wdtransf-stage-item {
grid-template-columns: 1fr;
}
.wdtransf-widget .wdtransf-stage-value {
text-align: left;
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

@@ -0,0 +1,570 @@
var WdTransfWidget = SuperWidget.extend({
datasetName: "transferenciav2",
pageSize: 10,
batchSize: 1000,
currentPage: 1,
rowsCache: [],
isIncrementalLoading: false,
loadOffset: 0,
batchToken: 0,
lastChunkMarker: "",
noPagingMode: false,
stageDefs: [
{ label: "Solicitacao", activities: ["0", "1"] },
{ label: "Aprovacao", activities: ["4"] },
{ label: "Emissao NFe", activities: ["6"] },
{ label: "Coleta", activities: ["31"] },
{ label: "Entrega", activities: ["57"] },
{ label: "Recebimento", activities: ["18"] },
{ label: "Consultar Entrada", activities: ["99"] },
{ label: "Verificar Problema", activities: ["24", "104"] },
{ label: "Finalizada", activities: ["96", "101"] },
{ label: "Cancelada", activities: ["39", "60"] }
],
bindings: {
local: {},
global: {}
},
init: function() {
this.$widget = $("#MyWidget_" + this.instanceId);
this.bindEvents();
this.populateActivityFilter();
this.currentPage = 1;
this.loadData();
},
bindEvents: function() {
var self = this;
self.$widget.on("click", "[data-action='reload']", function() {
self.currentPage = 1;
self.loadData();
});
self.$widget.on("change", "[data-role='activityFilter']", function() {
self.currentPage = 1;
self.render();
});
self.$widget.on("keypress", "[data-role='search']", function(e) {
if (e.which === 13) {
e.preventDefault();
self.currentPage = 1;
self.render();
}
});
self.$widget.on("click", "[data-action='prevPage']", function() {
self.setPage(self.currentPage - 1);
});
self.$widget.on("click", "[data-action='nextPage']", function() {
self.setPage(self.currentPage + 1);
});
},
populateActivityFilter: function() {
var added = {};
var options = ["<option value=''>Todas</option>"];
for (var i = 0; i < this.stageDefs.length; i++) {
var stage = this.stageDefs[i];
for (var j = 0; j < stage.activities.length; j++) {
var code = String(stage.activities[j]);
if (added[code]) continue;
added[code] = true;
options.push(
"<option value='" + this.escapeHtml(code) + "'>" +
this.escapeHtml(code + " - " + this.getActivityLabel(code)) +
"</option>"
);
}
}
this.$widget.find("[data-role='activityFilter']").html(options.join(""));
},
loadData: function() {
this.batchToken++;
this.rowsCache = [];
this.currentPage = 1;
this.loadOffset = 0;
this.lastChunkMarker = "";
this.noPagingMode = false;
this.isIncrementalLoading = true;
this.setLoading(true);
this.setMessage("Carregando solicitacoes...", "info");
this.render();
this.loadNextBatch(this.batchToken);
},
loadNextBatch: function(token) {
var self = this;
if (token !== self.batchToken) return;
self.fetchDatasetBatch(self.batchSize, self.loadOffset, function(err, rows) {
if (token !== self.batchToken) return;
if (err) {
self.isIncrementalLoading = false;
self.setLoading(false);
self.render();
self.setMessage("Erro ao carregar dataset: " + err, "danger");
return;
}
rows = rows || [];
if (!rows.length) {
self.isIncrementalLoading = false;
self.setLoading(false);
self.render();
self.setMessage("Dados carregados: " + self.formatNumber(self.rowsCache.length) + " registro(s).", "success");
return;
}
var chunkMarker = self.buildChunkMarker(rows[0]);
if (self.loadOffset > 0 && chunkMarker && chunkMarker === self.lastChunkMarker) {
self.isIncrementalLoading = false;
self.setLoading(false);
self.render();
self.setMessage("Paginacao do dataset nao evoluiu (sqlStart/offset). Verifique suporte no ambiente.", "warning");
return;
}
self.lastChunkMarker = chunkMarker;
self.rowsCache = self.rowsCache.concat(rows);
self.loadOffset += rows.length;
self.render();
self.setMessage("Carregando solicitacoes... " + self.formatNumber(self.rowsCache.length) + " registro(s).", "info");
if (self.noPagingMode) {
self.isIncrementalLoading = false;
self.setLoading(false);
self.render();
self.setMessage("Dados carregados: " + self.formatNumber(self.rowsCache.length) + " registro(s).", "success");
return;
}
if (rows.length < self.batchSize) {
self.isIncrementalLoading = false;
self.setLoading(false);
self.render();
self.setMessage("Dados carregados: " + self.formatNumber(self.rowsCache.length) + " registro(s).", "success");
return;
}
setTimeout(function() {
self.loadNextBatch(token);
}, 0);
});
},
fetchDatasetBatch: function(limit, offset, callback) {
var self = this;
if (self.noPagingMode && offset > 0) {
callback(null, []);
return;
}
try {
if (typeof DatasetFactory !== "undefined" && typeof DatasetFactory.getDataset === "function" &&
typeof ConstraintType !== "undefined" && typeof DatasetFactory.createConstraint === "function") {
var constraints = self.noPagingMode ? null : self.buildFactoryPagingConstraints(limit, offset);
var ds = DatasetFactory.getDataset(self.datasetName, null, constraints, null);
var rows = (ds && ds.values) ? ds.values : [];
// Fallback para datasets (card/form) que nao suportam sqlLimit/sqlStart como MUST.
if (!rows.length && offset === 0 && !self.noPagingMode) {
var dsNoPaging = DatasetFactory.getDataset(self.datasetName, null, null, null);
var rowsNoPaging = (dsNoPaging && dsNoPaging.values) ? dsNoPaging.values : [];
if (rowsNoPaging.length) {
self.noPagingMode = true;
callback(null, rowsNoPaging);
return;
}
}
callback(null, rows);
return;
}
} catch (e) {
// fallback REST
}
this.fetchDatasetBatchViaRest(limit, offset, callback);
},
buildFactoryPagingConstraints: function(limit, offset) {
var constraints = [];
constraints.push(DatasetFactory.createConstraint("sqlLimit", String(limit), String(limit), ConstraintType.MUST));
constraints.push(DatasetFactory.createConstraint("sqlStart", String(offset), String(offset), ConstraintType.MUST));
constraints.push(DatasetFactory.createConstraint("offset", String(offset), String(offset), ConstraintType.MUST));
constraints.push(DatasetFactory.createConstraint("sqlOffset", String(offset), String(offset), ConstraintType.MUST));
return constraints;
},
fetchDatasetBatchViaRest: function(limit, offset, callback) {
var self = this;
if (self.noPagingMode && offset > 0) {
callback(null, []);
return;
}
function readRows(resp) {
if (resp && resp.content && resp.content.values) return resp.content.values;
if (resp && resp.values) return resp.values;
return [];
}
function request(usePaging, done) {
var constraints = usePaging ? self.buildRestPagingConstraints(limit, offset) : [];
$.ajax({
url: "/api/public/ecm/dataset/datasets",
type: "POST",
contentType: "application/json; charset=UTF-8",
dataType: "json",
data: JSON.stringify({
name: self.datasetName,
fields: [],
constraints: constraints,
order: []
})
}).done(function(resp) {
done(null, readRows(resp) || []);
}).fail(function(xhr) {
var detail = xhr && (xhr.responseText || xhr.statusText || xhr.status);
done(detail || "falha na API REST de datasets", []);
});
}
request(!self.noPagingMode, function(err, rows) {
if (err) {
callback(err);
return;
}
if (!rows.length && offset === 0 && !self.noPagingMode) {
request(false, function(err2, rows2) {
if (err2) {
callback(err2);
return;
}
if (rows2.length) {
self.noPagingMode = true;
}
callback(null, rows2 || []);
});
return;
}
callback(null, rows || []);
});
},
buildRestPagingConstraints: function(limit, offset) {
return [
{ _field: "sqlLimit", _initialValue: String(limit), _finalValue: String(limit), _type: 1 },
{ _field: "sqlStart", _initialValue: String(offset), _finalValue: String(offset), _type: 1 },
{ _field: "offset", _initialValue: String(offset), _finalValue: String(offset), _type: 1 },
{ _field: "sqlOffset", _initialValue: String(offset), _finalValue: String(offset), _type: 1 }
];
},
buildChunkMarker: function(row) {
if (!row) return "";
var id = this.pick(row, ["metadata#id", "id", "WKNumProces", "processInstanceId"]);
var state = this.pick(row, ["activity", "WKNumState", "state"]);
return (id || "-") + "|" + (state || "-");
},
render: function() {
var rows = this.getFilteredRows(this.rowsCache);
this.renderKpis(rows);
this.renderStageBars(rows);
this.renderTable(rows);
this.renderUpdatedAt();
},
getFilteredRows: function(rows) {
var out = [];
var search = $.trim(String(this.$widget.find("[data-role='search']").val() || "")).toLowerCase();
var activityFilter = $.trim(String(this.$widget.find("[data-role='activityFilter']").val() || ""));
for (var i = 0; i < (rows || []).length; i++) {
var row = rows[i] || {};
var activityCode = this.getActivityCode(row);
if (activityFilter && activityCode !== activityFilter) {
continue;
}
if (search) {
var base = this.extractRow(row);
var blob = [
base.processo,
base.solicitante,
base.origem,
base.destino,
base.dataAbertura,
base.atividadeCode
].join(" ").toLowerCase();
if (blob.indexOf(search) === -1) {
continue;
}
}
out.push(row);
}
return out;
},
renderKpis: function(rows) {
var total = rows.length;
var transit = this.countByActivities(rows, ["31", "57"]);
var pendingReceipt = this.countByActivities(rows, ["18"]);
var problem = this.countByActivities(rows, ["24", "104"]);
var done = this.countByActivities(rows, ["96", "101"]);
this.$widget.find("[data-role='kpiTotal']").text(this.formatNumber(total));
this.$widget.find("[data-role='kpiTransit']").text(this.formatNumber(transit));
this.$widget.find("[data-role='kpiPendingReceipt']").text(this.formatNumber(pendingReceipt));
this.$widget.find("[data-role='kpiProblem']").text(this.formatNumber(problem));
this.$widget.find("[data-role='kpiDone']").text(this.formatNumber(done));
},
renderStageBars: function(rows) {
var total = rows.length;
var html = [];
for (var i = 0; i < this.stageDefs.length; i++) {
var stage = this.stageDefs[i];
var count = this.countByActivities(rows, stage.activities);
var percent = total > 0 ? ((count * 100) / total) : 0;
html.push(
"<div class='wdtransf-stage-item'>" +
"<span class='wdtransf-stage-label'>" + this.escapeHtml(stage.label) + "</span>" +
"<div class='wdtransf-stage-bar-wrap'>" +
"<div class='wdtransf-stage-bar' style='width:" + percent.toFixed(2) + "%;'></div>" +
"</div>" +
"<span class='wdtransf-stage-value'>" + this.formatNumber(count) + "</span>" +
"</div>"
);
}
this.$widget.find("[data-role='stageBars']").html(html.join(""));
},
renderTable: function(rows) {
var html = [];
var totalRows = rows.length;
var totalPages = totalRows > 0 ? Math.ceil(totalRows / this.pageSize) : 1;
if (this.currentPage > totalPages) {
this.currentPage = totalPages;
}
if (this.currentPage < 1) {
this.currentPage = 1;
}
var startIndex = totalRows > 0 ? ((this.currentPage - 1) * this.pageSize) : 0;
var endIndex = totalRows > 0 ? Math.min(startIndex + this.pageSize, totalRows) : 0;
var pageRows = rows.slice(startIndex, endIndex);
if (!totalRows) {
var emptyMsg = this.isIncrementalLoading ?
"Carregando dados..." :
"Nenhum registro para os filtros informados.";
html.push("<tr><td colspan='6'>" + this.escapeHtml(emptyMsg) + "</td></tr>");
this.$widget.find("[data-role='tableBody']").html(html.join(""));
this.renderPagination(0, 0, 0, 0);
return;
}
for (var i = 0; i < pageRows.length; i++) {
var base = this.extractRow(pageRows[i]);
html.push(
"<tr>" +
"<td>" + this.escapeHtml(base.processo) + "</td>" +
"<td>" + this.escapeHtml(base.solicitante) + "</td>" +
"<td>" + this.escapeHtml(base.origem) + "</td>" +
"<td>" + this.escapeHtml(base.destino) + "</td>" +
"<td>" + this.escapeHtml(base.dataAbertura) + "</td>" +
"<td>" + this.escapeHtml(base.atividadeCode) + "</td>" +
"</tr>"
);
}
this.$widget.find("[data-role='tableBody']").html(html.join(""));
this.renderPagination(totalRows, totalPages, startIndex + 1, endIndex);
},
renderPagination: function(totalRows, totalPages, firstRow, lastRow) {
var info = "Exibindo " + this.formatNumber(firstRow) + "-" + this.formatNumber(lastRow) +
" de " + this.formatNumber(totalRows);
if (totalRows === 0) {
info = "Exibindo 0-0 de 0";
}
this.$widget.find("[data-role='pageInfo']").text(info);
this.$widget.find("[data-role='pageStatus']").text(
"Pagina " + this.formatNumber(this.currentPage) + " de " +
this.formatNumber(totalPages || 1) +
(this.isIncrementalLoading ? " (carregando...)" : "")
);
var disablePrev = (this.currentPage <= 1 || totalRows === 0);
var disableNext = (this.currentPage >= (totalPages || 1) && !this.isIncrementalLoading) || totalRows === 0;
this.$widget.find("[data-action='prevPage']").prop("disabled", disablePrev);
this.$widget.find("[data-action='nextPage']").prop("disabled", disableNext);
},
setPage: function(page) {
var n = parseInt(page, 10);
if (isNaN(n)) return;
if (n < 1) n = 1;
var totalPages = Math.ceil(this.getFilteredRows(this.rowsCache).length / this.pageSize) || 1;
if (n > totalPages) {
if (this.isIncrementalLoading) {
this.setMessage("Aguarde: ainda carregando mais registros...", "info");
return;
}
n = totalPages;
}
this.currentPage = n;
this.render();
},
extractRow: function(row) {
var activityCode = this.getActivityCode(row);
var solicitante = this.pick(row, ["requesterName"]) || "-";
var origem = this.pick(row, ["ufOrigem"]) || "-";
var destino = this.pick(row, ["ufDestino"]) || "-";
return {
processo: this.pick(row, ["WKNumProces"]) || "-",
solicitante: solicitante,
origem: origem,
destino: destino,
dataAbertura: this.formatDate(this.pick(row, ["dataAbertura"])) || "-",
atividadeCode: activityCode || "-",
atividadeLabel: this.getActivityLabel(activityCode)
};
},
getActivityCode: function(row) {
var raw = this.pick(row, ["Activity", "activity", "WKNumState", "state", "statusAtividade"]);
var text = $.trim(String(raw || ""));
if (!text) return "";
var parsed = parseInt(text, 10);
return isNaN(parsed) ? text : String(parsed);
},
getActivityLabel: function(code) {
var map = {
"0": "Solicitacao",
"1": "Solicitacao",
"4": "Aprovacao",
"6": "Emissao NFe",
"18": "Recebimento",
"24": "Verificar Problema",
"31": "Coleta",
"39": "Cancelada",
"57": "Entrega",
"60": "Cancelada",
"99": "Consultar Entrada",
"96": "Finalizada",
"101": "Finalizada",
"104": "Problema de Lancamento"
};
return map[String(code || "")] || "Nao mapeada";
},
countByActivities: function(rows, activities) {
var set = {};
for (var i = 0; i < activities.length; i++) {
set[String(activities[i])] = true;
}
var count = 0;
for (var j = 0; j < rows.length; j++) {
var code = this.getActivityCode(rows[j]);
if (set[String(code)]) count++;
}
return count;
},
pick: function(row, keys) {
for (var i = 0; i < keys.length; i++) {
var value = row[keys[i]];
if (value !== null && value !== undefined && String(value).trim() !== "") {
return String(value).trim();
}
}
return "";
},
formatDate: function(value) {
var text = $.trim(String(value || ""));
if (!text) return "";
var iso = /^(\d{4})-(\d{2})-(\d{2})/.exec(text);
if (iso) {
return iso[3] + "/" + iso[2] + "/" + iso[1];
}
return text;
},
formatNumber: function(value) {
var n = Number(value || 0);
if (isNaN(n)) return "0";
return n.toLocaleString("pt-BR");
},
renderUpdatedAt: function() {
var now = new Date();
var stamp = now.toLocaleDateString("pt-BR") + " " + now.toLocaleTimeString("pt-BR");
this.$widget.find("[data-role='updatedAt']").text("Atualizado em: " + stamp);
},
setLoading: function(isLoading) {
this.$widget.toggleClass("is-loading", !!isLoading);
if (isLoading) {
this.setMessage("Carregando dados...", "info");
}
},
setMessage: function(text, type) {
var $msg = this.$widget.find("[data-role='message']");
$msg.removeClass("is-info is-success is-warning is-danger");
if (!text) {
$msg.hide().text("");
return;
}
var className = "is-info";
if (type === "success") className = "is-success";
if (type === "warning") className = "is-warning";
if (type === "danger") className = "is-danger";
$msg.addClass(className).text(text).show();
},
escapeHtml: function(text) {
return String(text == null ? "" : text)
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#39;");
}
});