nuevo mantenedor de roles

francisco/photos
Francisco Sandoval 2024-01-07 13:16:53 -03:00
parent add9428eab
commit 684ff2e65b
29 changed files with 551 additions and 579 deletions

View File

@ -22,7 +22,7 @@
* Typecheck JS in `.svelte` and `.js` files by default.
* Disable this if you'd like to use dynamic types.
*/
"checkJs": true,
"checkJs": false,
"baseUrl": ".",
"paths": {

View File

@ -1,5 +1,5 @@
<div class="table-responsive">
<div class="table-responsive" style="max-height: 500px;">
<table class="table table-hover table-bordered">
<slot />
</table>

View File

@ -13,7 +13,7 @@
import Sidebar from './Sidebar.svelte'
import Footer from './Footer.svelte'
import Notifications from './Notifications.svelte'
import { routes } from '$/routes/user.routes'
import { getRoutes } from '$/routes/user.routes'
import { Router, Route, createHistory } from 'svelte-navigator'
import hashHistory from './hashHistory'
import { onMount } from 'svelte'
@ -24,6 +24,11 @@
let triggerEvent = false;
// @ts-ignore
const history = createHistory(hashHistory())
let routes = []
getRoutes()
.then(data => routes = data)
.catch(error => alert(error))
onMount(() => {
triggerEvent && document.dispatchEvent(new Event('DOMContentLoaded'));
@ -49,8 +54,8 @@
<main class="content">
<div class="container-fluid p-0">
{#each routes as r}
<Route path={r.path}>
{#each routes as r, index}
<Route path={r.path} >
<svelte:component this={r.component} />
</Route>
{/each}

View File

@ -1,15 +1,23 @@
<script>
import { Link, useMatch } from 'svelte-navigator'
import { storePermisos } from "$/stores/global";
import { Link, useMatch } from "svelte-navigator";
export let to = '#'
const absoluteMatch = useMatch(to)
export let to = "#";
const absoluteMatch = useMatch(to);
let exist = false
storePermisos.subscribe(val => {
exist = val.findIndex(r => r.path.indexOf(to) === 0) !== -1;
})
let match;
$: match = $absoluteMatch?.fullPath === to;
</script>
<li class={"sidebar-item" + (match ? ' active' : '')}>
<Link class="sidebar-link" {to}>
<slot />
</Link>
</li>
{#if exist}
<li class={"sidebar-item" + (match ? " active" : "")}>
<Link class="sidebar-link" {to}>
<slot />
</Link>
</li>
{/if}

View File

@ -3,6 +3,7 @@
import { getAplicaciones } from "$/services/aplicaciones";
import PageTitle from "$/components/PageTitle.svelte";
import ModalAplicacion from "./ModalAplicacion.svelte";
import { getPermisoPath } from "$/stores/global";
const limit = 15;
let page = 1;
@ -12,6 +13,7 @@
let aplicaciones = []
let aplicacion = null
let loading = false;
let permiso_app = getPermisoPath()
$: onPage(page)
@ -47,9 +49,11 @@
<div class="card">
<div class="card-header">
<button class="btn btn-primary" on:click|preventDefault={onNuevo}>
<i class="bi bi-plus-lg"></i> Nuevo
</button>
{#if permiso_app.escritura}
<button class="btn btn-primary" on:click|preventDefault={onNuevo}>
<i class="bi bi-plus-lg"></i> Nuevo
</button>
{/if}
</div>
<div class="card-body">
<div class="table-responsive">
@ -81,7 +85,7 @@
</thead>
<tbody>
{#each aplicaciones as app, index}
<tr>
<tr key={index}>
<td class="table-light">{offset + index + 1}</td>
<td>{app.id_aplicacion}</td>
<td><a href={"#"} on:click|preventDefault={() => onEdita(app)}>{app.nombre_app}</a></td>

View File

@ -2,11 +2,13 @@
import Modal from "../../components/Modal.svelte";
import { getAplicacion, createAplicacion, updateAplicacion, deleteAplicacion } from "$/services/aplicaciones";
import { createEventDispatcher } from "svelte";
import { getPermisoPath } from "$/stores/global";
const dispatch = createEventDispatcher();
export let aplicacion = {}
let form = {}
let loading = false;
let permiso_app = getPermisoPath()
$: begin(aplicacion.id_aplicacion)
@ -61,7 +63,7 @@
<Modal title={'Aplicacion #' + (aplicacion.id_aplicacion || 'Nuevo')}
size="lg"
on:close={() => dispatch('close')}>
<div class="form">
<div class={"form" + (permiso_app.escritura ? '' : ' disabled')}>
<div class="row mb-3">
<div class="col-md-3">ID</div>
<div class="col-md">
@ -92,8 +94,14 @@
</div>
</div>
<svelte:fragment slot="buttons">
<button class="btn btn-primary"type="submit" disabled={loading}>Guardar</button>
<button class="btn btn-danger" on:click|preventDefault={onDelete} disabled={loading}>Eliminar</button>
{#if permiso_app.escritura}
<button class="btn btn-primary"type="submit" disabled={loading}>Guardar</button>
<button class="btn btn-danger" on:click|preventDefault={onDelete} disabled={loading}>Eliminar</button>
{/if}
</svelte:fragment>
</Modal>
</form>
</form>
<style>
.disabled { pointer-events: none !important; }
</style>

View File

@ -5,6 +5,7 @@
import { getComunas, getComuna, createComuna, updateComuna, deleteComuna } from '$/services/comunas'
import Modal from '$/components/Modal.svelte';
import FormComuna from './Form.svelte';
import { getPermisoPath } from '$/stores/global';
let comuna = null
let es_nuevo = true
@ -12,6 +13,7 @@
let page = 1
let loading = false;
const limit = 15
let permiso_app = getPermisoPath()
$: onPage(page)
@ -77,10 +79,12 @@
<div class="card">
<div class="card-header">
<div class="mb-3 d-flex">
<button class="btn btn-primary me-3"
on:click|preventDefault={onNuevo}>
<i class="bi bi-plus-lg"></i> Nuevo
</button>
{#if permiso_app.escritura}
<button class="btn btn-primary me-3"
on:click|preventDefault={onNuevo}>
<i class="bi bi-plus-lg"></i> Nuevo
</button>
{/if}
<div class="m-auto"></div>
<Link to='/' class="btn btn-outline-secondary">Volver</Link>
</div>
@ -113,7 +117,7 @@
<i class="bi bi-arrow-repeat"></i>
</a>
<Paginate
offset={(page - 1) * limit}
forcePage={page}
{limit}
count={comunas.count}
on:page={ev => page = ev.detail}
@ -127,11 +131,15 @@
<Modal title="Comuna"
on:close={() => comuna = null}
>
<FormComuna bind:form={comuna} {es_nuevo} />
<div class={permiso_app.escritura ? "" : "disabled"}>
<FormComuna bind:form={comuna} {es_nuevo} />
</div>
<svelte:fragment slot="buttons">
<button type="submit" class="btn btn-primary">Guardar</button>
{#if !es_nuevo}
{#if permiso_app.escritura}
<button type="submit" class="btn btn-primary">Guardar</button>
{/if}
{#if !es_nuevo && permiso_app.escritura}
<button class="btn btn-danger" on:click|preventDefault={onDelete}>Eliminar</button>
{/if}
</svelte:fragment>
@ -140,7 +148,6 @@
{/if}
<style>
.table-responsive {
max-height: calc(100vh - 300px);
}
.table-responsive { max-height: calc(100vh - 300px); }
.disabled { pointer-events: none !important; }
</style>

View File

@ -7,12 +7,14 @@
createParaderoImagen,
deleteParaderoImagen,
} from "$/services/paraderos";
import { getPermisoPath } from "$/stores/global";
import IconLoading from "../../components/IconLoading.svelte";
export let parada = null;
let form = {};
let imagenes = [];
let loading = false;
let permiso_app = getPermisoPath();
$: init(!!parada);
@ -55,7 +57,7 @@
if (!confirm("Estás seguro de eliminar la imagen?")) return;
await deleteParaderoImagen(id_paradero_imagen);
imagenes = imagenes.filter(
(imagen) => imagen.id_paradero_imagen !== id_paradero_imagen
(imagen) => imagen.id_paradero_imagen !== id_paradero_imagen,
);
} catch (error) {
alert(error);
@ -71,21 +73,21 @@
Coordenadas:
<div class="input-group mb-3">
<div class="input-group-text">Latitud</div>
<div class="form-control">{form.stop_lat || '...'}</div>
<div class="form-control">{form.stop_lat || "..."}</div>
</div>
<div class="input-group mb-3">
<div class="input-group-text">Longitud</div>
<div class="form-control">{form.stop_lon || '...'}</div>
<div class="form-control">{form.stop_lon || "..."}</div>
</div>
Propiedades:
<form on:submit|preventDefault={onSave}>
<form on:submit|preventDefault={onSave} class={permiso_app.escritura ? '' : 'disabled'}>
<div class="input-group mb-3">
<div class="input-group-text">Identificador</div>
<input
type="text"
disabled
value={form.id_paradero || '...'}
value={form.id_paradero || "..."}
class="form-control"
/>
</div>
@ -106,11 +108,13 @@
/>
</div>
<hr />
<div class="text-center">
<button type="submit" class="btn btn-primary"
><i class="bi bi-save" /> Guardar</button
>
</div>
{#if permiso_app.escritura}
<div class="text-center">
<button type="submit" class="btn btn-primary"
><i class="bi bi-save" /> Guardar</button
>
</div>
{/if}
</form>
<div class="my-3" />
@ -129,24 +133,26 @@
{/each}
<!-- agregar imagen -->
<form action="" on:submit|preventDefault={onSaveImagen}>
<div class="card">
<div class="card-body">
<div class="form-control" style="overflow: hidden">
<input
type="file"
name="file1"
accept="*.png,*.jpg,*.jpeg"
/>
{#if permiso_app.escritura}
<form action="" on:submit|preventDefault={onSaveImagen}>
<div class="card">
<div class="card-body">
<div class="form-control" style="overflow: hidden">
<input
type="file"
name="file1"
accept="*.png,*.jpg,*.jpeg"
/>
</div>
</div>
<div class="card-footer text-center">
<button class="btn btn-primary" type="submit">
<i class="bi bi-plus-lg" /> Agregar imagen
</button>
</div>
</div>
<div class="card-footer text-center">
<button class="btn btn-primary" type="submit">
<i class="bi bi-plus-lg" /> Agregar imagen
</button>
</div>
</div>
</form>
</form>
{/if}
</div>
<style>
@ -158,4 +164,7 @@
bottom: 0.5rem;
right: 0.5rem;
}
.disabled {
pointer-events: none !important;
}
</style>

View File

@ -5,6 +5,7 @@
import { getTiposDispositivo } from "../../services/tipos_dispositivo";
import { url_base } from "../../services/_config";
import { getInfoPublic } from '../../services/paraderos';
import { getPermisoPath } from '$/stores/global';
export let parada = null;
let loading = false;
@ -12,6 +13,7 @@
let dispositivos = [];
let url_qrcode = null;
let nuevoDispositivo = null;
let permiso_app = getPermisoPath()
async function fetchDispositivos({ id_paradero = null }) {
try {
@ -91,15 +93,22 @@
<tr>
<td>{disp.id_dispositivo}</td>
<td>{disp.tipo_dispositivo?.descripcion || '--'}</td>
<td><a href={"#"} on:click|preventDefault={() => onDelete(disp)}><i class="bi bi-trash text-danger"></i></a></td>
<td>
{#if permiso_app.escritura}
<a href={"#"} on:click|preventDefault={() => onDelete(disp)}><i class="bi bi-trash text-danger"></i></a>
{/if}
</td>
</tr>
{/each}
</tbody>
</table>
<div class="my-3 text-center">
<button class="btn btn-outline-primary" on:click|preventDefault={() => nuevoDispositivo = {}}>Nuevo Dispositivo</button>
</div>
{#if permiso_app.escritura}
<div class="my-3 text-center">
<button class="btn btn-outline-primary" on:click|preventDefault={() => nuevoDispositivo = {}}>Nuevo Dispositivo</button>
</div>
{/if}
{:else}
<form action="" on:submit|preventDefault={onSave}>
<div class="input-group">

View File

@ -3,10 +3,12 @@
import Paginate from '$/components/Paginate.svelte'
import { getPersonas } from '$/services/personas';
import PageTitle from '$/components/PageTitle.svelte';
import { getPermisoPath } from '$/stores/global';
let page = 1;
let limit = 15;
let personas = { results: [], count: 0 };
let loading = false;
let permiso_app = getPermisoPath()
$: onPage(page)
@ -27,9 +29,11 @@
<div class="card">
<div class="card-header">
<Link to='/personas/nuevo' class="btn btn-primary">
<i class="bi bi-plus-lg"></i> Nuevo
</Link>
{#if permiso_app.escritura}
<Link to='/personas/nuevo' class="btn btn-primary">
<i class="bi bi-plus-lg"></i> Nuevo
</Link>
{/if}
</div>
<div class="card-body">
<table class="table table-sm">

View File

@ -1,6 +1,6 @@
<script>
import { onMount } from 'svelte'
import { storeLayout } from '$/stores/global'
import { getPermisoPath, storeLayout } from '$/stores/global'
import FormPersona from './Form.svelte'
import { Link, useParams, useNavigate } from 'svelte-navigator';
import { getPersona, createPersona, updatePersona } from '$/services/personas';
@ -18,6 +18,7 @@
let es_nuevo = true;
let form = {}
let loading = false;
let permiso_app = getPermisoPath()
$: es_nuevo = !$params.rut
$: begin($params)
@ -55,13 +56,21 @@
<form action="" on:submit|preventDefault={onSave}>
<div class="card">
<div class="card-header d-flex">
<button type="submit" class="btn btn-primary"><i class="bi bi-save"></i> Guardar</button>
{#if permiso_app.escritura}
<button type="submit" class="btn btn-primary"><i class="bi bi-save"></i> Guardar</button>
{/if}
<div class="m-auto"></div>
<Link to="/personas" class="btn btn-outline-secondary">Volver</Link>
</div>
<div class="card-body">
<h4 class="h4 mb-3">Datos de la persona</h4>
<FormPersona bind:form={form} {es_nuevo} />
<div class={permiso_app.escritura ? "" : "disabled"}>
<FormPersona bind:form={form} {es_nuevo} />
</div>
</div>
</div>
</form>
</form>
<style>
.disabled { pointer-events: none !important; }
</style>

View File

@ -3,6 +3,7 @@
import { getRoles } from "$/services/roles";
import PageTitle from "$/components/PageTitle.svelte";
import ModalRol from "./ModalRol.svelte";
import { getPermisoPath } from "$/stores/global";
const limit = 15;
let page = 1;
@ -12,6 +13,9 @@
let roles = []
let rol = null
let loading = false;
let permiso_app = getPermisoPath()
console.log({ permiso_app })
$: onPage(page)
@ -47,17 +51,19 @@
<div class="card">
<div class="card-header">
<button class="btn btn-primary" on:click|preventDefault={onNuevo}>
<i class="bi bi-plus-lg"></i> Nuevo
</button>
{#if permiso_app.escritura}
<button class="btn btn-primary" on:click|preventDefault={onNuevo}>
<i class="bi bi-plus-lg"></i> Nuevo
</button>
{/if}
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-sm table-bordered">
<thead>
<tr class="table-light">
<th style="width:5%">Nro</th>
<th>
<th style="width: 5%">Nro</th>
<th style="width: 5%">
<a href={"#"} on:click|preventDefault={() => onOrderBy('id_rol')}>ID</a>
{#if ordering === 'id_rol'}<i class="bi bi-caret-up-fill"></i>{/if}
{#if ordering === '-id_rol'}<i class="bi bi-caret-down-fill"></i>{/if}
@ -86,7 +92,7 @@
<i class="bi bi-arrow-repeat"></i>
</a>
<Paginate
{offset}
forcePage={page}
{limit}
{count}
on:page={ev => page = ev.detail}
@ -95,11 +101,7 @@
</div>
{#if rol}
<ModalRol
{rol}
on:close={() => rol = null}
on:refresh={() => onPage(page)}
/>
<ModalRol {rol} on:close={() => rol = null} on:refresh={() => onPage(page)} />
{/if}
<style>

View File

@ -1,263 +1,195 @@
<script>
import Modal from "../../components/Modal.svelte";
import { getRol, createRol, updateRol, deleteRol } from "$/services/roles";
import Modal from "$/components/Modal.svelte";
import { getAplicaciones } from "$/services/aplicaciones";
import { getRolesyaplicaciones , createRolyaplicacion , updateRolyaplicacion , deleteRolyaplicacion } from "$/services/rolesyaplicaciones";
import { createRol, getRol, updateRol } from "$/services/roles";
import { createRolyaplicacion, deleteRolyaplicacion, getRolesyaplicaciones, updateRolyaplicacion } from "$/services/roles_aplicaciones";
import { createRolLinea, deleteRolLinea, getRolLineas } from '$/services/roles_lineas';
import { getPermisoPath } from "$/stores/global";
import { createEventDispatcher } from "svelte";
import { getRolesaplicaciones } from "../../services/rolesyaplicaciones";
const dispatch = createEventDispatcher();
import TabForm from "./TabForm.svelte";
import TabAplicaciones from "./TabAplicaciones.svelte";
import TabLineas from "./TabLineas.svelte";
import "./modal.css"
import { getLineas } from "$/services/lineas";
const dispatch = createEventDispatcher()
export let rol = {}
export let rol = {};
let loading = false
let form = {}
let loading = false;
let form2 = []
let form3 = []
let rolaplicaciones = []
let form_inicio = []
let permiso_app = getPermisoPath()
let permisos_app = []
let permisos_lineas = []
let tab = 0
$: begin(rol.id_rol)
$: begin2(rol.id_rol)
async function begin(id) {
async function fetchRol({ id_rol = null }) {
try {
if (!id) return;
form = await getRol(id) || {}
if (!id_rol) return;
form = await getRol(id_rol) || {}
await fetchPermisosAplicaciones(id_rol)
await fetchPermisosLineas(id_rol)
} catch (error) {
alert(error.detail || error)
alert(error)
}
}
async function begin2(id) {
async function fetchPermisosAplicaciones(id_rol) {
try {
form2 = await getAplicaciones() || []
if (!id) {
rolaplicaciones = []
}
else{
rolaplicaciones = await getRolesyaplicaciones(id)
}
form3 = combinarArreglos(form2,rolaplicaciones)
const aplicaciones = await getAplicaciones({ ordering: 'nombre_app' })
const rol_aplicaciones = await getRolesyaplicaciones(id_rol)
for(const obj1 of form3){
const nuevoItem = {
id_rol_app: obj1.id_rol_app,
id_aplicacion: obj1.id_aplicacion,
nombre_app: obj1.nombre_app,
vigente: obj1.vigente,
id_rol:obj1.id_rol,
solo_visualizar:obj1.solo_visualizar,
acceso:obj1.acceso
};
form_inicio.push(nuevoItem)
permisos_app = aplicaciones.map(app => {
const item = rol_aplicaciones.find(el => el.id_aplicacion === app.id_aplicacion)
const acceso = !!item
const { id_rol_app = null, solo_visualizar = false} = item || {}
}
return { ...app, id_rol_app, acceso, solo_visualizar, modificado: false }
})
} catch (error) {
alert(error.detail || error)
alert(error)
}
}
async function onSave() {
async function fetchPermisosLineas(id_rol) {
try {
const lineas = await getLineas()
const rol_lineas = await getRolLineas({ id_rol })
permisos_lineas = lineas.map(linea => {
const item = rol_lineas.find(el => el.id_linea === linea.id_linea)
const acceso = !!item;
return { ...linea, id_rol_linea: item?.id_rol_linea || null, acceso, modificado: false }
})
} catch (error) {
alert(error)
}
}
async function onSaveRol() {
try {
loading = true;
if (rol.id_rol) {
form = await updateRol(form)
form3 = CrearEditarEliminar(rol.id_rol,form_inicio,form3)
for(const obj1 of form3){
if (obj1.opcion == "Crear"){
await createRolyaplicacion(obj1)
}
else if (obj1.opcion == "Editar"){
await updateRolyaplicacion(obj1)
}
else if (obj1.opcion == "Eliminar"){
await deleteRolyaplicacion(obj1.id_rol_app)
}
}
} else {
form = await createRol(form)
form3 = Arreglo_crear(form3,form.id_rol)
for(const obj1 of form3){
await createRolyaplicacion(obj1)
await fetchPermisosAplicaciones(form.id_rol)
await fetchPermisosLineas(form.id_rol)
}
dispatch('refresh')
alert('Propiedades del Rol guardadas.')
} catch (error) {
alert(error)
}
}
async function onDeleteRol() {
try {
} catch (error) {
alert(error)
}
}
async function onSavePermisos() {
try {
const modificados = permisos_app.filter(el => el.modificado)
const { id_rol } = rol;
for (let permiso of modificados) {
if (!permiso.acceso && permiso.id_rol_app) {
await deleteRolyaplicacion(permiso.id_rol_app)
}
if (permiso.acceso && !permiso.id_rol_app) {
const { id_aplicacion, solo_visualizar = false } = permiso;
await createRolyaplicacion({ id_rol, id_aplicacion, solo_visualizar })
}
if (permiso.acceso && permiso.id_rol_app) {
const { id_rol_app, solo_visualizar = false } = permiso;
await updateRolyaplicacion({ id_rol_app, solo_visualizar })
}
}
alert('Se ha guardado la aplicación')
dispatch('refresh')
dispatch('close')
alert('Permisos de aplicaciones guardadas')
} catch (error) {
if (error.detail) {
alert(error.detail)
} else {
alert(JSON.stringify(error))
}
} finally {
loading = false;
alert(error)
}
}
async function onDelete() {
async function onSaveLineas() {
try {
if (!confirm('Eliminará el registro?')) return;
loading = true;
for(const obj1 of form_inicio){
if (obj1.id_rol_app != false){
if(obj1.acceso = true)
await deleteRolyaplicacion(obj1.id_rol_app)
}
const modificados = permisos_lineas.filter(el => el.modificado)
const { id_rol } = rol;
for (let permiso of modificados) {
if (!permiso.acceso && permiso.id_rol_linea) {
await deleteRolLinea(permiso.id_rol_linea)
}
if (permiso.acceso && !permiso.id_rol_linea) {
const { id_linea } = permiso;
await createRolLinea({ id_rol, id_linea })
}
}
await deleteRol(form.id_rol)
alert('Se ha eliminado la aplicación')
dispatch('refresh')
dispatch('close')
alert('Permisos de lineas guardadas')
} catch (error) {
alert(error.detail || error)
} finally {
loading = false;
}
}
function combinarArreglos(arreglo1, arreglo2) {
const resultado = [];
for (const obj1 of arreglo1) {
const objResultado = { ...obj1 };
const obj2 = arreglo2.find(item => item.id_aplicacion === obj1.id_aplicacion);
if (obj2) {
objResultado.id_rol = obj2.id_rol !== undefined ? obj2.id_rol : null;
objResultado.solo_visualizar = obj2.solo_visualizar !== undefined ? obj2.solo_visualizar : null;
objResultado.id_rol_app = obj2.id_rol_app !== undefined ? obj2.id_rol_app : null;
objResultado.acceso = true;
} else {
objResultado.id_rol = null;
objResultado.solo_visualizar = null;
objResultado.acceso = false;
objResultado.id_rol_app = false;
}
resultado.push(objResultado);
}
return resultado;
}
function Arreglo_crear(input_data,id) {
const result = [];
for (const item of input_data) {
if (item.acceso) {
result.push({
"id_aplicacion": item.id_aplicacion,
"id_rol": id,
"solo_visualizar": item.solo_visualizar
});
alert(error)
}
}
return result;
}
function CrearEditarEliminar(id, arregloInicial, arregloFinal) {
const resultado = [];
for (let i = 0; i < arregloInicial.length; i++) {
const inicio = arregloInicial[i];
const fin = arregloFinal[i];
const nuevoItem = {
id_aplicacion: inicio.id_aplicacion,
id_rol: id,
solo_visualizar: fin.solo_visualizar,
};
if (inicio.acceso !== fin.acceso) {
nuevoItem.opcion = inicio.acceso ? "Eliminar" : "Crear";
if(inicio.acceso == true){
nuevoItem.id_rol_app = inicio.id_rol_app
}
} else if (inicio.solo_visualizar !== fin.solo_visualizar) {
nuevoItem.opcion = "Editar";
nuevoItem.id_rol_app = inicio.id_rol_app
} else {
nuevoItem.opcion = null;
}
resultado.push(nuevoItem);
}
return resultado;
}
$: fetchRol(rol)
</script>
<form action="" on:submit|preventDefault={onSave}>
<Modal title={'rol #' + (rol.id_rol || 'Nuevo')}
size="lg"
on:close={() => dispatch('close')}>
<div class="form">
<div class="row mb-3">
<div class="col-md-3">Rol ID</div>
<div class="col-md">
{#if rol.id_rol}
<input type="number" value={form.id_rol} disabled class="form-control">
{:else}
<input type="number" bind:value={form.id_rol} required class="form-control">
{/if}
</div>
</div>
<div class="row mb-3">
<div class="col-md-3">Nombre Rol</div>
<div class="col-md">
<input type="text" bind:value={form.nombre_rol} required class="form-control">
</div>
</div>
<form action="" on:submit|preventDefault={onSaveRol}>
<Modal classBody="mymodal" title={"rol #" + (rol.id_rol || "Nuevo")} size="lg" on:close={() => dispatch("close")}>
<ul class="nav nav-tabs">
<li class="nav-item">
<a class={"nav-link" + (tab === 0 ? ' active' : '')} href={"#"} on:click|preventDefault={() => tab = 0}>Propiedades</a>
</li>
<li class={"nav-item" + (form.id_rol ? '' : ' disabled')}>
<a class={"nav-link" + (tab === 1 ? ' active' : '')} href={"#"} on:click|preventDefault={() => tab = 1}>Aplicaciones</a>
</li>
<li class={"nav-item" + (form.id_rol ? '' : ' disabled')}>
<a class={"nav-link" + (tab === 2 ? ' active' : '')} href={"#"} on:click|preventDefault={() => tab = 2}>Lineas</a>
</li>
</ul>
<div class="card">
<div class="card-header bg-secondary text-light">Permiso a Aplicaciones</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-sm table-bordered">
<thead>
<tr>
<th>Aplicaciones</th>
<th>Acceso</th>
<th>Solo visualizar</th>
</tr>
</thead>
<tbody>
{#each form3 as aplicacion}
<tr>
<td>{aplicacion.nombre_app}</td>
<td><input type="checkbox" bind:checked={aplicacion.acceso} ></td>
<td><input type="checkbox" bind:checked={aplicacion.solo_visualizar} disabled = {!aplicacion.acceso} ></td>
</tr>
{/each}
</tbody>
</table>
</div>
</div>
</div>
<div class="p-3 bg-white">
{#if tab === 0}
<TabForm bind:form={form} escritura={permiso_app.escritura} />
{/if}
{#if tab === 1}
<TabAplicaciones bind:permisos={permisos_app} />
{/if}
{#if tab === 2}
<TabLineas bind:permisos={permisos_lineas} />
{/if}
</div>
<svelte:fragment slot="buttons">
<button class="btn btn-primary"type="submit" disabled={loading}>Guardar</button>
<button class="btn btn-danger" on:click|preventDefault={onDelete} disabled={loading}>Eliminar</button>
{#if permiso_app.escritura}
{#if tab === 0}
<button class="btn btn-primary" type="submit" disabled={loading}>
<i class="bi bi-save"></i> Guardar
</button>
{#if rol.id_rol}
<button class="btn btn-danger" on:click|preventDefault={onDeleteRol} disabled={loading}>
<i class="bi bi-trash"></i> Eliminar
</button>
{/if}
{/if}
{#if tab === 1}
<button class="btn btn-primary" type="button" disabled={loading} on:click|preventDefault={onSavePermisos}>
<i class="bi bi-save"></i> Guardar Permisos Aplicaciones
</button>
{/if}
{#if tab === 2}
<button class="btn btn-primary" type="button" disabled={loading} on:click|preventDefault={onSaveLineas}>
<i class="bi bi-save"></i> Guardar Permisos Lineas
</button>
{/if}
{/if}
</svelte:fragment>
</Modal>
</form>

View File

@ -0,0 +1,40 @@
<script>
export let permisos = []
</script>
<table class="table">
<thead>
<tr>
<th>Aplicación</th>
<th>Vigente</th>
<th>Acceso</th>
<th>Solo Visualiza</th>
</tr>
</thead>
<tbody>
{#each permisos as app}
<tr>
<td>{app.nombre_app}</td>
<td>{app.vigente ? '✅' : '⛔'}</td>
<td>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id={`check-acceso-${app.id_aplicacion}`}
bind:checked={app.acceso}
on:change={() => app.modificado = true}
disabled={!app.vigente}>
<label class="form-check-label" for={`check-acceso-${app.id_aplicacion}`}>&nbsp;</label>
</div>
</td>
<td>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id={`check-solo-visualiza-${app.id_aplicacion}`}
bind:checked={app.solo_visualizar}
on:change={() => app.modificado = true}
disabled={!app.vigente || !app.acceso}>
<label class="form-check-label" for={`check-solo-visualiza-${app.id_aplicacion}`}>&nbsp;</label>
</div>
</td>
</tr>
{/each}
</tbody>
</table>

View File

@ -0,0 +1,19 @@
<script>
export let form = {}
export let escritura = false
</script>
<div class={"form" + (escritura ? '' : ' disabled')}>
<div class="row mb-3">
<div class="col-md-3">Rol ID</div>
<div class="col-md">
<input type="number" value={form.id_rol} disabled class="form-control" />
</div>
</div>
<div class="row mb-3">
<div class="col-md-3">Nombre Rol</div>
<div class="col-md">
<input type="text" bind:value={form.nombre_rol} required class="form-control" />
</div>
</div>
</div>

View File

@ -0,0 +1,33 @@
<script>
import TableResponsive from "$/components/TableResponsive.svelte";
export let permisos = []
</script>
<TableResponsive>
<thead>
<tr>
<th>Linea</th>
<th>Vigente</th>
<th>Visualiza</th>
</tr>
</thead>
<tbody>
{#each permisos as linea}
<tr>
<td>{linea.route_long_name}</td>
<td>{linea.vigente ? '✅' : '⛔'}</td>
<td>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch"
bind:checked={linea.acceso}
on:change={() => linea.modificado = true}
disabled={!linea.vigente}
id={`check-linea-${linea.id_linea}`}>
<label class="form-check-label" for={`check-linea-${linea.id_linea}`}>&nbsp;</label>
</div>
</td>
</tr>
{/each}
</tbody>
</TableResponsive>

View File

@ -0,0 +1,12 @@
.disabled { pointer-events: none !important; }
.mymodal { background-color: var(--bs-gray-200); }
.nav-tabs {
--bs-nav-tabs-border-color: var(--bs-white);
--bs-nav-tabs-border-width: 0;
}
.nav-tabs .nav-link.active {
--bs-nav-tabs-link-active-bg: var(--bs-white);
--bs-nav-tabs-link-active-color: var(--bs-secondary);
--bs-nav-tabs-link-active-border-color: var(--bs-white);
}

View File

@ -1,121 +0,0 @@
<script>
import Paginate from "$/components/Paginate.svelte";
import { getRolesaplicaciones , getRolesyaplicaciones } from "$/services/rolesyaplicaciones";
import PageTitle from "$/components/PageTitle.svelte";
import ModalRol from "./ModalRolaplicacion.svelte";
const limit = 15;
let page = 1;
let offset = 0;
let count = 0;
let ordering = 'id_rol'
let roles = []
let rol = null
let loading = false;
let data2 = []
$: onPage(page)
async function onPage(p) {
try {
loading = true
offset = (p - 1) * limit;
const data = await getRolesaplicaciones({ offset, limit, ordering })
data2= await getRolesyaplicaciones(1)
roles = data.results;
count = data.count;
} catch (error) {
alert(error)
} finally {
loading = false;
}
}
function onEdita(item) {
rol = item;
}
function onNuevo() {
rol = {}
}
function onOrderBy(field) {
ordering = ordering === field ? '-' + field : field;
onPage(page)
}
</script>
<PageTitle {loading}>rolesyaplicaciones</PageTitle>
<div>
{data2}
{#each data2 as rol}
{rol.id_rol}
{rol.id_aplicacion}
{/each}
</div>
<div class="card">
<div class="card-header">
<button class="btn btn-primary" on:click|preventDefault={onNuevo}>
<i class="bi bi-plus-lg"></i> Nuevo
</button>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-sm table-bordered">
<thead>
<tr class="table-light">
<th style="width:5%">Nro</th>
<th>
<a href={"#"} on:click|preventDefault={() => onOrderBy('id_aplicacion')}>ID rol</a>
{#if ordering === 'id_aplicacion'}<i class="bi bi-caret-up-fill"></i>{/if}
{#if ordering === '-id_aplicacion'}<i class="bi bi-caret-down-fill"></i>{/if}
</th>
<th>
<a href={"#"} on:click|preventDefault={() => onOrderBy('id_rol')}>Id app</a>
{#if ordering === 'id_rol'}<i class="bi bi-caret-up-fill"></i>{/if}
{#if ordering === '-id_rol'}<i class="bi bi-caret-down-fill"></i>{/if}
</th>
<th style="width:5%">Solo Visualizar</th>
</tr>
</thead>
<tbody>
{#each roles as app, index}
<tr>
<td class="table-light">{offset + index + 1}</td>
<td>{app.id_rol}</td>
<td><a href={"#"} on:click|preventDefault={() => onEdita(app)}>{app.id_aplicacion}</a></td>
<td>{app.solo_visualizar}</td>
</tr>
{/each}
</tbody>
</table>
</div>
</div>
<div class="card-footer d-flex">
<a href={"#"} class="btn btn-outline-secondary me-3" on:click|preventDefault={() => onPage(page)}>
<i class="bi bi-arrow-repeat"></i>
</a>
<Paginate
{offset}
{limit}
{count}
on:page={ev => page = ev.detail}
/>
</div>
</div>
{#if rol}
<ModalRol
{rol}
on:close={() => rol = null}
on:refresh={() => onPage(page)}
/>
{/if}
<style>
.table-responsive {
max-height: calc(100vh - 300px);
}
</style>

View File

@ -1,95 +0,0 @@
<script>
import Modal from "../../components/Modal.svelte";
import { getRolyaplicacion, createRolyaplicacion, updateRolyaplicacion, deleteRolyaplicacion } from "$/services/rolesyaplicaciones";
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();
export let rol = {}
let form = {}
let loading = false;
$: begin(rol.id_aplicacion)
async function begin(id) {
try {
if (!id) return;
form = await getRolyaplicacion(id) || {}
} catch (error) {
alert(error.detail || error)
}
}
async function onSave() {
try {
loading = true;
if (rol.id_aplicacion) {
form = await updateRolyaplicacion(form)
} else {
form = await createRolyaplicacion(form)
}
alert('Se ha guardado la aplicación')
dispatch('refresh')
dispatch('close')
} catch (error) {
if (error.detail) {
alert(error.detail)
} else {
alert(JSON.stringify(error))
}
} finally {
loading = false;
}
}
async function onDelete() {
try {
if (!confirm('Eliminará el registro?')) return;
loading = true;
await deleteRolyaplicacion(form.id_aplicacion)
alert('Se ha eliminado la aplicación')
dispatch('refresh')
dispatch('close')
} catch (error) {
alert(error.detail || error)
} finally {
loading = false;
}
}
</script>
<form action="" on:submit|preventDefault={onSave}>
<Modal title={'Aplicacion #' + (rol.id_aplicacion || 'Nuevo')}
size="lg"
on:close={() => dispatch('close')}>
<div class="form">
<div class="row mb-3">
<div class="col-md-3">ID app</div>
<div class="col-md">
{#if rol.id_aplicacion}
<input type="number" value={form.id_aplicacion} disabled class="form-control">
{:else}
<input type="number" bind:value={form.id_aplicacion} required class="form-control">
{/if}
</div>
</div>
<div class="row mb-3">
<div class="col-md-3">ID rol</div>
<div class="col-md">
<input type="text" bind:value={form.id_rol} required class="form-control">
</div>
</div>
<div class="mb-3">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" bind:checked={form.solo_visualizar} role="switch" id="vigente">
<label class="form-check-label" for="vigente">solo_visualizar</label>
</div>
</div>
</div>
<svelte:fragment slot="buttons">
<button class="btn btn-primary"type="submit" disabled={loading}>Guardar</button>
<button class="btn btn-danger" on:click|preventDefault={onDelete} disabled={loading}>Eliminar</button>
</svelte:fragment>
</Modal>
</form>

View File

@ -1,85 +1,94 @@
<script>
import { getPermisoPath } from "$/stores/global";
import IconLoading from "../../components/IconLoading.svelte";
import Modal from "../../components/Modal.svelte";
import Modal from "../../components/Modal.svelte";
import { createLetreroLUR, deleteLetreroLUR } from "../../services/letreros_lur";
import { createLinea, deleteLinea, updateLinea } from "../../services/lineas";
import { createLinea, updateLinea } from "../../services/lineas";
import FormRuta from "./FormRuta.svelte";
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher()
const dispatch = createEventDispatcher();
export let ruta = null;
let form = {}
let form = {};
let error_messages = null;
let loading = false
let loading = false;
let permiso_app = getPermisoPath();
$: form = { ...ruta }
$: form = { ...ruta };
async function onSave() {
try {
loading = true
error_messages = null
loading = true;
error_messages = null;
const { id_linea } = ruta;
const { route_short_name, route_long_name,
linea1, linea2, linea3, linea4,
bgcolor1, color1, bgcolor2, color2
} = form;
const { route_short_name, route_long_name, linea1, linea2, linea3, linea4, bgcolor1, color1, bgcolor2, color2, } = form;
if (id_linea) {
await updateLinea({ id_linea, route_short_name, route_long_name })
await updateLinea({ id_linea, route_short_name, route_long_name });
} else {
await createLinea({ route_short_name, route_long_name })
await createLinea({ route_short_name, route_long_name });
}
await deleteLetreroLUR(route_short_name).catch(() => {})
await deleteLetreroLUR(route_short_name).catch(() => {});
await createLetreroLUR({
codigo: route_short_name,
linea1, linea2, linea3, linea4,
bgcolor1, color1, bgcolor2, color2
})
dispatch('close')
linea1,
linea2,
linea3,
linea4,
bgcolor1,
color1,
bgcolor2,
color2,
});
dispatch("close");
} catch (error) {
const data = JSON.parse(error) || null
const data = JSON.parse(error) || null;
if (data) error_messages = data;
console.log({ data })
console.log({ data });
} finally {
loading = false
loading = false;
}
}
// async function onDelete() {
// try {
// const { id_linea, route_short_name } = ruta;
// await deleteLetreroLUR(route_short_name)
// await deleteLinea(id_linea)
// dispatch('close')
// } catch (error) {
// console.log({ error })
// }
// }
</script>
<form on:submit|preventDefault={onSave}>
<Modal title="Ruta de Servicio" size="xl"
on:close={() => dispatch('close')}
<Modal
title="Ruta de Servicio"
size="xl"
on:close={() => dispatch("close")}
>
<FormRuta {form} />
<div class={permiso_app.escritura ? "" : "disabled"}>
<FormRuta {form} />
</div>
{#if error_messages}
<div class="alert alert-danger">
<ul>
{#each Object.entries(error_messages) as [field, message]}
<li>{field}: {message[0]}</li>
<li>{field}: {message[0]}</li>
{/each}
</ul>
</div>
{/if}
<svelte:fragment slot="buttons">
<button class="btn btn-primary" type="submit" disabled={loading}><i class="bi bi-save"></i> Guardar</button>
<!-- {#if ruta.id_linea}
<button class="btn btn-danger" on:click|preventDefault={onDelete}><i class="bi bi-trash"></i> Eliminar</button>
{/if} -->
{#if permiso_app.escritura}
<button
class="btn btn-primary"
type="submit"
disabled={loading}
>
<i class="bi bi-save"></i> Guardar
</button>
{/if}
{#if loading}<IconLoading />{/if}
</svelte:fragment>
</Modal>
</form>
</form>
<style>
.disabled {
pointer-events: none !important;
}
</style>

View File

@ -93,7 +93,7 @@
</div>
<div class="card-footer">
<Paginate
forcePage={offset / limit}
forcePage={offset / limit + 1}
count={lineas.count}
{limit}
on:page={ev => offset = (ev.detail - 1) * limit}

View File

@ -3,11 +3,13 @@
import Paginate from '$/components/Paginate.svelte'
import PageTitle from '$/components/PageTitle.svelte'
import { getUsuarios } from '$/services/usuarios'
import { getPermisoPath } from '$/stores/global';
let usuarios = { count: 0, results: [] }
let page = 1
const limit = 15
let loading = false
let permiso_app = getPermisoPath()
$: onPage(page)
@ -29,9 +31,11 @@
<div class="card">
<div class="card-header">
<div class="mb-3 d-flex">
<Link to='/usuarios/nuevo' class="btn btn-primary">
<i class="bi bi-plus-lg"></i> Nuevo
</Link>
{#if permiso_app.escritura}
<Link to='/usuarios/nuevo' class="btn btn-primary">
<i class="bi bi-plus-lg"></i> Nuevo
</Link>
{/if}
<div class="m-auto"></div>
<Link to='/' class="btn btn-outline-secondary">Volver</Link>
</div>
@ -69,7 +73,7 @@
<i class="bi bi-arrow-repeat"></i>
</a>
<Paginate
offset={(page - 1) * limit}
forcePage={page}
{limit}
count={usuarios.count}
on:page={ev => page = ev.detail}

View File

@ -1,6 +1,6 @@
<script>
import { onMount } from 'svelte'
import { storeLayout } from '$/stores/global'
import { getPermisoPath, storeLayout } from '$/stores/global'
import PageTitle from '$/components/PageTitle.svelte';
import FormPersona from '../personas/Form.svelte'
import FormUsuario from './Form.svelte'
@ -22,6 +22,7 @@
let form_usuario = {}
let clave2 = ''
let loading = false;
let permiso_app = getPermisoPath()
$: es_nuevo = !$params.login
$: begin($params)
@ -74,11 +75,15 @@
<PageTitle {loading}>{es_nuevo ? 'Nuevo Usuario': 'Editar Usuario'}</PageTitle>
<form action="" on:submit|preventDefault={onSave}>
<form action="" on:submit|preventDefault={onSave} class={permiso_app.escritura ? '' : 'disabled'}>
<div class="card">
<div class="card-header d-flex">
<button type="submit" class="btn btn-primary"><i class="bi bi-save"></i> Guardar</button>
{#if !es_nuevo}
{#if permiso_app.escritura}
<button type="submit" class="btn btn-primary">
<i class="bi bi-save"></i> Guardar
</button>
{/if}
{#if !es_nuevo && permiso_app.escritura}
<button type="button" class="btn btn-danger ms-2"
on:click|preventDefault={onDelete}>
<i class="bi bi-trash"></i> Eliminar
@ -95,4 +100,8 @@
<FormUsuario bind:form={form_usuario} bind:clave2={clave2} {es_nuevo} />
</div>
</div>
</form>
</form>
<style>
.disabled { pointer-events: none !important; }
</style>

View File

@ -12,19 +12,19 @@ import PagePersonaModifica from '$/pages/personas/Persona.svelte'
import PageMapaParaderos from '$/pages/mapas/Paraderos.svelte'
import PageMapaRutas from '$/pages/mapas/Rutas.svelte'
import PageRoles from '$/pages/roles/Admin.svelte'
import PageRolesyAplicaciones from '$/pages/rolesaplicaciones/Admin.svelte'
import PageParaderos from '$/pages/paraderos/Home.svelte'
import PageRutas from "$/pages/rutas/Home.svelte";
import { getPermisosApp } from '$/services/usuarios'
import { storePermisos } from '$/stores/global'
export const routes = [
{ path: '/', component: PageHome },
{ path: '/perfil', component: PagePerfil },
export const routes_base = [
{ path: '/', component: PageHome, public: true },
{ path: '/perfil', component: PagePerfil, public: true },
{ path: '/aplicaciones', component: PageAplicaciones },
{ path: '/usuarios', component: PageUsuarios },
{ path: '/usuarios/nuevo', component: PageUsuarioCreate },
{ path: '/usuarios/:login', component: PageUsuarioModifica },
{ path: '/roles', component: PageRoles },
{ path: '/rolesaplicaciones', component: PageRolesyAplicaciones },
{ path: '/comunas', component: PageComunas },
{ path: '/personas', component: PagePersonas },
{ path: '/personas/nuevo', component: PagePersonaCreate },
@ -33,5 +33,21 @@ export const routes = [
{ path: '/mapas/rutas', component: PageMapaRutas },
{ path: '/paraderos', component: PageParaderos },
{ path: '/rutas', component: PageRutas },
{ path: '*', component: PageError },
]
{ path: '*', component: PageError, public: true },
];
export let routes = [];
export async function getRoutes() {
const permisos = await getPermisosApp()
const new_routes = routes_base.map(el => {
if (el.public) return el;
const permiso = permisos.aplicaciones.find(app => el.path.indexOf(app.path_app) === 0) || null;
return permiso ? { ...el, escritura: permiso.escritura } : null;
})
routes = new_routes.filter(el => el !== null)
storePermisos.set(routes.map(el => ({ path: el.path, escritura: el.escritura || false })))
return routes;
}

View File

@ -1,6 +1,6 @@
import { base, getToken } from "./_config";
export async function createToken({ username, password }) {
export async function createToken({ username=null, password=null }) {
const res = await fetch(`${base}/auth/`, {
method: 'POST',
body: JSON.stringify({ username, password }),

View File

@ -0,0 +1,30 @@
import { base, getToken } from './_config'
export async function getRolLineas(params) {
const query = !params ? '' : '?' + (new URLSearchParams(params).toString());
const res = await fetch(`${base}/roles-lineas/${query}`, {
headers: { "Authorization": `Bearer ${getToken()}`, "Content-Type": "application/json" }
})
if (!res.ok) throw await res.json()
return res.json()
}
export async function createRolLinea(data) {
const res = await fetch(`${base}/roles-lineas/`, {
method: 'POST',
body: JSON.stringify(data),
headers: { "Authorization": `Bearer ${getToken()}`, "Content-Type": "application/json" }
})
if (!res.ok) throw await res.json()
return res.json()
}
export async function deleteRolLinea(id) {
const res = await fetch(`${base}/roles-lineas/${id}/`, {
method: 'DELETE',
headers: { "Authorization": `Bearer ${getToken()}`, "Content-Type": "application/json" }
})
if (!res.ok) throw await res.json()
return res.text()
}

View File

@ -18,6 +18,15 @@ export async function getUsuario(id) {
return res.json()
}
export async function getPermisosApp() {
const res = await fetch(`${base}/usuarios/permisos/`, {
method: 'POST',
headers: { "Authorization": `Bearer ${getToken()}`, "Content-Type": "application/json" }
})
if (!res.ok) throw await res.text()
return res.json()
}
export async function createUsuario(data) {
const res = await fetch(`${base}/usuarios/`, {
method: 'POST',

View File

@ -1,4 +1,5 @@
import { writable } from 'svelte/store'
import { useLocation } from "svelte-navigator";
const cacheParaderos = JSON.parse(sessionStorage.getItem('cache-paraderos') || 'null') || null;
@ -6,5 +7,14 @@ export const storeMessages = writable([]);
export const storeParaderos = writable(cacheParaderos);
export const storeSession = writable({});
export const storeLayout = writable({ showSidebar: true });
export const storePermisos = writable([]);
storeParaderos.subscribe(val => sessionStorage.setItem('cache-paraderos', JSON.stringify(val)))
storeParaderos.subscribe(val => sessionStorage.setItem('cache-paraderos', JSON.stringify(val)))
export function getPermisoPath(path = null) {
let location = useLocation()
let pathname = null
location.subscribe(val => pathname = val.pathname)
return { escritura: true };
}