gl aggregate table (ETL), cronjob by NODEJS
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* BatchOverlay — shared full-screen progress overlay.
|
||||
*
|
||||
* Usage:
|
||||
* BatchOverlay.show(title, total, options)
|
||||
* options: { unit: 'documents', color: '#dc3545' }
|
||||
*
|
||||
* BatchOverlay.update(done, total, currentItem)
|
||||
* Advances the bar and ETA. currentItem shown in the sub-line.
|
||||
*
|
||||
* BatchOverlay.done(message, onClose)
|
||||
* Switches to "complete" state — green checkmark + Done button.
|
||||
* onClose fires when the user dismisses.
|
||||
*
|
||||
* BatchOverlay.hide()
|
||||
* Force-hides (use for error bail-outs before done is reached).
|
||||
*/
|
||||
var BatchOverlay = (function () {
|
||||
|
||||
var _startMs = 0;
|
||||
var _onClose = null;
|
||||
var _unit = 'items';
|
||||
var _color = '#0d6efd';
|
||||
var _injected = false;
|
||||
|
||||
var _HTML = '<div id="bos-wrap" style="display:none;position:fixed;inset:0;z-index:9999;' +
|
||||
'background:rgba(0,0,0,0.55);align-items:center;justify-content:center;">' +
|
||||
'<div class="card shadow-lg p-4 text-center" style="min-width:380px;max-width:480px;width:90%;">' +
|
||||
'<div id="bos-spinner" class="spinner-border mx-auto mb-3" role="status" style="width:2.5rem;height:2.5rem;"></div>' +
|
||||
'<div id="bos-icon" class="mx-auto mb-3" style="display:none;font-size:2.5rem;color:#198754;"><i class="ti ti-circle-check"></i></div>' +
|
||||
'<div class="fw-semibold fs-6 mb-1" id="bos-title">Processing…</div>' +
|
||||
'<div class="text-muted small mb-4" id="bos-sub"></div>' +
|
||||
'<div id="bos-pct" style="font-size:3rem;font-weight:700;line-height:1;letter-spacing:-1px;">0%</div>' +
|
||||
'<div class="text-muted small mb-3" id="bos-count"></div>' +
|
||||
'<div class="progress mb-2" style="height:10px;border-radius:6px;">' +
|
||||
'<div id="bos-bar" class="progress-bar progress-bar-striped progress-bar-animated"' +
|
||||
' role="progressbar" style="width:0%;border-radius:6px;"' +
|
||||
' aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>' +
|
||||
'</div>' +
|
||||
'<div class="text-muted small" id="bos-eta"> </div>' +
|
||||
'<button id="bos-close" class="btn btn-success mt-3" style="display:none;">' +
|
||||
'<i class="ti ti-check me-1"></i>Done' +
|
||||
'</button>' +
|
||||
'</div></div>';
|
||||
|
||||
function _inject() {
|
||||
if (_injected) return;
|
||||
$('body').append(_HTML);
|
||||
$('#bos-close').on('click', function () {
|
||||
_resetState();
|
||||
$('#bos-wrap').hide();
|
||||
if (_onClose) { _onClose(); _onClose = null; }
|
||||
});
|
||||
_injected = true;
|
||||
}
|
||||
|
||||
function _resetState() {
|
||||
$('#bos-spinner').show().css('color', _color);
|
||||
$('#bos-icon').hide();
|
||||
$('#bos-pct').css('color', _color);
|
||||
$('#bos-bar')
|
||||
.addClass('progress-bar-striped progress-bar-animated')
|
||||
.removeClass('bg-success')
|
||||
.css('background-color', _color)
|
||||
.css('width', '0%').attr('aria-valuenow', 0);
|
||||
$('#bos-close').hide();
|
||||
$('#bos-eta').html(' ');
|
||||
}
|
||||
|
||||
function show(title, total, options) {
|
||||
options = options || {};
|
||||
_unit = options.unit || 'items';
|
||||
_color = options.color || '#0d6efd';
|
||||
_onClose = options.onClose || null;
|
||||
_startMs = Date.now();
|
||||
|
||||
_inject();
|
||||
_resetState();
|
||||
|
||||
$('#bos-title').text(title);
|
||||
$('#bos-sub').text('Starting…');
|
||||
$('#bos-pct').text('0%');
|
||||
$('#bos-count').text('0 / ' + total + ' ' + _unit);
|
||||
$('#bos-wrap').css('display', 'flex');
|
||||
}
|
||||
|
||||
function update(done, total, currentItem) {
|
||||
var pct = Math.round(done / total * 100);
|
||||
var elapsed = (Date.now() - _startMs) / 1000;
|
||||
var eta = ' ';
|
||||
if (done > 0) {
|
||||
var remaining = Math.round((elapsed / done) * (total - done));
|
||||
eta = remaining > 0 ? ('~' + remaining + 's remaining') : 'almost done…';
|
||||
}
|
||||
$('#bos-pct').text(pct + '%');
|
||||
$('#bos-bar').css('width', pct + '%').attr('aria-valuenow', pct);
|
||||
$('#bos-count').text(done + ' / ' + total + ' ' + _unit);
|
||||
if (currentItem !== undefined) $('#bos-sub').text('Processing ' + currentItem + '…');
|
||||
$('#bos-eta').html(eta);
|
||||
}
|
||||
|
||||
function done(message, onClose) {
|
||||
_onClose = onClose || null;
|
||||
$('#bos-spinner').hide();
|
||||
$('#bos-icon').show();
|
||||
$('#bos-pct').text('100%').css('color', '#198754');
|
||||
$('#bos-bar')
|
||||
.removeClass('progress-bar-striped progress-bar-animated')
|
||||
.css('background-color', '').addClass('bg-success')
|
||||
.css('width', '100%').attr('aria-valuenow', 100);
|
||||
$('#bos-sub').text(message || 'Complete.');
|
||||
$('#bos-eta').html(' ');
|
||||
$('#bos-close').show();
|
||||
}
|
||||
|
||||
function hide() {
|
||||
if (_injected) $('#bos-wrap').hide();
|
||||
}
|
||||
|
||||
return { show: show, update: update, done: done, hide: hide };
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user