major update
This commit is contained in:
46
.github/workflows/main.yml
vendored
46
.github/workflows/main.yml
vendored
@@ -1,46 +0,0 @@
|
||||
name: Build and publish clients
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
|
||||
jobs:
|
||||
build-windows:
|
||||
permissions:
|
||||
contents: write
|
||||
name: Build EXE
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: "Build Files"
|
||||
run: "python3 build.py 'TeleSec para Windows'"
|
||||
- name: Create Executable
|
||||
uses: sayyid5416/pyinstaller@v1
|
||||
with:
|
||||
python_ver: "3.11"
|
||||
spec: "WinApp.spec"
|
||||
requirements: "requirements.txt"
|
||||
upload_exe_with_name: "TeleSec_Windows"
|
||||
|
||||
release:
|
||||
needs:
|
||||
- build-windows
|
||||
name: Release via GHA
|
||||
runs-on: ubuntu-latest
|
||||
if: startsWith(github.ref_name, 'v')
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: TeleSec_Windows
|
||||
- uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: "TeleSec para Windows.exe"
|
||||
prerelease: true
|
||||
allowUpdates: true
|
||||
omitBodyDuringUpdate: true
|
||||
omitPrereleaseDuringUpdate: true
|
||||
2
.github/workflows/static.yml
vendored
2
.github/workflows/static.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v5
|
||||
- name: Build
|
||||
run: python3 build.py
|
||||
run: TELESEC_HOSTER=GitHub-Pages python3 build.py
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
|
||||
39
WinApp.spec
39
WinApp.spec
@@ -1,39 +0,0 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
a = Analysis(
|
||||
["main.py"],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
pyz = PYZ(a.pure)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name="TeleSec",
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon=["favicon.ico"],
|
||||
)
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"theme_color":"#23365e",
|
||||
"background_color":"#ffffff",
|
||||
"icons":[
|
||||
{"purpose":"maskable","sizes":"512x512","src":"icon512_maskable.png","type":"image/png"},
|
||||
{"purpose":"any","sizes":"512x512","src":"icon512_rounded.png","type":"image/png"}
|
||||
],
|
||||
"orientation":"portrait",
|
||||
"display":"standalone",
|
||||
"dir":"auto",
|
||||
"lang":"es-ES",
|
||||
"start_url":"index.html",
|
||||
"scope":"/",
|
||||
"description":"La app de TeleSec",
|
||||
"id":"telesec.tech.eus",
|
||||
"name": "TeleSec",
|
||||
"short_name": "TeleSec"
|
||||
}
|
||||
@@ -348,10 +348,11 @@ hr {
|
||||
align-items: center;
|
||||
padding: 0 5px;
|
||||
border-radius: 3px 3px 0 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.ribbon-tab {
|
||||
padding: 4px 15px;
|
||||
padding: 4px 9px;
|
||||
cursor: pointer;
|
||||
border-right: 1px solid #a2a9b9;
|
||||
font-size: 13px;
|
||||
@@ -367,7 +368,7 @@ hr {
|
||||
gap: 10px;
|
||||
background-color: #c8d4eb;
|
||||
border: 1px solid #a2a9b9;
|
||||
overflow-x: scroll;
|
||||
overflow-x: auto;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 185 KiB |
4
build.py
4
build.py
@@ -16,7 +16,8 @@ def get_all_files(directory):
|
||||
PREFETCH = ""
|
||||
VERSIONCO = "2025-08"
|
||||
HANDLEPARSE = get_all_files("src")
|
||||
|
||||
TITLE = os.environ.get("TELESEC_TITLE", "TeleSec")
|
||||
HOSTER = os.environ.get("TELESEC_HOSTER", "EuskadiTech")
|
||||
# Combine assets from JSON and recursively found files
|
||||
ASSETS = get_all_files("assets")
|
||||
|
||||
@@ -35,6 +36,7 @@ def replace_handles(string):
|
||||
string = string.replace("%%PREFETCH%%", PREFETCH)
|
||||
string = string.replace("%%VERSIONCO%%", VERSIONCO)
|
||||
string = string.replace("%%TITLE%%", "TeleSec")
|
||||
string = string.replace("%%HOSTER%%", HOSTER)
|
||||
string = string.replace("%%ASSETSJSON%%", json.dumps(ASSETS, ensure_ascii=False))
|
||||
return string
|
||||
|
||||
|
||||
6
main.py
6
main.py
@@ -1,6 +0,0 @@
|
||||
import webview
|
||||
import sys
|
||||
|
||||
if __name__ == '__main__':
|
||||
webview.create_window('TeleSec', url="https://telesec.tech.eus/")
|
||||
webview.start()
|
||||
@@ -1 +1 @@
|
||||
pywebview
|
||||
requests
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,14 +3,14 @@ var EventListeners = {
|
||||
Timeout: [],
|
||||
Interval: [],
|
||||
QRScanner: [],
|
||||
}
|
||||
};
|
||||
var urlParams = new URLSearchParams(location.search);
|
||||
var AC_BYPASS = false;
|
||||
if (urlParams.get("ac_bypass") == "yes") {
|
||||
AC_BYPASS = true;
|
||||
}
|
||||
if (urlParams.get("hidenav") != undefined){
|
||||
document.getElementById("header_hide_query").style.display = "none"
|
||||
if (urlParams.get("hidenav") != undefined) {
|
||||
document.getElementById("header_hide_query").style.display = "none";
|
||||
}
|
||||
var GROUPID = "";
|
||||
// const PUBLIC_KEY = "~cppGiuA4UFUPGTDoC-4r2izVC3F7MfpaCmF3iZdESN4.vntmjgbAVUpF_zfinYY6EKVFuuTYxh5xOrL4KmtdTmc"
|
||||
@@ -38,13 +38,21 @@ var SECRET = "";
|
||||
var SUB_LOGGED_IN = false;
|
||||
var SUB_LOGGED_IN_DETAILS = false;
|
||||
var SUB_LOGGED_IN_ID = false;
|
||||
var SAVE_WAIT = 500;
|
||||
var SC_Personas = {};
|
||||
var PeerConnectionInterval = 5000;
|
||||
if (urlParams.get("sublogin") != null) {
|
||||
SUB_LOGGED_IN = true;
|
||||
SUB_LOGGED_IN_ID = urlParams.get("sublogin");
|
||||
SUB_LOGGED_IN_DETAILS = true;
|
||||
setInterval(() => {
|
||||
SUB_LOGGED_IN_DETAILS = SC_Personas[SUB_LOGGED_IN_ID];
|
||||
var sli = 15;
|
||||
var slii = setInterval(() => {
|
||||
SUB_LOGGED_IN_DETAILS = SC_Personas[SUB_LOGGED_IN_ID];
|
||||
}, 7500);
|
||||
sli-=1;
|
||||
if (sli < 0) {
|
||||
clearInterval(slii);
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
function LogOutTeleSec() {
|
||||
SUB_LOGGED_IN = false;
|
||||
@@ -55,4 +63,4 @@ function LogOutTeleSec() {
|
||||
urlParams.delete("sublogin");
|
||||
history.replaceState(null, "", "?" + urlParams.toString());
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ window.rtcRoom = "telesec.tech.eus";
|
||||
var opt = {
|
||||
axe: false,
|
||||
localStorage: false,
|
||||
peers: RELAYS
|
||||
peers: RELAYS,
|
||||
// radisk: true,
|
||||
};
|
||||
|
||||
@@ -40,8 +40,10 @@ function formatPeerInfo(peer) {
|
||||
}
|
||||
|
||||
function isPeerConnected(peer) {
|
||||
return peer.wire != undefined &&
|
||||
(peer.wire.readyState == 1 || peer.wire.readyState == "open");
|
||||
return (
|
||||
peer.wire != undefined &&
|
||||
(peer.wire.readyState == 1 || peer.wire.readyState == "open")
|
||||
);
|
||||
}
|
||||
|
||||
function createPeerListElement(wireHType, wireID) {
|
||||
@@ -53,21 +55,21 @@ function createPeerListElement(wireHType, wireID) {
|
||||
function updateConnectionStatus(peerCount) {
|
||||
var statusImage = peerCount < 1 ? "connect_ko.svg" : "connect_ok.svg";
|
||||
if (window.navigator.onLine == false) {
|
||||
statusImage = "offline.svg"
|
||||
statusImage = "offline.svg";
|
||||
}
|
||||
document.getElementById("connectStatus").src = `static/ico/${statusImage}`;
|
||||
|
||||
|
||||
if (peerCount < 1) {
|
||||
if (!window.peerRetryCount) window.peerRetryCount = 0;
|
||||
window.peerRetryCount = (window.peerRetryCount + 1) % 3;
|
||||
if (window.peerRetryCount === 0) {
|
||||
gun.opt({ peers: RELAYS });
|
||||
|
||||
|
||||
// Enhanced peer connection retry
|
||||
setTimeout(() => {
|
||||
gun.opt({ peers: RELAYS });
|
||||
}, 1000);
|
||||
|
||||
|
||||
setTimeout(() => {
|
||||
gun.opt({ peers: RELAYS });
|
||||
}, 3000);
|
||||
@@ -76,9 +78,9 @@ function updateConnectionStatus(peerCount) {
|
||||
} else {
|
||||
ConnectionStarted = true;
|
||||
AtLeastThreePeers = true;
|
||||
|
||||
|
||||
// When we have good connectivity, force a data refresh
|
||||
if (typeof refreshAllData === 'function') {
|
||||
if (typeof refreshAllData === "function") {
|
||||
setTimeout(refreshAllData, 1000);
|
||||
}
|
||||
}
|
||||
@@ -88,22 +90,22 @@ function getPeers() {
|
||||
const peerCountEl = document.getElementById("peerCount");
|
||||
const peerListEl = document.getElementById("peerList");
|
||||
const list = document.createElement("ul");
|
||||
|
||||
|
||||
document.getElementById("peerPID").innerText = "PID " + gun.back("opt.pid");
|
||||
|
||||
|
||||
const connectedPeers = Object.values(gun.back("opt.peers"))
|
||||
.filter(isPeerConnected)
|
||||
.map(peer => {
|
||||
.map((peer) => {
|
||||
const { wireHType, wireID } = formatPeerInfo(peer);
|
||||
return createPeerListElement(wireHType, wireID);
|
||||
});
|
||||
|
||||
connectedPeers.forEach(el => list.append(el));
|
||||
|
||||
|
||||
connectedPeers.forEach((el) => list.append(el));
|
||||
|
||||
peerListEl.innerHTML = list.innerHTML;
|
||||
const peerCount = connectedPeers.length;
|
||||
peerCountEl.innerText = peerCount;
|
||||
|
||||
|
||||
updateConnectionStatus(peerCount);
|
||||
}
|
||||
function safeuuid(prefix = "AXLUID_") {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="manifest" href="manifest.json" />
|
||||
<title>%%TITLE%%</title>
|
||||
<link rel="icon" type="image/png" href="static/TeleSec.jpg" />
|
||||
<link rel="icon" type="image/png" href="static/logo.jpg" />
|
||||
<link href="static/euskaditech-css/simple.css" rel="stylesheet" />
|
||||
<link href="static/toastr.min.css" rel="stylesheet" />
|
||||
%%PREFETCH%%
|
||||
@@ -19,7 +19,7 @@
|
||||
<div class="ribbon-content">
|
||||
<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="buscar">Buscar</div>
|
||||
<div class="ribbon-tab" data-tab="credenciales">Credenciales</div>
|
||||
</div>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
Iniciar sesión
|
||||
</button><br>
|
||||
<b>Conectado a <span id="peerCount">?</span>
|
||||
nodos</b>
|
||||
nodos - proveedor %%HOSTER%%</b>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
@@ -86,7 +86,7 @@
|
||||
display: none;
|
||||
" />
|
||||
<div id="snackbar">
|
||||
Hay una nueva versión de TeleSec.<br /><a id="reload">Pulsa aqui para actualizar.</a>
|
||||
Hay una nueva versión de %%TITLE%%.<br /><a id="reload">Pulsa aqui para actualizar.</a>
|
||||
</div>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js" integrity="sha256-/H4YS+7aYb9kJ5OKhFYPUjSJdrtV6AeyJOtTkw6X72o=" crossorigin="anonymous"></script>
|
||||
<script src="static/showdown.min.js"></script>
|
||||
@@ -122,10 +122,10 @@
|
||||
<script src="page/resumen_diario.js"></script>
|
||||
<script src="page/personas.js"></script>
|
||||
<script src="page/supercafe.js"></script>
|
||||
<script src="page/avisos.js"></script>
|
||||
<!-- <script src="page/avisos.js"></script> -->
|
||||
<script src="page/comedor.js"></script>
|
||||
<script src="page/notas.js"></script>
|
||||
<script src="page/chat.js"></script>
|
||||
<!-- <script src="page/chat.js"></script> -->
|
||||
<script src="page/buscar.js"></script>
|
||||
<script src="page/pagos.js"></script>
|
||||
</body>
|
||||
|
||||
28
src/manifest.json
Normal file
28
src/manifest.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"theme_color": "#23365e",
|
||||
"background_color": "#ffffff",
|
||||
"icons": [
|
||||
{
|
||||
"purpose": "maskable",
|
||||
"sizes": "512x512",
|
||||
"src": "icon512_maskable.png",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"purpose": "any",
|
||||
"sizes": "512x512",
|
||||
"src": "icon512_rounded.png",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"orientation": "portrait",
|
||||
"display": "standalone",
|
||||
"dir": "auto",
|
||||
"lang": "es-ES",
|
||||
"start_url": "index.html",
|
||||
"scope": "/",
|
||||
"description": "%%TITLE%% - Comunicación Hipersegura",
|
||||
"id": "telesec.tech.eus",
|
||||
"name": "%%TITLE%%",
|
||||
"short_name": "%%TITLE%%"
|
||||
}
|
||||
@@ -230,7 +230,7 @@ PAGES.aulas = {
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("aulas,solicitudes");
|
||||
}, 750);
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
};
|
||||
document.getElementById(btn_borrar).onclick = () => {
|
||||
@@ -239,7 +239,7 @@ PAGES.aulas = {
|
||||
toastr.error("Borrado!");
|
||||
setTimeout(() => {
|
||||
setUrlHash("aulas,solicitudes");
|
||||
}, 750);
|
||||
}, SAVE_WAIT);
|
||||
}
|
||||
};
|
||||
},
|
||||
@@ -310,27 +310,27 @@ PAGES.aulas = {
|
||||
title = "Diario " + date[2] + "/" + date[1] + "/" + date[0];
|
||||
}
|
||||
container.innerHTML = `
|
||||
<a class="button" href="#aulas,informes">← Volver a informes</a>
|
||||
<h1>Informe <code id="${nameh1}"></code></h1>
|
||||
<fieldset style="float: none; width: calc(100% - 40px);max-width: none;">
|
||||
<legend>Valores</legend>
|
||||
<div style="max-width: 400px;">
|
||||
<label>
|
||||
Asunto<br>
|
||||
<input type="text" id="${field_asunto}" value=""><br><br>
|
||||
</label>
|
||||
<input type="hidden" id="${field_autor}" readonly value="">
|
||||
<input type="hidden" id="${field_fecha}" value="">
|
||||
</div>
|
||||
<a class="button" href="#aulas,informes">← Volver a informes</a>
|
||||
<h1>Informe <code id="${nameh1}"></code></h1>
|
||||
<fieldset style="float: none; width: calc(100% - 40px);max-width: none;">
|
||||
<legend>Valores</legend>
|
||||
<div style="max-width: 400px;">
|
||||
<label>
|
||||
Contenido<br>
|
||||
<textarea id="${field_contenido}" style="width: 100%; height: 400px;"></textarea><br><br>
|
||||
Asunto<br>
|
||||
<input type="text" id="${field_asunto}" value=""><br><br>
|
||||
</label>
|
||||
<hr>
|
||||
<button class="btn5" id="${btn_guardar}">Guardar</button>
|
||||
<button class="rojo" id="${btn_borrar}">Borrar</button>
|
||||
</fieldset>
|
||||
`;
|
||||
<input type="hidden" id="${field_autor}" readonly value="">
|
||||
<input type="hidden" id="${field_fecha}" value="">
|
||||
</div>
|
||||
<label>
|
||||
Contenido<br>
|
||||
<textarea id="${field_contenido}" style="width: 100%; height: 400px;"></textarea><br><br>
|
||||
</label>
|
||||
<hr>
|
||||
<button class="btn5" id="${btn_guardar}">Guardar</button>
|
||||
<button class="rojo" id="${btn_borrar}">Borrar</button>
|
||||
</fieldset>
|
||||
`;
|
||||
gun
|
||||
.get(TABLE)
|
||||
.get("aulas_informes")
|
||||
@@ -366,7 +366,7 @@ PAGES.aulas = {
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("aulas,informes");
|
||||
}, 750);
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
};
|
||||
document.getElementById(btn_borrar).onclick = () => {
|
||||
@@ -375,7 +375,7 @@ PAGES.aulas = {
|
||||
toastr.error("Borrado!");
|
||||
setTimeout(() => {
|
||||
setUrlHash("aulas,informes");
|
||||
}, 750);
|
||||
}, SAVE_WAIT);
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
@@ -4,7 +4,6 @@ PAGES.avisos = {
|
||||
navcss: "btn5",
|
||||
icon: "static/appico/File_Plugin.svg",
|
||||
AccessControl: true,
|
||||
Esconder: true,
|
||||
Title: "Avisos",
|
||||
edit: function (mid) {
|
||||
if (!checkRole("avisos:edit")) {setUrlHash("avisos");return}
|
||||
@@ -22,40 +21,40 @@ PAGES.avisos = {
|
||||
var btn_borrar = safeuuid();
|
||||
var div_actions = safeuuid();
|
||||
container.innerHTML = `
|
||||
<h1>Aviso <code id="${nameh1}"></code></h1>
|
||||
<fieldset style="float: left;">
|
||||
<legend>Valores</legend>
|
||||
<label>
|
||||
Fecha<br>
|
||||
<input readonly disabled type="text" id="${field_fecha}" value=""><br><br>
|
||||
</label>
|
||||
<label>
|
||||
Asunto<br>
|
||||
<input type="text" id="${field_asunto}" value=""><br><br>
|
||||
</label>
|
||||
<input type="hidden" id="${field_origen}">
|
||||
<input type="hidden" id="${field_destino}">
|
||||
<div id="${div_actions}"></div>
|
||||
<label>
|
||||
Mensaje<br>
|
||||
<textarea id="${field_mensaje}"></textarea><br><br>
|
||||
</label>
|
||||
<label>
|
||||
Respuesta<br>
|
||||
<textarea id="${field_respuesta}"></textarea><br><br>
|
||||
</label>
|
||||
<label>
|
||||
Estado<br>
|
||||
<input readonly disabled type="text" id="${field_estado}" value="">
|
||||
<br>
|
||||
<button id="${btn_leer}">Leido</button>
|
||||
<button id="${btn_desleer}">No leido</button>
|
||||
<br>
|
||||
</label><hr>
|
||||
<button class="btn5" id="${btn_guardar}">Guardar</button>
|
||||
<button class="rojo" id="${btn_borrar}">Borrar</button>
|
||||
</fieldset>
|
||||
`;
|
||||
<h1>Aviso <code id="${nameh1}"></code></h1>
|
||||
<fieldset style="float: left;">
|
||||
<legend>Valores</legend>
|
||||
<label>
|
||||
Fecha<br>
|
||||
<input readonly disabled type="text" id="${field_fecha}" value=""><br><br>
|
||||
</label>
|
||||
<label>
|
||||
Asunto<br>
|
||||
<input type="text" id="${field_asunto}" value=""><br><br>
|
||||
</label>
|
||||
<input type="hidden" id="${field_origen}">
|
||||
<input type="hidden" id="${field_destino}">
|
||||
<div id="${div_actions}"></div>
|
||||
<label>
|
||||
Mensaje<br>
|
||||
<textarea id="${field_mensaje}"></textarea><br><br>
|
||||
</label>
|
||||
<label>
|
||||
Respuesta<br>
|
||||
<textarea id="${field_respuesta}"></textarea><br><br>
|
||||
</label>
|
||||
<label>
|
||||
Estado<br>
|
||||
<input readonly disabled type="text" id="${field_estado}" value="">
|
||||
<br>
|
||||
<button id="${btn_leer}">Leido</button>
|
||||
<button id="${btn_desleer}">No leido</button>
|
||||
<br>
|
||||
</label><hr>
|
||||
<button class="btn5" id="${btn_guardar}">Guardar</button>
|
||||
<button class="rojo" id="${btn_borrar}">Borrar</button>
|
||||
</fieldset>
|
||||
`;
|
||||
document.getElementById(btn_leer).onclick = () => {
|
||||
document.getElementById(field_estado).value = "leido";
|
||||
};
|
||||
@@ -158,7 +157,7 @@ PAGES.avisos = {
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("avisos");
|
||||
}, 750);
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
};
|
||||
document.getElementById(btn_borrar).onclick = () => {
|
||||
@@ -167,7 +166,7 @@ PAGES.avisos = {
|
||||
toastr.error("Borrado!");
|
||||
setTimeout(() => {
|
||||
setUrlHash("avisos");
|
||||
}, 750);
|
||||
}, SAVE_WAIT);
|
||||
}
|
||||
};
|
||||
},
|
||||
@@ -176,10 +175,10 @@ PAGES.avisos = {
|
||||
const tablebody = safeuuid();
|
||||
var btn_new = safeuuid();
|
||||
container.innerHTML = `
|
||||
<h1>Avisos</h1>
|
||||
<button id="${btn_new}">Nuevo aviso</button>
|
||||
<div id="cont"></div>
|
||||
`;
|
||||
<h1>Avisos</h1>
|
||||
<button id="${btn_new}">Nuevo aviso</button>
|
||||
<div id="cont"></div>
|
||||
`;
|
||||
TS_IndexElement(
|
||||
"avisos",
|
||||
[
|
||||
|
||||
@@ -4,14 +4,14 @@ PAGES.buscar = {
|
||||
Title: "Buscar",
|
||||
AccessControl: true,
|
||||
Esconder: true,
|
||||
|
||||
index: function() {
|
||||
|
||||
index: function () {
|
||||
const searchInput = safeuuid();
|
||||
const resultsContainer = safeuuid();
|
||||
const searchButton = safeuuid();
|
||||
const recentSearches = safeuuid();
|
||||
const moduleFilter = safeuuid();
|
||||
|
||||
|
||||
container.innerHTML = `
|
||||
<h1>🔍 Búsqueda Global</h1>
|
||||
<p>Busca en todos los módulos: personas, materiales, café, comedor, notas y avisos</p>
|
||||
@@ -51,60 +51,66 @@ PAGES.buscar = {
|
||||
</fieldset>
|
||||
</div>
|
||||
`;
|
||||
|
||||
|
||||
// Initialize global search
|
||||
const globalSearch = GlobalSearch();
|
||||
globalSearch.loadAllData();
|
||||
|
||||
|
||||
// Get accessible modules for the current user
|
||||
const accessibleModules = globalSearch.getAccessibleModules();
|
||||
|
||||
|
||||
const searchInputEl = document.getElementById(searchInput);
|
||||
const resultsEl = document.getElementById(resultsContainer);
|
||||
const searchButtonEl = document.getElementById(searchButton);
|
||||
const recentSearchesEl = document.getElementById(recentSearches);
|
||||
const moduleFilterEl = document.getElementById(moduleFilter);
|
||||
|
||||
|
||||
// Populate module filter dropdown with only accessible modules
|
||||
function populateModuleFilter() {
|
||||
// Clear existing options except "Todos los módulos"
|
||||
moduleFilterEl.innerHTML = '<option value="">Todos los módulos</option>';
|
||||
|
||||
|
||||
// Add only accessible modules
|
||||
accessibleModules.forEach(module => {
|
||||
const option = document.createElement('option');
|
||||
accessibleModules.forEach((module) => {
|
||||
const option = document.createElement("option");
|
||||
option.value = module.key;
|
||||
option.textContent = `${getModuleIcon(module.key)} ${module.title}`;
|
||||
moduleFilterEl.appendChild(option);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Helper function to get module icons (fallback for older module mappings)
|
||||
function getModuleIcon(moduleKey) {
|
||||
const iconMap = {
|
||||
'personas': '👤',
|
||||
'materiales': '📦',
|
||||
'supercafe': '☕',
|
||||
'comedor': '🍽️',
|
||||
'avisos': '🔔',
|
||||
'aulas': '🏫',
|
||||
'resumen_diario': '📊'
|
||||
personas: "👤",
|
||||
materiales: "📦",
|
||||
supercafe: "☕",
|
||||
comedor: "🍽️",
|
||||
avisos: "🔔",
|
||||
aulas: "🏫",
|
||||
resumen_diario: "📊",
|
||||
};
|
||||
return iconMap[moduleKey] || '📋';
|
||||
return iconMap[moduleKey] || "📋";
|
||||
}
|
||||
|
||||
|
||||
// Load recent searches from localStorage
|
||||
function loadRecentSearches() {
|
||||
const recent = JSON.parse(localStorage.getItem('telesec_recent_searches') || '[]');
|
||||
const recent = JSON.parse(
|
||||
localStorage.getItem("telesec_recent_searches") || "[]"
|
||||
);
|
||||
if (recent.length > 0) {
|
||||
recentSearchesEl.innerHTML = `
|
||||
<fieldset>
|
||||
<legend>Búsquedas recientes</legend>
|
||||
${recent.map(term => `
|
||||
${recent
|
||||
.map(
|
||||
(term) => `
|
||||
<button onclick="document.getElementById('${searchInput}').value='${term}'; document.getElementById('${searchButton}').click();" class="btn4">
|
||||
${term}
|
||||
</button>
|
||||
`).join('')}
|
||||
`
|
||||
)
|
||||
.join("")}
|
||||
<button onclick="localStorage.removeItem('telesec_recent_searches'); this.parentElement.style.display='none';" class="rojo">
|
||||
Limpiar
|
||||
</button>
|
||||
@@ -112,28 +118,30 @@ PAGES.buscar = {
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Populate the module filter dropdown
|
||||
populateModuleFilter();
|
||||
|
||||
|
||||
// Save search term to recent searches
|
||||
function saveToRecent(term) {
|
||||
if (!term || term.length < 2) return;
|
||||
|
||||
let recent = JSON.parse(localStorage.getItem('telesec_recent_searches') || '[]');
|
||||
recent = recent.filter(t => t !== term); // Remove if exists
|
||||
|
||||
let recent = JSON.parse(
|
||||
localStorage.getItem("telesec_recent_searches") || "[]"
|
||||
);
|
||||
recent = recent.filter((t) => t !== term); // Remove if exists
|
||||
recent.unshift(term); // Add to beginning
|
||||
recent = recent.slice(0, 5); // Keep only 5 most recent
|
||||
|
||||
localStorage.setItem('telesec_recent_searches', JSON.stringify(recent));
|
||||
|
||||
localStorage.setItem("telesec_recent_searches", JSON.stringify(recent));
|
||||
loadRecentSearches();
|
||||
}
|
||||
|
||||
|
||||
// Perform search
|
||||
function performSearch() {
|
||||
const searchTerm = searchInputEl.value.trim();
|
||||
const selectedModule = moduleFilterEl.value;
|
||||
|
||||
|
||||
if (searchTerm.length < 2) {
|
||||
resultsEl.innerHTML = `
|
||||
<fieldset>
|
||||
@@ -143,7 +151,7 @@ PAGES.buscar = {
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Show loading
|
||||
resultsEl.innerHTML = `
|
||||
<fieldset>
|
||||
@@ -151,46 +159,50 @@ PAGES.buscar = {
|
||||
<div>⏳ Procesando búsqueda...</div>
|
||||
</fieldset>
|
||||
`;
|
||||
|
||||
|
||||
// Add small delay to show loading state
|
||||
setTimeout(() => {
|
||||
let results = globalSearch.performSearch(searchTerm);
|
||||
|
||||
|
||||
// Filter by module if selected
|
||||
if (selectedModule) {
|
||||
results = results.filter(result => result._module === selectedModule);
|
||||
results = results.filter(
|
||||
(result) => result._module === selectedModule
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
globalSearch.renderResults(results, resultsEl);
|
||||
saveToRecent(searchTerm);
|
||||
|
||||
|
||||
// Add stats
|
||||
if (results.length > 0) {
|
||||
const statsDiv = document.createElement('fieldset');
|
||||
const legend = document.createElement('legend');
|
||||
legend.textContent = 'Estadísticas';
|
||||
const statsDiv = document.createElement("fieldset");
|
||||
const legend = document.createElement("legend");
|
||||
legend.textContent = "Estadísticas";
|
||||
statsDiv.appendChild(legend);
|
||||
|
||||
let filterText = selectedModule ? ` en ${moduleFilterEl.options[moduleFilterEl.selectedIndex].text}` : '';
|
||||
const content = document.createElement('div');
|
||||
|
||||
let filterText = selectedModule
|
||||
? ` en ${moduleFilterEl.options[moduleFilterEl.selectedIndex].text}`
|
||||
: "";
|
||||
const content = document.createElement("div");
|
||||
content.innerHTML = `📊 Se encontraron <strong>${results.length}</strong> resultados para "<strong>${searchTerm}</strong>"${filterText}`;
|
||||
statsDiv.appendChild(content);
|
||||
|
||||
|
||||
resultsEl.insertBefore(statsDiv, resultsEl.firstChild);
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
|
||||
// Event listeners
|
||||
searchButtonEl.onclick = performSearch;
|
||||
|
||||
|
||||
// Filter change listener
|
||||
moduleFilterEl.onchange = () => {
|
||||
if (searchInputEl.value.trim().length >= 2) {
|
||||
performSearch();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Auto-search as user types (with debounce)
|
||||
let searchTimeout;
|
||||
searchInputEl.oninput = () => {
|
||||
@@ -201,22 +213,22 @@ PAGES.buscar = {
|
||||
}
|
||||
}, 1501);
|
||||
};
|
||||
|
||||
|
||||
// Focus on search input
|
||||
searchInputEl.focus();
|
||||
|
||||
|
||||
// Add keyboard shortcuts
|
||||
document.addEventListener('keydown', function(e) {
|
||||
document.addEventListener("keydown", function (e) {
|
||||
// Ctrl+F or Cmd+F to focus search
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'f') {
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === "f") {
|
||||
e.preventDefault();
|
||||
searchInputEl.focus();
|
||||
searchInputEl.select();
|
||||
}
|
||||
|
||||
|
||||
// Escape to clear search
|
||||
if (e.key === 'Escape') {
|
||||
searchInputEl.value = '';
|
||||
if (e.key === "Escape") {
|
||||
searchInputEl.value = "";
|
||||
searchInputEl.focus();
|
||||
resultsEl.innerHTML = `
|
||||
<fieldset>
|
||||
@@ -238,17 +250,17 @@ PAGES.buscar = {
|
||||
`;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Check for quick search term from header
|
||||
const quickSearchTerm = sessionStorage.getItem('telesec_quick_search');
|
||||
const quickSearchTerm = sessionStorage.getItem("telesec_quick_search");
|
||||
if (quickSearchTerm) {
|
||||
searchInputEl.value = quickSearchTerm;
|
||||
sessionStorage.removeItem('telesec_quick_search');
|
||||
sessionStorage.removeItem("telesec_quick_search");
|
||||
// Perform search automatically
|
||||
setTimeout(performSearch, 100);
|
||||
}
|
||||
|
||||
|
||||
// Load recent searches
|
||||
loadRecentSearches();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -15,17 +15,17 @@ PAGES.comedor = {
|
||||
container.innerHTML = `
|
||||
<h1>Entrada del menú <code id="${nameh1}"></code></h1>
|
||||
<fieldset style="float: left;">
|
||||
<legend>Valores</legend>
|
||||
<label>
|
||||
Fecha<br>
|
||||
<input type="date" id="${field_fecha}" value=""><br><br>
|
||||
</label>
|
||||
<label>
|
||||
Platos<br>
|
||||
<textarea id="${field_platos}"></textarea><br><br>
|
||||
</label>
|
||||
<button class="btn5" id="${btn_guardar}">Guardar</button>
|
||||
<button class="rojo" id="${btn_borrar}">Borrar</button>
|
||||
<legend>Valores</legend>
|
||||
<label>
|
||||
Fecha<br>
|
||||
<input type="date" id="${field_fecha}" value=""><br><br>
|
||||
</label>
|
||||
<label>
|
||||
Platos<br>
|
||||
<textarea id="${field_platos}"></textarea><br><br>
|
||||
</label>
|
||||
<button class="btn5" id="${btn_guardar}">Guardar</button>
|
||||
<button class="rojo" id="${btn_borrar}">Borrar</button>
|
||||
</fieldset>
|
||||
`;
|
||||
gun
|
||||
@@ -66,7 +66,7 @@ PAGES.comedor = {
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("comedor");
|
||||
}, 750);
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
};
|
||||
document.getElementById(btn_borrar).onclick = () => {
|
||||
@@ -75,19 +75,19 @@ PAGES.comedor = {
|
||||
toastr.error("Borrado!");
|
||||
setTimeout(() => {
|
||||
setUrlHash("comedor");
|
||||
}, 750);
|
||||
}, SAVE_WAIT);
|
||||
}
|
||||
};
|
||||
},
|
||||
index: function () {
|
||||
if (!checkRole("comedor")) {setUrlHash("index");return}
|
||||
const tablebody = safeuuid();
|
||||
const cont = safeuuid();
|
||||
var btn_new = safeuuid();
|
||||
container.innerHTML = `
|
||||
<h1>Menú del comedor</h1>
|
||||
<button id="${btn_new}">Nueva entrada</button>
|
||||
<div id="cont"></div>
|
||||
`;
|
||||
<h1>Menú del comedor</h1>
|
||||
<button id="${btn_new}">Nueva entrada</button>
|
||||
<div id="${cont}"></div>
|
||||
`;
|
||||
TS_IndexElement(
|
||||
"comedor",
|
||||
[
|
||||
@@ -105,7 +105,7 @@ PAGES.comedor = {
|
||||
}
|
||||
],
|
||||
gun.get(TABLE).get("comedor"),
|
||||
document.querySelector("#cont"),
|
||||
document.getElementById(cont),
|
||||
(data, new_tr) => {
|
||||
// new_tr.style.backgroundColor = "#FFCCCB";
|
||||
if (data.Fecha == CurrentISODate()) {
|
||||
|
||||
@@ -52,16 +52,16 @@ PAGES.dataman = {
|
||||
container.innerHTML = `
|
||||
<h1>Exportar Datos</h1>
|
||||
<fieldset>
|
||||
<legend>Exportar datos</legend>
|
||||
<em>Al pulsar, Espera hasta que salga una notificacion verde.</em>
|
||||
<br>
|
||||
<br>
|
||||
<button id="${button_export_local}" type="button">Exportar sin cifrar</button>
|
||||
<button id="${button_export_safe}" type="button">Exportar con cifrado</button>
|
||||
<button id="${button_export_safe_cloud}" style="display: none;" type="button">Exportar a EuskadiTech - cifrado</button>
|
||||
<!--<br><br><em>Para descargar envia un correo a telesec@tech.eus con el asunto "TSBK %${GROUPID}".</em>-->
|
||||
<legend>Exportar datos</legend>
|
||||
<em>Al pulsar, Espera hasta que salga una notificacion verde.</em>
|
||||
<br>
|
||||
<br>
|
||||
<button id="${button_export_local}" type="button">Exportar sin cifrar</button>
|
||||
<button id="${button_export_safe}" type="button">Exportar con cifrado</button>
|
||||
<button id="${button_export_safe_cloud}" style="display: none;" type="button">Exportar a EuskadiTech - cifrado</button>
|
||||
<!--<br><br><em>Para descargar envia un correo a telesec@tech.eus con el asunto "TSBK %${GROUPID}".</em>-->
|
||||
</fieldset>
|
||||
`;
|
||||
`;
|
||||
document.getElementById(button_export_local).onclick = () => {
|
||||
var data_export = {};
|
||||
var output = {
|
||||
@@ -85,7 +85,7 @@ PAGES.dataman = {
|
||||
});
|
||||
toastr.success("Exportado todo, descargando!");
|
||||
download(
|
||||
`Export TeleSec ${GROUPID}.json.txt`,
|
||||
`Export %%TITLE%% ${GROUPID}.json.txt`,
|
||||
JSON.stringify(output)
|
||||
);
|
||||
//setUrlHash(sel);
|
||||
@@ -97,32 +97,32 @@ PAGES.dataman = {
|
||||
var download_data = (DATA) => {
|
||||
toastr.success("Exportado todo, descargado!");
|
||||
download(
|
||||
`Export TeleSec Encriptado ${GROUPID}.json.txt`,
|
||||
`Export %%TITLE%% Encriptado ${GROUPID}.json.txt`,
|
||||
JSON.stringify(DATA)
|
||||
);
|
||||
//setUrlHash(sel);
|
||||
};
|
||||
gun.get(TABLE).load(download_data);
|
||||
};
|
||||
document.getElementById(button_export_safe_cloud).onclick = () => {
|
||||
var download_data = (DATA) => {
|
||||
toastr.info("Exportado todo, subiendo!");
|
||||
fetch(
|
||||
"https://telesec-sync.tech.eus/upload_backup.php?table=" + GROUPID,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify(DATA),
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
toastr.success("Subido correctamente!");
|
||||
})
|
||||
.catch(() => {
|
||||
toastr.error("Ha ocurrido un error en la subida.");
|
||||
});
|
||||
};
|
||||
gun.get(TABLE).load(download_data);
|
||||
};
|
||||
// document.getElementById(button_export_safe_cloud).onclick = () => {
|
||||
// var download_data = (DATA) => {
|
||||
// toastr.info("Exportado todo, subiendo!");
|
||||
// fetch(
|
||||
// "https://telesec-sync.tech.eus/upload_backup.php?table=" + GROUPID,
|
||||
// {
|
||||
// method: "POST",
|
||||
// body: JSON.stringify(DATA),
|
||||
// }
|
||||
// )
|
||||
// .then(() => {
|
||||
// toastr.success("Subido correctamente!");
|
||||
// })
|
||||
// .catch(() => {
|
||||
// toastr.error("Ha ocurrido un error en la subida.");
|
||||
// });
|
||||
// };
|
||||
// gun.get(TABLE).load(download_data);
|
||||
// };
|
||||
},
|
||||
__import: function () {
|
||||
var select_type = safeuuid();
|
||||
|
||||
@@ -4,10 +4,11 @@ PAGES.index = {
|
||||
index: function() {
|
||||
container.innerHTML = `
|
||||
<h1>¡Hola, ${SUB_LOGGED_IN_DETAILS.Nombre}!<br>Bienvenidx a %%TITLE%%</h1>
|
||||
<h2>Tienes ${parseFloat(SUB_LOGGED_IN_DETAILS.Monedero_Balance).toString()} € en el monedero.</h2>
|
||||
<em>Utiliza el menú superior para abrir un modulo</em>
|
||||
<br><br>
|
||||
<button class="btn1" onclick="LogOutTeleSec()">Cerrar sesión</button>
|
||||
`;
|
||||
`;
|
||||
},
|
||||
edit: function(mid) {
|
||||
switch (mid) {
|
||||
|
||||
@@ -15,16 +15,16 @@ PAGES.login = {
|
||||
var btn_reload = safeuuid();
|
||||
var div_actions = safeuuid();
|
||||
container.innerHTML = `
|
||||
<h1>Iniciar sesión</h1>
|
||||
<fieldset>
|
||||
<legend>Valores</legend>
|
||||
<input type="hidden" id="${field_persona}">
|
||||
<div id="${div_actions}"></div>
|
||||
<button class="btn5" id="${btn_guardar}">Acceder</button>
|
||||
<button class="btn1" id="${btn_reload}">Recargar lista</button>
|
||||
</fieldset>
|
||||
<a href="#login,setup">Empezar desde cero</a>
|
||||
`;
|
||||
<h1>Iniciar sesión</h1>
|
||||
<fieldset>
|
||||
<legend>Valores</legend>
|
||||
<input type="hidden" id="${field_persona}">
|
||||
<div id="${div_actions}"></div>
|
||||
<button class="btn5" id="${btn_guardar}">Acceder</button>
|
||||
<button class="btn1" id="${btn_reload}">Recargar lista</button>
|
||||
</fieldset>
|
||||
<a href="#login,setup">Empezar desde cero</a>
|
||||
`;
|
||||
var divact = document.getElementById(div_actions);
|
||||
addCategory_Personas(
|
||||
divact,
|
||||
|
||||
@@ -12,7 +12,6 @@ PAGES.materiales = {
|
||||
var field_cantidad = safeuuid();
|
||||
var field_unidad = safeuuid();
|
||||
var field_cantidad_min = safeuuid();
|
||||
var field_abierto = safeuuid();
|
||||
var field_ubicacion = safeuuid();
|
||||
var field_referencia = safeuuid();
|
||||
var field_notas = safeuuid();
|
||||
@@ -98,7 +97,7 @@ PAGES.materiales = {
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("materiales");
|
||||
}, 750);
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
};
|
||||
document.getElementById(btn_borrar).onclick = () => {
|
||||
@@ -107,7 +106,7 @@ PAGES.materiales = {
|
||||
toastr.error("Borrado!");
|
||||
setTimeout(() => {
|
||||
setUrlHash("materiales");
|
||||
}, 750);
|
||||
}, SAVE_WAIT);
|
||||
}
|
||||
};
|
||||
},
|
||||
@@ -115,6 +114,7 @@ PAGES.materiales = {
|
||||
if (!checkRole("materiales")) {setUrlHash("index");return}
|
||||
var btn_new = safeuuid();
|
||||
var select_ubicacion = safeuuid();
|
||||
var tableContainer = safeuuid();
|
||||
container.innerHTML = `
|
||||
<h1>Materiales</h1>
|
||||
<label>Filtrar por ubicación:
|
||||
@@ -123,7 +123,7 @@ PAGES.materiales = {
|
||||
</select>
|
||||
</label>
|
||||
<button id="${btn_new}">Nuevo Material</button>
|
||||
<div id="tableContainer"></div>
|
||||
<div id="${tableContainer}"></div>
|
||||
`;
|
||||
|
||||
const config = [
|
||||
@@ -190,7 +190,7 @@ PAGES.materiales = {
|
||||
"materiales",
|
||||
config,
|
||||
gun.get(TABLE).get("materiales"),
|
||||
document.getElementById("tableContainer"),
|
||||
document.getElementById(tableContainer),
|
||||
function(data, new_tr) {
|
||||
if (parseFloat(data.Cantidad) < parseFloat(data.Cantidad_Minima)) {
|
||||
new_tr.style.background = "lightcoral"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
PERMS["notas"] = "Notas"
|
||||
PERMS["notas"] = "Noticias"
|
||||
PERMS["notas:edit"] = "> Editar"
|
||||
PAGES.notas = {
|
||||
navcss: "btn5",
|
||||
icon: "static/appico/Notepad.svg",
|
||||
icon: "static/appico/Newspaper.svg",
|
||||
AccessControl: true,
|
||||
Title: "Notas",
|
||||
Title: "Noticias",
|
||||
edit: function (mid) {
|
||||
if (!checkRole("notas:edit")) {setUrlHash("notas");return}
|
||||
var nameh1 = safeuuid();
|
||||
@@ -15,7 +15,7 @@ PAGES.notas = {
|
||||
var btn_borrar = safeuuid();
|
||||
var div_actions = safeuuid();
|
||||
container.innerHTML = `
|
||||
<h1>Nota <code id="${nameh1}"></code></h1>
|
||||
<h1>Noticia <code id="${nameh1}"></code></h1>
|
||||
<fieldset style="float: none; width: calc(100% - 40px);max-width: none;">
|
||||
<legend>Valores</legend>
|
||||
<div style="max-width: 400px;">
|
||||
@@ -28,7 +28,7 @@ PAGES.notas = {
|
||||
</div>
|
||||
<label>
|
||||
Contenido<br>
|
||||
<textarea id="${field_contenido}" style="width: 100%; height: 400px;"></textarea><br><br>
|
||||
<textarea id="${field_contenido}" style="width: calc(100% - 15px); height: 400px;"></textarea><br><br>
|
||||
</label>
|
||||
<hr>
|
||||
<button class="btn5" id="${btn_guardar}">Guardar</button>
|
||||
@@ -62,7 +62,7 @@ PAGES.notas = {
|
||||
addCategory_Personas(
|
||||
divact,
|
||||
SC_Personas,
|
||||
data["Autor"] || "",
|
||||
data["Autor"] || SUB_LOGGED_IN_ID || "",
|
||||
(value) => {
|
||||
document.getElementById(field_autor).value = value;
|
||||
},
|
||||
@@ -93,7 +93,7 @@ PAGES.notas = {
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("notas");
|
||||
}, 750);
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
};
|
||||
document.getElementById(btn_borrar).onclick = () => {
|
||||
@@ -102,7 +102,7 @@ PAGES.notas = {
|
||||
toastr.error("Borrado!");
|
||||
setTimeout(() => {
|
||||
setUrlHash("notas");
|
||||
}, 750);
|
||||
}, SAVE_WAIT);
|
||||
}
|
||||
};
|
||||
},
|
||||
@@ -111,8 +111,8 @@ PAGES.notas = {
|
||||
const tablebody = safeuuid();
|
||||
var btn_new = safeuuid();
|
||||
container.innerHTML = `
|
||||
<h1>Notas</h1>
|
||||
<button id="${btn_new}">Nueva nota</button>
|
||||
<h1>Noticias</h1>
|
||||
<button id="${btn_new}">Nueva noticia</button>
|
||||
<div id="cont"></div>
|
||||
`;
|
||||
TS_IndexElement(
|
||||
|
||||
@@ -51,7 +51,7 @@ PAGES.pagos = {
|
||||
container.innerHTML = `
|
||||
<div style="max-width: 600px; margin: 0 auto; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 20px; border-radius: 15px; box-shadow: 0 10px 30px rgba(0,0,0,0.3);">
|
||||
<h1 style="color: white; text-align: center; margin-bottom: 20px;">
|
||||
Terminal de pago TeleSec
|
||||
Terminal de pago %%TITLE%%
|
||||
</h1>
|
||||
|
||||
<div style="margin: 0 auto;max-width: 435px;background: white;padding: 20px;border-radius: 10px;margin-bottom: 20px;">
|
||||
@@ -268,6 +268,19 @@ PAGES.pagos = {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check if persona has enough balance for Gasto or Transferencia
|
||||
if (tipo === 'Gasto' || tipo === 'Transferencia') {
|
||||
if (metodo == "Tarjeta") {
|
||||
var persona = SC_Personas[personaId];
|
||||
var currentBalance = parseFloat(persona.Monedero_Balance || 0);
|
||||
if (currentBalance < monto) {
|
||||
if (!confirm(`Saldo insuficiente (${currentBalance.toFixed(2)}€). ¿Continuar de todos modos?`)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Move to step 3 - confirmation
|
||||
document.getElementById('step2').style.display = 'none';
|
||||
document.getElementById('step3').style.display = 'block';
|
||||
@@ -393,19 +406,6 @@ PAGES.pagos = {
|
||||
}
|
||||
}
|
||||
|
||||
// Check if persona has enough balance for Gasto or Transferencia
|
||||
if (tipo === 'Gasto' || tipo === 'Transferencia') {
|
||||
if (metodo == "Tarjeta") {
|
||||
var persona = SC_Personas[personaId];
|
||||
var currentBalance = parseFloat(persona.Monedero_Balance || 0);
|
||||
if (currentBalance < monto) {
|
||||
if (!confirm(`Saldo insuficiente (${currentBalance.toFixed(2)}€). ¿Continuar de todos modos?`)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create transaction
|
||||
var ticketId = safeuuid("");
|
||||
var transactionData = {
|
||||
@@ -498,7 +498,7 @@ PAGES.pagos = {
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("pagos," + ticketId);
|
||||
}, 750);
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1337,7 +1337,7 @@ PAGES.pagos = {
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("pagos," + transactionId);
|
||||
}, 750);
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
PERMS["personas"] = "Personas"
|
||||
PERMS["personas:edit"] = "> Editar"
|
||||
PERMS["personas"] = "Personas";
|
||||
PERMS["personas:edit"] = "> Editar";
|
||||
PAGES.personas = {
|
||||
navcss: "btn3",
|
||||
icon: "static/appico/File_Person.svg",
|
||||
AccessControl: true,
|
||||
Title: "Personas",
|
||||
edit: function (mid) {
|
||||
if (!checkRole("personas:edit")) {setUrlHash("personas");return}
|
||||
if (!checkRole("personas:edit")) {
|
||||
setUrlHash("personas");
|
||||
return;
|
||||
}
|
||||
var nameh1 = safeuuid();
|
||||
var permisosdet = safeuuid();
|
||||
var field_nombre = safeuuid();
|
||||
@@ -21,59 +24,68 @@ PAGES.personas = {
|
||||
var btn_borrar = safeuuid();
|
||||
var btn_ver_monedero = safeuuid();
|
||||
container.innerHTML = `
|
||||
<h1>Persona <code id="${nameh1}"></code></h1>
|
||||
${BuildQR("personas," + mid, "Esta Persona")}
|
||||
<fieldset>
|
||||
<label>
|
||||
Nombre<br>
|
||||
<input type="text" id="${field_nombre}"><br><br>
|
||||
</label>
|
||||
<label>
|
||||
Zona<br>
|
||||
<input type="text" id="${field_zona}"><br><br>
|
||||
</label>
|
||||
</label>
|
||||
<details>
|
||||
<summary>Permisos</summary>
|
||||
<form id="${permisosdet}">
|
||||
</form>
|
||||
</details>
|
||||
<label>
|
||||
Anilla<br>
|
||||
<input type="color" id="${field_anilla}"><br><br>
|
||||
</label>
|
||||
<label>
|
||||
Foto (PNG o JPG)<br>
|
||||
<img id="${render_foto}" height="100px" style="border: 3px inset; min-width: 7px;" src="static/ico/user_generic.png">
|
||||
<input type="file" accept="image/*" id="${field_foto}" style="display: none;"><br><br>
|
||||
</label>
|
||||
|
||||
<details style="background: #e3f2fd; border: 2px solid #2196f3; border-radius: 8px; padding: 10px; margin: 15px 0;">
|
||||
<summary style="cursor: pointer; font-weight: bold; color: #1976d2;">💳 Tarjeta Monedero</summary>
|
||||
<div style="padding: 15px;">
|
||||
<label>
|
||||
Balance Actual<br>
|
||||
<input type="number" step="0.01" id="${field_monedero_balance}" style="font-size: 24px; font-weight: bold; color: #1976d2;"><br>
|
||||
<small>Se actualiza automáticamente con las transacciones</small><br><br>
|
||||
</label>
|
||||
<label>
|
||||
Notas del Monedero<br>
|
||||
<textarea id="${field_monedero_notas}" rows="3" placeholder="Notas adicionales sobre el monedero..."></textarea><br><br>
|
||||
</label>
|
||||
<button type="button" id="${btn_ver_monedero}" class="btn5">Ver Transacciones del Monedero</button>
|
||||
</div>
|
||||
</details>
|
||||
<h1>Persona <code id="${nameh1}"></code></h1>
|
||||
${BuildQR("personas," + mid, "Esta Persona")}
|
||||
<fieldset>
|
||||
<label>
|
||||
Nombre<br>
|
||||
<input type="text" id="${field_nombre}"><br><br>
|
||||
</label>
|
||||
<label>
|
||||
Zona<br>
|
||||
<input type="text" id="${field_zona}"><br><br>
|
||||
</label>
|
||||
</label>
|
||||
<details>
|
||||
<summary>Permisos</summary>
|
||||
<form id="${permisosdet}">
|
||||
</form>
|
||||
</details>
|
||||
<label>
|
||||
Anilla<br>
|
||||
<input type="color" id="${field_anilla}"><br><br>
|
||||
</label>
|
||||
<label>
|
||||
Foto (PNG o JPG)<br>
|
||||
<img id="${render_foto}" height="100px" style="border: 3px inset; min-width: 7px;" src="static/ico/user_generic.png">
|
||||
<input type="file" accept="image/*" id="${field_foto}" style="display: none;"><br><br>
|
||||
</label>
|
||||
|
||||
<details style="background: #e3f2fd; border: 2px solid #2196f3; border-radius: 8px; padding: 10px; margin: 15px 0;">
|
||||
<summary style="cursor: pointer; font-weight: bold; color: #1976d2;">💳 Tarjeta Monedero</summary>
|
||||
<div style="padding: 15px;">
|
||||
<label>
|
||||
Balance Actual<br>
|
||||
<input type="number" step="0.01" id="${field_monedero_balance}" style="font-size: 24px; font-weight: bold; color: #1976d2;"><br>
|
||||
<small>Se actualiza automáticamente con las transacciones</small><br><br>
|
||||
</label>
|
||||
<label>
|
||||
Notas del Monedero<br>
|
||||
<textarea id="${field_monedero_notas}" rows="3" placeholder="Notas adicionales sobre el monedero..."></textarea><br><br>
|
||||
</label>
|
||||
<button type="button" id="${btn_ver_monedero}" class="btn5">Ver Transacciones del Monedero</button>
|
||||
</div>
|
||||
</details>
|
||||
<details style="background: #e3f2fd; border: 2px solid #21f328ff; border-radius: 8px; padding: 10px; margin: 15px 0;">
|
||||
<summary style="cursor: pointer; font-weight: bold; color: #38d219ff;">Generar enlaces</summary>
|
||||
<div style="padding: 15px;">
|
||||
<label>
|
||||
Inicio de sesión automatico<br>
|
||||
<input type="url" value="https://" style="font-size: 24px; font-weight: bold; color: #1976d2;"><br>
|
||||
</label>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<label>
|
||||
Notas<br>
|
||||
<textarea id="${field_notas}"></textarea><br><br>
|
||||
</label><hr>
|
||||
<button class="btn5" id="${btn_guardar}">Guardar</button>
|
||||
<button class="rojo" id="${btn_borrar}">Borrar</button>
|
||||
</fieldset>
|
||||
`;
|
||||
<label>
|
||||
Notas<br>
|
||||
<textarea id="${field_notas}"></textarea><br><br>
|
||||
</label><hr>
|
||||
<button class="btn5" id="${btn_guardar}">Guardar</button>
|
||||
<button class="rojo" id="${btn_borrar}">Borrar</button>
|
||||
</fieldset>
|
||||
`;
|
||||
var resized = "";
|
||||
var pdel = document.getElementById(permisosdet)
|
||||
var pdel = document.getElementById(permisosdet);
|
||||
gun
|
||||
.get(TABLE)
|
||||
.get("personas")
|
||||
@@ -81,20 +93,20 @@ PAGES.personas = {
|
||||
.once((data, key) => {
|
||||
function load_data(data, ENC = "") {
|
||||
document.getElementById(nameh1).innerText = key;
|
||||
var pot = "<ul>"
|
||||
var pot = "<ul>";
|
||||
Object.entries(PERMS).forEach((page) => {
|
||||
var c = ""
|
||||
var c = "";
|
||||
if ((data["Roles"] || ",").split(",").includes(page[0])) {
|
||||
c = "checked"
|
||||
c = "checked";
|
||||
}
|
||||
pot += `
|
||||
<li><label>
|
||||
<input name="perm" value="${page[0]}" type="checkbox" ${c}>
|
||||
${page[1]}
|
||||
</label></li>
|
||||
`
|
||||
})
|
||||
pdel.innerHTML = pot + "</ul>"
|
||||
`;
|
||||
});
|
||||
pdel.innerHTML = pot + "</ul>";
|
||||
document.getElementById(field_nombre).value = data["Nombre"] || "";
|
||||
document.getElementById(field_zona).value = data["Region"] || "";
|
||||
document.getElementById(field_anilla).value = data["SC_Anilla"] || "";
|
||||
@@ -102,8 +114,10 @@ PAGES.personas = {
|
||||
data["Foto"] || "static/ico/user_generic.png";
|
||||
resized = data["Foto"] || "static/ico/user_generic.png";
|
||||
document.getElementById(field_notas).value = data["markdown"] || "";
|
||||
document.getElementById(field_monedero_balance).value = data["Monedero_Balance"] || 0;
|
||||
document.getElementById(field_monedero_notas).value = data["Monedero_Notas"] || "";
|
||||
document.getElementById(field_monedero_balance).value =
|
||||
data["Monedero_Balance"] || 0;
|
||||
document.getElementById(field_monedero_notas).value =
|
||||
data["Monedero_Notas"] || "";
|
||||
}
|
||||
if (typeof data == "string") {
|
||||
TS_decrypt(data, SECRET, (data) => {
|
||||
@@ -130,7 +144,7 @@ PAGES.personas = {
|
||||
);
|
||||
});
|
||||
document.getElementById(btn_guardar).onclick = () => {
|
||||
var dt = new FormData(pdel)
|
||||
var dt = new FormData(pdel);
|
||||
var data = {
|
||||
Nombre: document.getElementById(field_nombre).value,
|
||||
Region: document.getElementById(field_zona).value,
|
||||
@@ -138,7 +152,9 @@ PAGES.personas = {
|
||||
SC_Anilla: document.getElementById(field_anilla).value,
|
||||
Foto: resized,
|
||||
markdown: document.getElementById(field_notas).value,
|
||||
Monedero_Balance: parseFloat(document.getElementById(field_monedero_balance).value) || 0,
|
||||
Monedero_Balance:
|
||||
parseFloat(document.getElementById(field_monedero_balance).value) ||
|
||||
0,
|
||||
Monedero_Notas: document.getElementById(field_monedero_notas).value,
|
||||
};
|
||||
var enc = TS_encrypt(data, SECRET, (encrypted) => {
|
||||
@@ -148,7 +164,7 @@ PAGES.personas = {
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("personas");
|
||||
}, 750);
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
};
|
||||
document.getElementById(btn_ver_monedero).onclick = () => {
|
||||
@@ -160,22 +176,25 @@ PAGES.personas = {
|
||||
toastr.error("Borrado!");
|
||||
setTimeout(() => {
|
||||
setUrlHash("personas");
|
||||
}, 750);
|
||||
}, SAVE_WAIT);
|
||||
}
|
||||
};
|
||||
},
|
||||
index: function () {
|
||||
if (!checkRole("personas")) {setUrlHash("index");return}
|
||||
if (!checkRole("personas")) {
|
||||
setUrlHash("index");
|
||||
return;
|
||||
}
|
||||
var btn_new = safeuuid();
|
||||
container.innerHTML = `
|
||||
<h1>Personas</h1>
|
||||
<button id="${btn_new}">Nueva Persona</button>
|
||||
<div id="tableContainer"></div>
|
||||
`;
|
||||
<h1>Personas</h1>
|
||||
<button id="${btn_new}">Nueva Persona</button>
|
||||
<div id="tableContainer"></div>
|
||||
`;
|
||||
|
||||
const config = [
|
||||
{
|
||||
label: "Persona",
|
||||
{
|
||||
label: "Persona",
|
||||
type: "persona",
|
||||
self: true,
|
||||
},
|
||||
@@ -191,12 +210,12 @@ PAGES.personas = {
|
||||
undefined,
|
||||
true // Enable global search bar
|
||||
);
|
||||
if (!checkRole("personas:edit")) {
|
||||
document.getElementById(btn_new).style.display = "none"
|
||||
} else {
|
||||
document.getElementById(btn_new).onclick = () => {
|
||||
setUrlHash("personas," + safeuuid(""));
|
||||
};
|
||||
}
|
||||
if (!checkRole("personas:edit")) {
|
||||
document.getElementById(btn_new).style.display = "none";
|
||||
} else {
|
||||
document.getElementById(btn_new).onclick = () => {
|
||||
setUrlHash("personas," + safeuuid(""));
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -23,39 +23,39 @@ PAGES.supercafe = {
|
||||
var btn_guardar2 = safeuuid();
|
||||
var btn_borrar = safeuuid();
|
||||
container.innerHTML = `
|
||||
<h1>Comanda <code id="${nameh1}"></code></h1>
|
||||
<button onclick="setUrlHash('supercafe');">Salir</button>
|
||||
<fieldset style="text-align: center;">
|
||||
<legend>Rellenar comanda</legend>
|
||||
<label style="display: none;">
|
||||
Fecha<br>
|
||||
<input readonly disabled type="text" id="${field_fecha}" value=""><br><br>
|
||||
</label>
|
||||
<label style="display: none;">
|
||||
Persona<br>
|
||||
<input type="hidden" id="${field_persona}">
|
||||
<br><br>
|
||||
</label>
|
||||
<label style="display: none;">
|
||||
Comanda (utiliza el panel de relleno)<br>
|
||||
<textarea readonly disabled id="${field_comanda}"></textarea><br><br>
|
||||
</label>
|
||||
<div id="${div_actions}" open>
|
||||
<!--<summary>Mostrar botones de relleno</summary>-->
|
||||
</div>
|
||||
<label>
|
||||
Notas<br>
|
||||
<textarea id="${field_notas}"></textarea><br><br>
|
||||
</label>
|
||||
<label style="display: none;">
|
||||
Estado<br>
|
||||
<input readonly disabled type="text" id="${field_estado}" value="%%">
|
||||
<br>Modificar en el listado de comandas<br>
|
||||
</label>
|
||||
<button id=${btn_guardar} class="btn5">Guardar</button>
|
||||
<button id=${btn_borrar} class="rojo">Borrar</button>
|
||||
</fieldset>
|
||||
`;
|
||||
<h1>Comanda <code id="${nameh1}"></code></h1>
|
||||
<button onclick="setUrlHash('supercafe');">Salir</button>
|
||||
<fieldset style="text-align: center;">
|
||||
<legend>Rellenar comanda</legend>
|
||||
<label style="display: none;">
|
||||
Fecha<br>
|
||||
<input readonly disabled type="text" id="${field_fecha}" value=""><br><br>
|
||||
</label>
|
||||
<label style="display: none;">
|
||||
Persona<br>
|
||||
<input type="hidden" id="${field_persona}">
|
||||
<br><br>
|
||||
</label>
|
||||
<label style="display: none;">
|
||||
Comanda (utiliza el panel de relleno)<br>
|
||||
<textarea readonly disabled id="${field_comanda}"></textarea><br><br>
|
||||
</label>
|
||||
<div id="${div_actions}" open>
|
||||
<!--<summary>Mostrar botones de relleno</summary>-->
|
||||
</div>
|
||||
<label>
|
||||
Notas<br>
|
||||
<textarea id="${field_notas}"></textarea><br><br>
|
||||
</label>
|
||||
<label style="display: none;">
|
||||
Estado<br>
|
||||
<input readonly disabled type="text" id="${field_estado}" value="%%">
|
||||
<br>Modificar en el listado de comandas<br>
|
||||
</label>
|
||||
<button id=${btn_guardar} class="btn5">Guardar</button>
|
||||
<button id=${btn_borrar} class="rojo">Borrar</button>
|
||||
</fieldset>
|
||||
`;
|
||||
var currentData = {};
|
||||
var currentPersonaID = "";
|
||||
var divact = document.getElementById(div_actions);
|
||||
@@ -126,7 +126,7 @@ PAGES.supercafe = {
|
||||
setTimeout(() => {
|
||||
document.getElementById("actionStatus").style.display = "none";
|
||||
setUrlHash("supercafe");
|
||||
}, 750);
|
||||
}, SAVE_WAIT);
|
||||
});
|
||||
};
|
||||
document.getElementById(btn_borrar).onclick = () => {
|
||||
@@ -138,7 +138,7 @@ PAGES.supercafe = {
|
||||
betterGunPut(gun.get(TABLE).get("supercafe").get(mid), null);
|
||||
setTimeout(() => {
|
||||
setUrlHash("supercafe");
|
||||
}, 750);
|
||||
}, SAVE_WAIT);
|
||||
}
|
||||
};
|
||||
},
|
||||
@@ -165,24 +165,24 @@ PAGES.supercafe = {
|
||||
var tts_check = safeuuid();
|
||||
var old = {};
|
||||
container.innerHTML = `
|
||||
<h1>SuperCafé - Total: <span id="${totalprecio}">0</span>c</h1>
|
||||
<button id="${btn_new}" style="${sc_nobtn};">Nueva comanda</button>
|
||||
<br>
|
||||
<label>
|
||||
<b>Habilitar avisos:</b>
|
||||
<input type="checkbox" id="${tts_check}" style="height: 25px;width: 25px;">
|
||||
</label>
|
||||
<h1>SuperCafé - Total: <span id="${totalprecio}">0</span>c</h1>
|
||||
<button id="${btn_new}" style="${sc_nobtn};">Nueva comanda</button>
|
||||
<br>
|
||||
<label>
|
||||
<b>Habilitar avisos:</b>
|
||||
<input type="checkbox" id="${tts_check}" style="height: 25px;width: 25px;">
|
||||
</label>
|
||||
|
||||
<details style="background: beige; padding: 15px; border-radius: 15px; border: 2px solid black" open>
|
||||
<summary>Todas las comandas</summary>
|
||||
<div id="cont1"></div>
|
||||
</details>
|
||||
<br>
|
||||
<details style="background: lightpink; padding: 15px; border-radius: 15px; border: 2px solid black" open>
|
||||
<summary>Deudas</summary>
|
||||
<div id="cont2"></div>
|
||||
</details>
|
||||
`;
|
||||
<details style="background: beige; padding: 15px; border-radius: 15px; border: 2px solid black" open>
|
||||
<summary>Todas las comandas</summary>
|
||||
<div id="cont1"></div>
|
||||
</details>
|
||||
<br>
|
||||
<details style="background: lightpink; padding: 15px; border-radius: 15px; border: 2px solid black" open>
|
||||
<summary>Deudas</summary>
|
||||
<div id="cont2"></div>
|
||||
</details>
|
||||
`;
|
||||
var config = [
|
||||
{
|
||||
key: "Persona",
|
||||
|
||||
10
src/sw.js
10
src/sw.js
@@ -1,5 +1,7 @@
|
||||
var CACHE = "telesec_%%VERSIONCO%%"
|
||||
importScripts('https://storage.googleapis.com/workbox-cdn/releases/5.1.2/workbox-sw.js');
|
||||
var CACHE = "telesec_%%VERSIONCO%%";
|
||||
importScripts(
|
||||
"https://storage.googleapis.com/workbox-cdn/releases/5.1.2/workbox-sw.js"
|
||||
);
|
||||
|
||||
self.addEventListener("message", (event) => {
|
||||
if (event.data && event.data.type === "SKIP_WAITING") {
|
||||
@@ -8,8 +10,8 @@ self.addEventListener("message", (event) => {
|
||||
});
|
||||
|
||||
workbox.routing.registerRoute(
|
||||
new RegExp('/*'),
|
||||
new RegExp("/*"),
|
||||
new workbox.strategies.StaleWhileRevalidate({
|
||||
cacheName: CACHE
|
||||
cacheName: CACHE,
|
||||
})
|
||||
);
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "telesec",
|
||||
"compatibility_date": "2025-12-12",
|
||||
"assets": {
|
||||
"directory": "./dist",
|
||||
},
|
||||
"pages_build_output_dir": "./dist"
|
||||
}
|
||||
Reference in New Issue
Block a user