This commit is contained in:
naielv
2025-12-25 16:40:53 +01:00
parent a9cdfb567a
commit 15df8d12fe
8 changed files with 93 additions and 28 deletions

View File

@@ -807,6 +807,7 @@ function TS_IndexElement(
}
break;
case "persona":
case "persona-nombre":
var persona = SC_Personas[value] || { Nombre: "", Region: "" };
if (field.self == true) {
persona = data || { Nombre: "", Region: "" };
@@ -885,6 +886,17 @@ function TS_IndexElement(
new_tr.appendChild(tdRaw);
break;
}
case "moneda": {
const tdMoneda = document.createElement("td");
const valor = parseFloat(data[key.key]);
if (!isNaN(valor)) {
tdMoneda.innerText = valor.toFixed(2) + " €";
} else {
tdMoneda.innerText = key.default || "";
}
new_tr.appendChild(tdMoneda);
break;
}
case "fecha":
case "fecha-iso": {
const tdFechaISO = document.createElement("td");
@@ -1098,6 +1110,39 @@ function TS_IndexElement(
new_tr.appendChild(tdPersona);
break;
}
case "persona-nombre": {
let persona =
key.self === true ? data : SC_Personas[data[key.key]] || {};
const tdPersonaNombre = document.createElement("td");
tdPersonaNombre.style.textAlign = "center";
tdPersonaNombre.style.fontSize = "20px";
tdPersonaNombre.textContent = persona.Nombre || "";
new_tr.appendChild(tdPersonaNombre);
break;
}
case "attachment-persona": {
const tdAttachment = document.createElement("td");
const img = document.createElement("img");
img.src =
data[key.key] ||
"static/ico/user_generic.png";
img.style.maxHeight = "80px";
img.style.maxWidth = "80px";
tdAttachment.appendChild(img);
new_tr.appendChild(tdAttachment);
// Prefer attachment 'foto' stored in PouchDB if available
try {
const personaId = key.self === true ? (data._key || data._id || data.id) : data[key.key];
if (personaId) {
DB.getAttachment('personas', personaId, 'foto').then((durl) => {
if (durl) img.src = durl;
}).catch(() => {});
}
} catch (e) {
// ignore
}
break;
}
default:
break;
}

View File

@@ -8,17 +8,19 @@ var DB = (function () {
let secret = null;
let remote = null;
let changes = null;
let repPush = null;
let repPull = null;
let callbacks = {}; // table -> [cb]
function ensureLocal() {
if (local) return;
try {
const localName = localStorage.getItem('TELESEC_COUCH_DBNAME') || 'telesec';
const localName = 'telesec';
local = new PouchDB(localName);
if (changes) {
try { changes.cancel(); } catch (e) {}
changes = local.changes({ live: true, since: 'now', include_docs: true }).on('change', onChange);
}
changes = local.changes({ live: true, since: 'now', include_docs: true }).on('change', onChange);
} catch (e) {
console.warn('ensureLocal error', e);
}
@@ -31,7 +33,7 @@ var DB = (function () {
function init(opts) {
// opts: { secret, remoteServer, username, password, dbname }
secret = opts.secret || '';
const localName = opts.dbname || localStorage.getItem('TELESEC_COUCH_DBNAME') || 'telesec';
const localName = 'telesec';
local = new PouchDB(localName);
if (opts.remoteServer) {
@@ -63,11 +65,24 @@ var DB = (function () {
function replicateToRemote() {
ensureLocal();
if (!local || !remote) return;
PouchDB.replicate(local, remote, { live: true, retry: true }).on('error', function (err) {
console.warn('Replication error', err);
});
PouchDB.replicate(remote, local, { live: true, retry: true }).on('error', function (err) {
console.warn('Replication error', err);
// Cancel previous replications if any
try { if (repPush && repPush.cancel) repPush.cancel(); } catch (e) {}
try { if (repPull && repPull.cancel) repPull.cancel(); } catch (e) {}
repPush = PouchDB.replicate(local, remote, { live: true, retry: true })
.on('error', function (err) {
console.warn('Replication push error', err);
});
repPull = PouchDB.replicate(remote, local, { live: true, retry: true })
.on('error', function (err) {
console.warn('Replication pull error', err);
});
}
// Retry replication when network is restored
if (typeof window !== 'undefined' && window.addEventListener) {
window.addEventListener('online', function () {
try { setTimeout(replicateToRemote, 1000); } catch (e) {}
});
}

View File

@@ -20,7 +20,6 @@
<div class="ribbon-tabs">
<div class="ribbon-tab active" data-tab="modulos">Modulos</div>
<div class="ribbon-tab" data-tab="buscar">Buscar</div>
<div class="ribbon-tab" data-tab="credenciales">Credenciales</div>
</div>
<!-- Tab: Modulos -->

View File

@@ -11,8 +11,8 @@ PAGES.login = {
container.innerHTML = `
<h1>Configuración del servidor CouchDB</h1>
<fieldset>
<label>Servidor CouchDB (ej: https://couch.example.com)
<input type="text" id="${field_couch}" value="${localStorage.getItem('TELESEC_COUCH_URL') || ''}"><br><br>
<label>Servidor CouchDB (ej: couch.example.com)
<input type="text" id="${field_couch}" value="${(localStorage.getItem('TELESEC_COUCH_URL') || '').replace(/^https?:\/\//, '')}"><br><br>
</label>
<label>Nombre de la base (opcional, por defecto usa telesec-<grupo>)
<input type="text" id="${field_couch_dbname}" value="${localStorage.getItem('TELESEC_COUCH_DBNAME') || ''}"><br><br>
@@ -32,12 +32,12 @@ PAGES.login = {
var dbname = document.getElementById(field_couch_dbname).value.trim();
var user = document.getElementById(field_couch_user).value.trim();
var pass = document.getElementById(field_couch_pass).value;
localStorage.setItem('TELESEC_COUCH_URL', url);
localStorage.setItem('TELESEC_COUCH_URL', "https://" + url);
localStorage.setItem('TELESEC_COUCH_DBNAME', dbname);
localStorage.setItem('TELESEC_COUCH_USER', user);
localStorage.setItem('TELESEC_COUCH_PASS', pass);
try {
DB.init({ secret: SECRET, remoteServer: url, username: user, password: pass, dbname: dbname || undefined });
DB.init({ secret: SECRET, remoteServer: "https://" + url, username: user, password: pass, dbname: dbname || undefined });
toastr.success('Iniciando sincronización con CouchDB');
location.hash = "#login";
location.reload();

View File

@@ -113,7 +113,7 @@ PAGES.notas = {
[
{
key: "Autor",
type: "persona",
type: "persona-nombre",
default: "",
label: "Autor",
},

View File

@@ -716,6 +716,7 @@ PAGES.pagos = {
(async () => {
const data = await DB.get('pagos', tid);
function load_data(data) {
console.log("Transaction data:", data);
document.getElementById(nameh1).innerText = tid;
document.getElementById(field_ticket).value = data.Ticket || tid;
@@ -754,7 +755,7 @@ PAGES.pagos = {
// Edit button - navigate to edit mode
document.getElementById(btn_edit).onclick = () => {
setUrlHash("pagos,edit_transaction," + key);
setUrlHash("pagos,edit_transaction," + tid);
};
// Delete button
@@ -769,7 +770,7 @@ PAGES.pagos = {
"¿Estás seguro de que quieres ELIMINAR esta transacción?\n\nEsta acción NO se puede deshacer y los cambios en los monederos NO se revertirán automáticamente.\n\nPara revertir los cambios en los monederos, usa el botón 'Revertir Transacción' en su lugar."
)
) {
DB.del('pagos', key).then(() => {
DB.del('pagos', tid).then(() => {
toastr.success("Transacción eliminada");
setTimeout(() => {
setUrlHash("pagos");
@@ -801,17 +802,17 @@ PAGES.pagos = {
if (tipo === "Ingreso") {
revertWalletBalance(personaId, "Gasto", monto, () => {
deleteTransaction(key);
deleteTransaction(tid);
});
} else if (tipo === "Gasto") {
revertWalletBalance(personaId, "Ingreso", monto, () => {
deleteTransaction(key);
deleteTransaction(tid);
});
} else if (tipo === "Transferencia") {
var destinoId = data.PersonaDestino;
revertWalletBalance(personaId, "Ingreso", monto, () => {
revertWalletBalance(destinoId, "Gasto", monto, () => {
deleteTransaction(key);
deleteTransaction(tid);
});
});
}
@@ -855,7 +856,7 @@ PAGES.pagos = {
} else {
load_data(data || {});
}
});
})();
},
// Main index view with transaction log
@@ -951,7 +952,7 @@ PAGES.pagos = {
{
key: "Persona",
label: "Monedero",
type: "persona",
type: "persona-nombre",
default: "",
},
{
@@ -1257,7 +1258,7 @@ PAGES.pagos = {
} else {
loadTransactionData(data || {});
}
});
})();
// Tipo change handler
document.getElementById(field_tipo).addEventListener("change", function() {

View File

@@ -203,11 +203,16 @@ PAGES.personas = {
`;
const config = [
{
label: "Persona",
type: "persona",
self: true,
},
// {
// label: "Persona",
// type: "persona",
// self: true,
// },
{ key: "Foto", label: "Foto", type: "attachment-persona", default: "", self: true },
{ key: "Nombre", label: "Nombre", type: "text", default: "" },
{ key: "Region", label: "Zona", type: "text", default: "" },
{ key: "Monedero_Balance", label: "Saldo Monedero", type: "moneda" },
//{ key: "markdown", label: "Notas", type: "markdown", default: "" },
//{ key: "Roles", label: "Permisos", type: "text", default: "" }
];

View File

@@ -3,7 +3,7 @@ PAGES.resumen_diario = {
icon: "static/appico/calendar.png",
navcss: "btn3",
AccessControl: true,
Title: "Hoy y mañana",
Title: "Resumen Diario",
index: function () {
var data_Comedor = safeuuid();
var data_Tareas = safeuuid();