ADD: Breadcrum y modals
- FIX: Token de sesión movido a localStorage - UPDATE: Dependencias - UPDATE: Funcionamiento de los modals - ADD: Breadcrumbs
This commit is contained in:
parent
c3965ef4cf
commit
c453697d4e
887
package-lock.json
generated
887
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@
|
|||||||
"name": "notsoweb.frontend",
|
"name": "notsoweb.frontend",
|
||||||
"copyright": "Notsoweb Software Inc.",
|
"copyright": "Notsoweb Software Inc.",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.9.10",
|
"version": "0.9.12",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
5
src/components/Holos/Breadcrumb/Container.vue
Normal file
5
src/components/Holos/Breadcrumb/Container.vue
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<template>
|
||||||
|
<nav class="flex items-center py-1 gap-0.5">
|
||||||
|
<slot />
|
||||||
|
</nav>
|
||||||
|
</template>
|
||||||
55
src/components/Holos/Breadcrumb/Item.vue
Normal file
55
src/components/Holos/Breadcrumb/Item.vue
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<script setup>
|
||||||
|
import GoogleIcon from '@Shared/GoogleIcon.vue'
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
/** Definidores */
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
/** Propiedades */
|
||||||
|
const props = defineProps({
|
||||||
|
name: String,
|
||||||
|
icon: String,
|
||||||
|
route: Object,
|
||||||
|
active: Boolean,
|
||||||
|
})
|
||||||
|
|
||||||
|
/** Métodos */
|
||||||
|
const handleClick = () => {
|
||||||
|
if (props.active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
router.push(props.route);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<button
|
||||||
|
v-if="!active"
|
||||||
|
:to="route"
|
||||||
|
class="inline-flex items-center gap-1.5 text-sm duration-300 ease-in p-1 cursor-pointer"
|
||||||
|
@click="handleClick"
|
||||||
|
>
|
||||||
|
<GoogleIcon
|
||||||
|
:name="icon"
|
||||||
|
class="text-sm"
|
||||||
|
/>
|
||||||
|
<span class="text-sm font-semibold hover:underline" v-text="name" />
|
||||||
|
</button>
|
||||||
|
<span v-if="!active" class="inline-block text-sm select-none pointer-events-none opacity-50">
|
||||||
|
<GoogleIcon
|
||||||
|
name="arrow_forward_ios"
|
||||||
|
class="text-xs font-semibold"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
v-if="active"
|
||||||
|
class="inline-flex items-center gap-1.5 text-sm duration-300 ease-in p-1"
|
||||||
|
>
|
||||||
|
<GoogleIcon
|
||||||
|
:name="icon"
|
||||||
|
class="text-sm"
|
||||||
|
/>
|
||||||
|
<span class="font-semibold text-sm underline" v-text="name" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
13
src/components/Holos/Breadcrumb/Separator.vue
Normal file
13
src/components/Holos/Breadcrumb/Separator.vue
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<script setup>
|
||||||
|
import GoogleIcon from '@Shared/GoogleIcon.vue'
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<span class="inline-block mx-1 text-sm select-none pointer-events-none opacity-50">
|
||||||
|
<GoogleIcon
|
||||||
|
name="arrow_forward_ios"
|
||||||
|
class="text-xs font-semibold"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
@ -1,9 +1,9 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, nextTick } from 'vue';
|
import { ref, nextTick } from 'vue';
|
||||||
import { api, useForm } from '@Services/Api';
|
import { useForm } from '@Services/Api';
|
||||||
|
|
||||||
import Input from './Form/Input.vue';
|
import Input from './Form/Input.vue';
|
||||||
import DialogModal from './DialogModal.vue';
|
import DialogModal from './Modal/Elements/Base.vue';
|
||||||
import PrimaryButton from './Button/Primary.vue';
|
import PrimaryButton from './Button/Primary.vue';
|
||||||
import SecondaryButton from './Button/Secondary.vue';
|
import SecondaryButton from './Button/Secondary.vue';
|
||||||
|
|
||||||
|
|||||||
@ -1,45 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import Modal from './Modal.vue';
|
|
||||||
|
|
||||||
const emit = defineEmits(['close']);
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
show: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
maxWidth: {
|
|
||||||
type: String,
|
|
||||||
default: '2xl',
|
|
||||||
},
|
|
||||||
closeable: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const close = () => {
|
|
||||||
emit('close');
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<Modal
|
|
||||||
:show="show"
|
|
||||||
:max-width="maxWidth"
|
|
||||||
:closeable="closeable"
|
|
||||||
@close="close"
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<div class="text-lg px-4 font-medium">
|
|
||||||
<slot name="title" />
|
|
||||||
</div>
|
|
||||||
<div class="text-sm">
|
|
||||||
<slot name="content" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-row justify-center p-2 text-end">
|
|
||||||
<slot name="footer" />
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</template>
|
|
||||||
@ -1,7 +1,9 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
import ModalBase from './Elements/Base.vue';
|
||||||
import DangerButton from '../Button/Danger.vue';
|
import DangerButton from '../Button/Danger.vue';
|
||||||
import SecondaryButton from '../Button/Secondary.vue';
|
import SecondaryButton from '../Button/Secondary.vue';
|
||||||
import DialogModal from '../DialogModal.vue';
|
|
||||||
|
|
||||||
/** Eventos */
|
/** Eventos */
|
||||||
defineEmits([
|
defineEmits([
|
||||||
@ -11,16 +13,27 @@ defineEmits([
|
|||||||
|
|
||||||
/** Propiedades */
|
/** Propiedades */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
show: Boolean,
|
|
||||||
title: {
|
title: {
|
||||||
default: Lang('delete.title'),
|
default: Lang('delete.title'),
|
||||||
type: String
|
type: String
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** Referencias */
|
||||||
|
const modalRef = ref(null);
|
||||||
|
|
||||||
|
/** Exposiciones */
|
||||||
|
defineExpose({
|
||||||
|
open: () => modalRef.value.open(),
|
||||||
|
close: () => modalRef.value.close()
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<DialogModal :show="show">
|
<ModalBase
|
||||||
|
ref="modalRef"
|
||||||
|
@close="$emit('close')"
|
||||||
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
<p
|
<p
|
||||||
class="font-bold text-xl"
|
class="font-bold text-xl"
|
||||||
@ -49,9 +62,9 @@ const props = defineProps({
|
|||||||
/>
|
/>
|
||||||
<SecondaryButton
|
<SecondaryButton
|
||||||
v-text="$t('cancel')"
|
v-text="$t('cancel')"
|
||||||
@click="$emit('close')"
|
@click="modalRef.close()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</DialogModal>
|
</ModalBase>
|
||||||
</template>
|
</template>
|
||||||
@ -1,51 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import PrimaryButton from '../Button/Primary.vue';
|
|
||||||
import SecondaryButton from '../Button/Secondary.vue';
|
|
||||||
import DialogModal from '../DialogModal.vue';
|
|
||||||
|
|
||||||
/** Eventos */
|
|
||||||
const emit = defineEmits([
|
|
||||||
'close',
|
|
||||||
'update'
|
|
||||||
]);
|
|
||||||
|
|
||||||
/** Propiedades */
|
|
||||||
const props = defineProps({
|
|
||||||
show: Boolean,
|
|
||||||
title: {
|
|
||||||
default: Lang('edit'),
|
|
||||||
type: String
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<DialogModal :show="show">
|
|
||||||
<template #title>
|
|
||||||
<p
|
|
||||||
class="font-bold text-xl"
|
|
||||||
v-text="title"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<template #content>
|
|
||||||
<div class="w-full right-0">
|
|
||||||
<div class="overflow-hidden shadow-lg">
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #footer>
|
|
||||||
<div class="space-x-2">
|
|
||||||
<slot name="buttons" />
|
|
||||||
<PrimaryButton
|
|
||||||
v-text="$t('update')"
|
|
||||||
@click="$emit('update')"
|
|
||||||
/>
|
|
||||||
<SecondaryButton
|
|
||||||
v-text="$t('close')"
|
|
||||||
@click="$emit('close')"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</DialogModal>
|
|
||||||
</template>
|
|
||||||
@ -1,40 +1,20 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed, onMounted, onUnmounted, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
|
|
||||||
/** Eventos */
|
/** Eventos */
|
||||||
const emit = defineEmits([
|
const emit = defineEmits(['close']);
|
||||||
'close'
|
|
||||||
]);
|
|
||||||
|
|
||||||
/** Propiedades */
|
/** Propiedades */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
closeable: {
|
|
||||||
default: true,
|
|
||||||
type: Boolean
|
|
||||||
},
|
|
||||||
maxWidth: {
|
maxWidth: {
|
||||||
default: '2xl',
|
default: '2xl',
|
||||||
type: String
|
type: String
|
||||||
},
|
}
|
||||||
show: {
|
|
||||||
default: false,
|
|
||||||
type: Boolean
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const show = ref(false);
|
||||||
|
|
||||||
/** Métodos */
|
/** Métodos */
|
||||||
const close = () => {
|
|
||||||
if (props.closeable) {
|
|
||||||
emit('close');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const closeOnEscape = (e) => {
|
|
||||||
if (e.key === 'Escape' && props.show) {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const maxWidthClass = computed(() => {
|
const maxWidthClass = computed(() => {
|
||||||
return {
|
return {
|
||||||
'sm': 'sm:max-w-sm',
|
'sm': 'sm:max-w-sm',
|
||||||
@ -42,29 +22,45 @@ const maxWidthClass = computed(() => {
|
|||||||
'lg': 'sm:max-w-lg',
|
'lg': 'sm:max-w-lg',
|
||||||
'xl': 'sm:max-w-xl',
|
'xl': 'sm:max-w-xl',
|
||||||
'2xl': 'sm:max-w-2xl',
|
'2xl': 'sm:max-w-2xl',
|
||||||
|
'3xl': 'sm:max-w-3xl',
|
||||||
|
'4xl': 'sm:max-w-4xl',
|
||||||
|
'5xl': 'sm:max-w-5xl',
|
||||||
|
'6xl': 'sm:max-w-6xl',
|
||||||
|
'7xl': 'sm:max-w-7xl',
|
||||||
}[props.maxWidth];
|
}[props.maxWidth];
|
||||||
});
|
});
|
||||||
|
|
||||||
/** Observadores */
|
/** Observadores */
|
||||||
watch(() => props.show, () => {
|
watch(() => show, () => {
|
||||||
if (props.show) {
|
if (show.value) {
|
||||||
document.body.style.overflow = 'hidden';
|
document.body.style.overflow = 'hidden';
|
||||||
} else {
|
} else {
|
||||||
document.body.style.overflow = null;
|
document.body.style.overflow = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/** Ciclos */
|
/** Exposiciones */
|
||||||
onMounted(() => document.addEventListener('keydown', closeOnEscape));
|
defineExpose({
|
||||||
|
open: () => show.value = true,
|
||||||
onUnmounted(() => {
|
close: () => {
|
||||||
document.removeEventListener('keydown', closeOnEscape);
|
show.value = false;
|
||||||
document.body.style.overflow = null;
|
emit('close');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<teleport to="body">
|
<teleport to="body">
|
||||||
|
<transition
|
||||||
|
enter-active-class="ease-out duration-300"
|
||||||
|
enter-from-class="opacity-0"
|
||||||
|
enter-to-class="opacity-100"
|
||||||
|
leave-active-class="ease-in duration-300"
|
||||||
|
leave-from-class="opacity-100"
|
||||||
|
leave-to-class="opacity-0"
|
||||||
|
>
|
||||||
|
<div v-show="show" class="fixed inset-0 overflow-y-auto px-4 py-6 sm:px-0 bg-primary/50 z-50 transition-all"></div>
|
||||||
|
</transition>
|
||||||
<transition
|
<transition
|
||||||
enter-active-class="ease-out duration-300"
|
enter-active-class="ease-out duration-300"
|
||||||
enter-from-class="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
enter-from-class="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
@ -73,13 +69,23 @@ onUnmounted(() => {
|
|||||||
leave-from-class="opacity-100 translate-y-0 sm:scale-100"
|
leave-from-class="opacity-100 translate-y-0 sm:scale-100"
|
||||||
leave-to-class="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
leave-to-class="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
>
|
>
|
||||||
<div v-show="show" class="fixed inset-0 overflow-y-auto px-4 py-6 sm:px-0 bg-primary/90 z-50 transition-all" scroll-region>
|
<div v-show="show" class="fixed inset-0 overflow-y-auto px-4 py-6 sm:px-0 z-50 transition-all" scroll-region>
|
||||||
<div
|
<div
|
||||||
v-show="show"
|
v-show="show"
|
||||||
class="mb-6 bg-page text-page-t dark:bg-page-d dark:text-page-dt rounded-sm overflow-hidden shadow-xl transform transition-all sm:w-full sm:mx-auto"
|
class="mb-6 bg-page text-page-t dark:bg-page-d dark:text-page-dt rounded-sm overflow-hidden shadow-xl transform transition-all sm:w-full sm:mx-auto"
|
||||||
:class="maxWidthClass"
|
:class="maxWidthClass"
|
||||||
>
|
>
|
||||||
<slot v-if="show" />
|
<div class="flex flex-col">
|
||||||
|
<div class="text-lg px-4 font-medium">
|
||||||
|
<slot name="title" />
|
||||||
|
</div>
|
||||||
|
<div class="text-sm">
|
||||||
|
<slot name="content" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-row justify-center p-2 text-end">
|
||||||
|
<slot name="footer" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
@ -1,24 +1,32 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
import ModalBase from './Elements/Base.vue';
|
||||||
import SecondaryButton from '../Button/Secondary.vue';
|
import SecondaryButton from '../Button/Secondary.vue';
|
||||||
import PrimaryButton from '../Button/Primary.vue';
|
|
||||||
import DialogModal from '../DialogModal.vue';
|
|
||||||
|
|
||||||
/** Eventos */
|
/** Eventos */
|
||||||
const emit = defineEmits([
|
const emit = defineEmits(['close']);
|
||||||
'close',
|
|
||||||
'edit'
|
|
||||||
]);
|
|
||||||
|
|
||||||
/** Propiedades */
|
/** Propiedades */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
editable: Boolean,
|
|
||||||
show: Boolean,
|
|
||||||
title: String
|
title: String
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** Referencias */
|
||||||
|
const modalRef = ref(null);
|
||||||
|
|
||||||
|
/** Exposiciones */
|
||||||
|
defineExpose({
|
||||||
|
open: () => modalRef.value.open(),
|
||||||
|
close: () => modalRef.value.close()
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<DialogModal :show="show">
|
<ModalBase
|
||||||
|
ref="modalRef"
|
||||||
|
@close="emit('close')"
|
||||||
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
<p
|
<p
|
||||||
class="font-bold text-xl"
|
class="font-bold text-xl"
|
||||||
@ -35,15 +43,11 @@ const props = defineProps({
|
|||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="space-x-2">
|
<div class="space-x-2">
|
||||||
<slot name="buttons" />
|
<slot name="buttons" />
|
||||||
<PrimaryButton v-if="editable"
|
|
||||||
v-text="$t('update')"
|
|
||||||
@click="$emit('edit')"
|
|
||||||
/>
|
|
||||||
<SecondaryButton
|
<SecondaryButton
|
||||||
v-text="$t('close')"
|
v-text="$t('close')"
|
||||||
@click="$emit('close')"
|
@click="modalRef.close()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</DialogModal>
|
</ModalBase>
|
||||||
</template>
|
</template>
|
||||||
@ -1,4 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
import { api } from '@Services/Api.js';
|
import { api } from '@Services/Api.js';
|
||||||
|
|
||||||
import DestroyModal from '../Destroy.vue';
|
import DestroyModal from '../Destroy.vue';
|
||||||
@ -6,14 +7,13 @@ import Header from '../Elements/Header.vue';
|
|||||||
|
|
||||||
/** Eventos */
|
/** Eventos */
|
||||||
const emit = defineEmits([
|
const emit = defineEmits([
|
||||||
|
'open',
|
||||||
'close',
|
'close',
|
||||||
'update'
|
'update'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/** Propiedades */
|
/** Propiedades */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
model: Object,
|
|
||||||
show: Boolean,
|
|
||||||
to: Function,
|
to: Function,
|
||||||
title: {
|
title: {
|
||||||
type: String,
|
type: String,
|
||||||
@ -25,25 +25,41 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const model = ref({});
|
||||||
|
const modalRef = ref(null);
|
||||||
|
|
||||||
/** Métodos */
|
/** Métodos */
|
||||||
const destroy = (id) => api.delete(props.to(id), {
|
const destroy = () => {
|
||||||
onSuccess: () => {
|
api.delete(props.to(model.value.id), {
|
||||||
Notify.success(Lang('deleted'));
|
onSuccess: () => {
|
||||||
emit('close');
|
Notify.success(Lang('deleted'));
|
||||||
emit('update');
|
emit('update');
|
||||||
},
|
},
|
||||||
onError: () => {
|
onError: () => {
|
||||||
Notify.info(Lang('notFound'));
|
Notify.info(Lang('notFound'));
|
||||||
emit('close');
|
},
|
||||||
|
onFinish: () => {
|
||||||
|
modalRef.value.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Exposiciones */
|
||||||
|
defineExpose({
|
||||||
|
open: (modelData) => {
|
||||||
|
model.value = modelData;
|
||||||
|
modalRef.value.open();
|
||||||
|
|
||||||
|
emit('open')
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<DestroyModal
|
<DestroyModal
|
||||||
:show="show"
|
ref="modalRef"
|
||||||
@close="$emit('close')"
|
@close="$emit('close')"
|
||||||
@destroy="destroy(model.id)"
|
@destroy="destroy"
|
||||||
>
|
>
|
||||||
<Header
|
<Header
|
||||||
:title="model[title]"
|
:title="model[title]"
|
||||||
|
|||||||
@ -1,32 +1,46 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { RouterLink } from 'vue-router';
|
import { RouterLink, useRoute } from 'vue-router';
|
||||||
|
import { breadcrumbItem, breadcrumbMeta } from '@Controllers/BreadcrumbController.js';
|
||||||
|
|
||||||
import IconButton from '@Holos/Button/Icon.vue'
|
import IconButton from '@Holos/Button/Icon.vue'
|
||||||
|
import BreadcrumbContainer from '@Holos/Breadcrumb/Container.vue'
|
||||||
|
import BreadcrumbItem from '@Holos/Breadcrumb/Item.vue'
|
||||||
|
|
||||||
defineProps({
|
/** Definidores */
|
||||||
|
const vroute = useRoute();
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
title: String
|
title: String
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const breadcrumbs = breadcrumbMeta(vroute);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="title" class="flex w-full justify-center">
|
<div>
|
||||||
<h2
|
<BreadcrumbContainer>
|
||||||
class="font-bold text-xl uppercase"
|
<template v-for="(item, index) in breadcrumbs" :key="item.name">
|
||||||
v-text="title"
|
<BreadcrumbItem
|
||||||
/>
|
:name="item.name"
|
||||||
</div>
|
:icon="item.icon"
|
||||||
<div class="flex w-full justify-end py-[0.31rem] mb-2 border-y-2 border-page-t dark:border-page-dt">
|
:route="item.route"
|
||||||
<div id="buttons" class="flex items-center space-x-1 text-sm">
|
:active="index === breadcrumbs.length - 1"
|
||||||
<slot />
|
|
||||||
<RouterLink :to="$view({ name: 'index' })">
|
|
||||||
<IconButton
|
|
||||||
:title="$t('home')"
|
|
||||||
class="text-white"
|
|
||||||
icon="home"
|
|
||||||
filled
|
|
||||||
/>
|
/>
|
||||||
</RouterLink>
|
</template>
|
||||||
|
</BreadcrumbContainer>
|
||||||
|
<div class="flex w-full justify-end py-[0.31rem] mb-2 border-y-2 border-page-t dark:border-page-dt">
|
||||||
|
<div id="buttons" class="flex items-center space-x-1 text-sm">
|
||||||
|
<slot />
|
||||||
|
<RouterLink :to="$view({ name: 'index' })">
|
||||||
|
<IconButton
|
||||||
|
:title="$t('home')"
|
||||||
|
class="text-white"
|
||||||
|
icon="refresh"
|
||||||
|
filled
|
||||||
|
/>
|
||||||
|
</RouterLink>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -1,8 +1,15 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
import { breadcrumbMeta } from '@Controllers/BreadcrumbController.js';
|
||||||
|
|
||||||
import IconButton from '@Holos/Button/Icon.vue'
|
import IconButton from '@Holos/Button/Icon.vue'
|
||||||
import GoogleIcon from '@Shared/GoogleIcon.vue';
|
import GoogleIcon from '@Shared/GoogleIcon.vue';
|
||||||
|
import BreadcrumbContainer from '@Holos/Breadcrumb/Container.vue'
|
||||||
|
import BreadcrumbItem from '@Holos/Breadcrumb/Item.vue'
|
||||||
|
|
||||||
|
/** Definidores */
|
||||||
|
const vroute = useRoute();
|
||||||
|
|
||||||
/** Eventos */
|
/** Eventos */
|
||||||
const emit = defineEmits([
|
const emit = defineEmits([
|
||||||
@ -18,6 +25,7 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const breadcrumbs = breadcrumbMeta(vroute);
|
||||||
const query = ref('');
|
const query = ref('');
|
||||||
|
|
||||||
/** Métodos */
|
/** Métodos */
|
||||||
@ -30,14 +38,20 @@ const clear = () => {
|
|||||||
|
|
||||||
search();
|
search();
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="title" class="flex w-full justify-center">
|
<BreadcrumbContainer>
|
||||||
<h2
|
<template v-for="(item, index) in breadcrumbs" :key="item.name">
|
||||||
class="font-bold text-xl uppercase"
|
<BreadcrumbItem
|
||||||
v-text="title"
|
:name="item.name"
|
||||||
/>
|
:icon="item.icon"
|
||||||
</div>
|
:route="item.route"
|
||||||
|
:active="index === breadcrumbs.length - 1"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</BreadcrumbContainer>
|
||||||
<div class="flex w-full justify-between items-center border-y-2 border-page-t dark:border-page-dt">
|
<div class="flex w-full justify-between items-center border-y-2 border-page-t dark:border-page-dt">
|
||||||
<div>
|
<div>
|
||||||
<div class="relative py-1 z-0">
|
<div class="relative py-1 z-0">
|
||||||
|
|||||||
@ -4,30 +4,24 @@ import { RouterLink } from 'vue-router';
|
|||||||
import useNotificationSidebar from '@Stores/NotificationSidebar'
|
import useNotificationSidebar from '@Stores/NotificationSidebar'
|
||||||
import useNotifier from '@Stores/Notifier'
|
import useNotifier from '@Stores/Notifier'
|
||||||
|
|
||||||
import ModalController from '@Controllers/ModalController.js';
|
|
||||||
|
|
||||||
import GoogleIcon from '@Shared/GoogleIcon.vue';
|
import GoogleIcon from '@Shared/GoogleIcon.vue';
|
||||||
import Item from './Notification/Item.vue';
|
|
||||||
import PrimaryButton from '@Holos/Button/Primary.vue';
|
import PrimaryButton from '@Holos/Button/Primary.vue';
|
||||||
import ShowView from '@Holos/Skeleton/Sidebar/Notification/Show.vue';
|
import ShowModal from './Notification/Show.vue';
|
||||||
|
import Item from './Notification/Item.vue';
|
||||||
|
|
||||||
|
/** Eventos */
|
||||||
|
const emit = defineEmits(['open']);
|
||||||
|
|
||||||
/** Definidores */
|
/** Definidores */
|
||||||
const notifier = useNotifier();
|
const notifier = useNotifier();
|
||||||
const notificationSidebar = useNotificationSidebar()
|
const notificationSidebar = useNotificationSidebar()
|
||||||
|
|
||||||
/** Controladores */
|
|
||||||
const Modal = new ModalController();
|
|
||||||
|
|
||||||
/** Eventos */
|
|
||||||
const emit = defineEmits(['open']);
|
|
||||||
|
|
||||||
/** Propiedades */
|
/** Propiedades */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
sidebar: Boolean
|
sidebar: Boolean
|
||||||
});
|
});
|
||||||
|
|
||||||
const showModal = ref(Modal.showModal);
|
const showModal = ref(false);
|
||||||
const modelModal = ref(Modal.modelModal);
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -68,7 +62,7 @@ const modelModal = ref(Modal.modelModal);
|
|||||||
<Item v-for="notification in notifier.notifications"
|
<Item v-for="notification in notifier.notifications"
|
||||||
:key="notification.id"
|
:key="notification.id"
|
||||||
:notification="notification"
|
:notification="notification"
|
||||||
@openModal="Modal.switchShowModal(notification)"
|
@openModal="showModal.open(notification)"
|
||||||
/>
|
/>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -83,10 +77,8 @@ const modelModal = ref(Modal.modelModal);
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<ShowView
|
<ShowModal
|
||||||
:show="showModal"
|
ref="showModal"
|
||||||
:model="modelModal"
|
|
||||||
@close="Modal.switchShowModal"
|
|
||||||
@reload="notifier.getUpdates()"
|
@reload="notifier.getUpdates()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed, nextTick, onUpdated } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { getDateTime } from '@Controllers/DateController';
|
import { getDateTime } from '@Controllers/DateController';
|
||||||
import useNotifier from '@Stores/Notifier';
|
import useNotifier from '@Stores/Notifier';
|
||||||
|
|
||||||
@ -17,28 +17,34 @@ const emit = defineEmits([
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
/** Propiedades */
|
/** Propiedades */
|
||||||
const props = defineProps({
|
const modalRef = ref(null);
|
||||||
show: Boolean,
|
const model = ref({});
|
||||||
model: Object
|
|
||||||
});
|
|
||||||
|
|
||||||
onUpdated(() => {
|
/** Métodos */
|
||||||
if(!props.model.read_at && props.show) {
|
function readNotification() {
|
||||||
notifier.readNotification(props.model.id);
|
if(!model.value.read_at) {
|
||||||
|
notifier.readNotification(model.value.id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(!props.model.read_at && !props.show) {
|
/** Exposiciones */
|
||||||
emit('reload');
|
defineExpose({
|
||||||
|
open: (data) => {
|
||||||
|
model.value = data;
|
||||||
|
modalRef.value.open();
|
||||||
|
readNotification();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ShowModal
|
<ShowModal
|
||||||
:show="show"
|
ref="modalRef"
|
||||||
@close="$emit('close')"
|
:title="$t('notification')"
|
||||||
|
@close="$emit('reload')"
|
||||||
>
|
>
|
||||||
<Header
|
<Header
|
||||||
:title="model.data.title"
|
:title="model.data?.title"
|
||||||
>
|
>
|
||||||
</Header>
|
</Header>
|
||||||
<div class="py-2 border-b">
|
<div class="py-2 border-b">
|
||||||
@ -53,11 +59,11 @@ onUpdated(() => {
|
|||||||
</p>
|
</p>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<b>{{ $t('description') }}: </b>
|
<b>{{ $t('description') }}: </b>
|
||||||
{{ model.data.description }}
|
{{ model.data?.description }}
|
||||||
</div>
|
</div>
|
||||||
<div v-if="model.data.message" class="flex flex-col">
|
<div v-if="model.data?.message" class="flex flex-col">
|
||||||
<b>{{ $t('message') }}: </b>
|
<b>{{ $t('message') }}: </b>
|
||||||
{{ model.data.message }}
|
{{ model.data?.message }}
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
<b>{{ $t('created_at') }}: </b>
|
<b>{{ $t('created_at') }}: </b>
|
||||||
|
|||||||
19
src/controllers/BreadcrumbController.js
Normal file
19
src/controllers/BreadcrumbController.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/** Breadcrumb */
|
||||||
|
const breadcrumbItem = (name, icon, route = {name:'index'}) => ({ name, icon, route })
|
||||||
|
|
||||||
|
const breadcrumbMeta = (route) => {
|
||||||
|
let breadcrumbs = [];
|
||||||
|
|
||||||
|
route.matched.forEach(match => {
|
||||||
|
if(match.name && match.meta?.title) {
|
||||||
|
breadcrumbs.push(breadcrumbItem(match.meta.title, match.meta.icon, {name: match.name}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return breadcrumbs;
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
breadcrumbItem,
|
||||||
|
breadcrumbMeta,
|
||||||
|
}
|
||||||
@ -1,92 +0,0 @@
|
|||||||
import { ref } from 'vue';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controlador simple de las bandejas
|
|
||||||
*/
|
|
||||||
class ModalController
|
|
||||||
{
|
|
||||||
// Modals
|
|
||||||
confirmModal = ref(false);
|
|
||||||
destroyModal = ref(false);
|
|
||||||
editModal = ref(false);
|
|
||||||
noteModal = ref(false);
|
|
||||||
manyNotesModal = ref(false);
|
|
||||||
showModal = ref(false);
|
|
||||||
importModal = ref(false);
|
|
||||||
|
|
||||||
// Models
|
|
||||||
modelModal = ref({});
|
|
||||||
|
|
||||||
constructor() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controla el cambio entre show y edit
|
|
||||||
*/
|
|
||||||
switchShowEditModal = () => {
|
|
||||||
this.showModal.value = !this.showModal.value
|
|
||||||
this.editModal.value = !this.editModal.value
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controla el switch de eliminar
|
|
||||||
*/
|
|
||||||
switchShowModal = (model) => {
|
|
||||||
this._setModel(model);
|
|
||||||
this.showModal.value = !this.showModal.value
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controla el switch de importar
|
|
||||||
*/
|
|
||||||
switchImportModal = () => {
|
|
||||||
this.importModal.value = !this.importModal.value
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controla el switch de eliminar
|
|
||||||
*/
|
|
||||||
switchEditModal = (model) => {
|
|
||||||
this._setModel(model);
|
|
||||||
this.editModal.value = !this.editModal.value
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controla el switch de eliminar
|
|
||||||
*/
|
|
||||||
switchDestroyModal = (model) => {
|
|
||||||
this._setModel(model);
|
|
||||||
this.destroyModal.value = !this.destroyModal.value
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controla el switch de nota
|
|
||||||
*/
|
|
||||||
switchNoteModal = () => {
|
|
||||||
this.noteModal.value = !this.noteModal.value
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controla el switch de notas aplicadas a muchos
|
|
||||||
*/
|
|
||||||
switchManyNotesModal = () => {
|
|
||||||
this.manyNotesModal.value = !this.manyNotesModal.value
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controla el switch de nota
|
|
||||||
*/
|
|
||||||
switchConfirmModal = () => {
|
|
||||||
this.confirmModal.value = !this.confirmModal.value
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Guarda el modelo
|
|
||||||
*/
|
|
||||||
_setModel = (model) => {
|
|
||||||
if(model) {
|
|
||||||
this.modelModal.value = model;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ModalController;
|
|
||||||
@ -5,8 +5,6 @@ import { hasPermission } from '@Plugins/RolePermission';
|
|||||||
import { useSearcher } from '@Services/Api';
|
import { useSearcher } from '@Services/Api';
|
||||||
import { apiTo, transl } from './Module';
|
import { apiTo, transl } from './Module';
|
||||||
|
|
||||||
import ModalController from '@Controllers/ModalController.js';
|
|
||||||
|
|
||||||
import IconButton from '@Holos/Button/Icon.vue'
|
import IconButton from '@Holos/Button/Icon.vue'
|
||||||
import PrimaryButton from '@Holos/Button/Primary.vue';
|
import PrimaryButton from '@Holos/Button/Primary.vue';
|
||||||
import Input from '@Holos/Form/Input.vue';
|
import Input from '@Holos/Form/Input.vue';
|
||||||
@ -19,13 +17,7 @@ import ShowView from './Modals/Event.vue';
|
|||||||
const vroute = useRoute();
|
const vroute = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
/** Controladores */
|
|
||||||
const Modal = new ModalController();
|
|
||||||
|
|
||||||
/** Propiedades */
|
/** Propiedades */
|
||||||
const showModal = ref(Modal.showModal);
|
|
||||||
const modelModal = ref(Modal.modelModal);
|
|
||||||
|
|
||||||
const models = ref([]);
|
const models = ref([]);
|
||||||
|
|
||||||
const filters = reactive({
|
const filters = reactive({
|
||||||
@ -35,6 +27,9 @@ const filters = reactive({
|
|||||||
user: ''
|
user: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** Referencias */
|
||||||
|
const showModal = ref(null);
|
||||||
|
|
||||||
/** Métodos */
|
/** Métodos */
|
||||||
const searcher = useSearcher({
|
const searcher = useSearcher({
|
||||||
url: apiTo('index'),
|
url: apiTo('index'),
|
||||||
@ -133,7 +128,7 @@ onMounted(() => {
|
|||||||
<template v-for="event in items">
|
<template v-for="event in items">
|
||||||
<Item
|
<Item
|
||||||
:event="event"
|
:event="event"
|
||||||
@show="Modal.switchShowModal(event)"
|
@show="showModal.open(event)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</ol>
|
</ol>
|
||||||
@ -141,11 +136,9 @@ onMounted(() => {
|
|||||||
</Paginable>
|
</Paginable>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ShowView
|
<ShowView
|
||||||
:show="showModal"
|
ref="showModal"
|
||||||
:model="modelModal"
|
/>
|
||||||
@close="Modal.switchShowModal"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -1,4 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
import { getDateTime } from '@Controllers/DateController';
|
import { getDateTime } from '@Controllers/DateController';
|
||||||
|
|
||||||
import Header from '@Holos/Modal/Elements/Header.vue';
|
import Header from '@Holos/Modal/Elements/Header.vue';
|
||||||
@ -11,47 +12,64 @@ defineEmits([
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
/** Propiedades */
|
/** Propiedades */
|
||||||
defineProps({
|
const model = ref(null);
|
||||||
show: Boolean,
|
|
||||||
model: Object
|
/** Referencias */
|
||||||
|
const modalRef = ref(null);
|
||||||
|
|
||||||
|
/** Métodos */
|
||||||
|
function close() {
|
||||||
|
model.value = null;
|
||||||
|
|
||||||
|
emit('close');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Exposiciones */
|
||||||
|
defineExpose({
|
||||||
|
open: (data) => {
|
||||||
|
model.value = data;
|
||||||
|
modalRef.value.open();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<ShowModal
|
<ShowModal
|
||||||
:show="show"
|
ref="modalRef"
|
||||||
@close="$emit('close')"
|
@close="close"
|
||||||
>
|
>
|
||||||
<Header
|
<div v-if="model">
|
||||||
:title="model.event"
|
<Header
|
||||||
/>
|
:title="model.event"
|
||||||
<div class="flex w-full p-4">
|
|
||||||
<GoogleIcon
|
|
||||||
class="text-xl text-success"
|
|
||||||
name="contact_mail"
|
|
||||||
/>
|
/>
|
||||||
<div class="pl-3 w-full">
|
<div class="flex w-full p-4">
|
||||||
<p class="font-bold text-lg leading-none pb-2">
|
<GoogleIcon
|
||||||
{{ $t('details') }}
|
class="text-xl text-success"
|
||||||
</p>
|
name="contact_mail"
|
||||||
<div class="text-sm">
|
/>
|
||||||
<h4 class="font-semibold">{{ $t('event') }}:</h4>
|
<div class="pl-3 w-full">
|
||||||
<p>{{ model.event }}</p>
|
<p class="font-bold text-lg leading-none pb-2">
|
||||||
</div>
|
{{ $t('details') }}
|
||||||
<div class="text-sm">
|
|
||||||
<h4 class="font-semibold">{{ $t('description') }}:</h4>
|
|
||||||
<p>{{ model.description }}</p>
|
|
||||||
</div>
|
|
||||||
<div class="flex w-full flex-col">
|
|
||||||
<p class="font-semibold">
|
|
||||||
{{ $t('changes') }}:
|
|
||||||
</p>
|
</p>
|
||||||
<div class="w-full text-xs p-2 border rounded-md">
|
<div class="text-sm">
|
||||||
<pre>{{ model.data }}</pre>
|
<h4 class="font-semibold">{{ $t('event') }}:</h4>
|
||||||
|
<p>{{ model.event }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="text-sm">
|
||||||
|
<h4 class="font-semibold">{{ $t('description') }}:</h4>
|
||||||
|
<p>{{ model.description }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex w-full flex-col">
|
||||||
|
<p class="font-semibold">
|
||||||
|
{{ $t('changes') }}:
|
||||||
|
</p>
|
||||||
|
<div class="w-full text-xs p-2 border rounded-md">
|
||||||
|
<pre>{{ model.data }}</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-sm">
|
||||||
|
<h4 class="font-semibold">{{ $t('created_at') }}:</h4>
|
||||||
|
<p>{{ getDateTime(model.created_at) }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="text-sm">
|
|
||||||
<h4 class="font-semibold">{{ $t('created_at') }}:</h4>
|
|
||||||
<p>{{ getDateTime(model.created_at) }}</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -3,21 +3,15 @@ import { onMounted, ref } from 'vue';
|
|||||||
import { can, apiTo, viewTo, transl } from './Module'
|
import { can, apiTo, viewTo, transl } from './Module'
|
||||||
import { useSearcher } from '@Services/Api';
|
import { useSearcher } from '@Services/Api';
|
||||||
|
|
||||||
import ModalController from '@Controllers/ModalController.js';
|
|
||||||
|
|
||||||
import IconButton from '@Holos/Button/Icon.vue'
|
import IconButton from '@Holos/Button/Icon.vue'
|
||||||
import DestroyView from '@Holos/Modal/Template/Destroy.vue';
|
import DestroyView from '@Holos/Modal/Template/Destroy.vue';
|
||||||
import SearcherHead from '@Holos/Searcher.vue';
|
import SearcherHead from '@Holos/Searcher.vue';
|
||||||
import Table from '@Holos/Table.vue';
|
import Table from '@Holos/Table.vue';
|
||||||
import Permissions from './Modals/Permissions.vue';
|
import Permissions from './Modals/Permissions.vue';
|
||||||
|
|
||||||
/** Controladores */
|
|
||||||
const Modal = new ModalController();
|
|
||||||
|
|
||||||
/** Propiedades */
|
/** Propiedades */
|
||||||
const destroyModal = ref(Modal.destroyModal);
|
const destroyModal = ref(null);
|
||||||
const editModal = ref(Modal.editModal);
|
const editModal = ref(null);
|
||||||
const modelModal = ref(Modal.modelModal);
|
|
||||||
|
|
||||||
const models = ref([]);
|
const models = ref([]);
|
||||||
|
|
||||||
@ -83,7 +77,7 @@ onMounted(() => {
|
|||||||
v-if="can('edit') && ![1,2].includes(model.id)"
|
v-if="can('edit') && ![1,2].includes(model.id)"
|
||||||
icon="license"
|
icon="license"
|
||||||
:title="transl('permissions.title')"
|
:title="transl('permissions.title')"
|
||||||
@click="Modal.switchEditModal(model)"
|
@click="editModal.open(model)"
|
||||||
outline
|
outline
|
||||||
/>
|
/>
|
||||||
<RouterLink
|
<RouterLink
|
||||||
@ -101,7 +95,7 @@ onMounted(() => {
|
|||||||
v-if="can('destroy') && ![1,2].includes(model.id)"
|
v-if="can('destroy') && ![1,2].includes(model.id)"
|
||||||
icon="delete"
|
icon="delete"
|
||||||
:title="$t('crud.destroy')"
|
:title="$t('crud.destroy')"
|
||||||
@click="Modal.switchDestroyModal(model)"
|
@click="destroyModal.open(model)"
|
||||||
outline
|
outline
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -113,18 +107,14 @@ onMounted(() => {
|
|||||||
|
|
||||||
<Permissions
|
<Permissions
|
||||||
v-if="can('index')"
|
v-if="can('index')"
|
||||||
:show="editModal"
|
ref="editModal"
|
||||||
:model="modelModal"
|
|
||||||
@close="Modal.switchEditModal"
|
|
||||||
/>
|
/>
|
||||||
<DestroyView
|
<DestroyView
|
||||||
v-if="can('destroy')"
|
v-if="can('destroy')"
|
||||||
|
ref="destroyModal"
|
||||||
title="description"
|
title="description"
|
||||||
subtitle=""
|
subtitle=""
|
||||||
:model="modelModal"
|
|
||||||
:show="destroyModal"
|
|
||||||
:to="(role) => apiTo('destroy', { role })"
|
:to="(role) => apiTo('destroy', { role })"
|
||||||
@close="Modal.switchDestroyModal"
|
|
||||||
@update="searcher.search()"
|
@update="searcher.search()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -4,8 +4,9 @@ import { api } from '@Services/Api';
|
|||||||
import { apiTo } from '../Module';
|
import { apiTo } from '../Module';
|
||||||
|
|
||||||
import Header from '@Holos/Modal/Elements/Header.vue';
|
import Header from '@Holos/Modal/Elements/Header.vue';
|
||||||
import EditModal from '@Holos/Modal/Edit.vue';
|
import EditModal from '@Holos/Modal/Show.vue';
|
||||||
import Checkbox from '@Holos/Form/Checkbox.vue';
|
import Checkbox from '@Holos/Form/Checkbox.vue';
|
||||||
|
import PrimaryButton from '@Holos/Button/Primary.vue';
|
||||||
|
|
||||||
/** Eventos */
|
/** Eventos */
|
||||||
const emit = defineEmits([
|
const emit = defineEmits([
|
||||||
@ -13,67 +14,87 @@ const emit = defineEmits([
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
/** Propiedades */
|
/** Propiedades */
|
||||||
const props = defineProps({
|
|
||||||
show: Boolean,
|
|
||||||
model: Object
|
|
||||||
});
|
|
||||||
|
|
||||||
const permissionTypes = ref([]);
|
const permissionTypes = ref([]);
|
||||||
const permissions = ref([]);
|
const permissions = ref([]);
|
||||||
|
const model = ref(null);
|
||||||
|
|
||||||
|
/** Referencias */
|
||||||
|
const modalRef = ref(null);
|
||||||
|
|
||||||
/** Métodos */
|
/** Métodos */
|
||||||
|
function close() {
|
||||||
|
modalRef.value.close();
|
||||||
|
emit('close');
|
||||||
|
}
|
||||||
|
|
||||||
function update() {
|
function update() {
|
||||||
api.put(apiTo('permissions', { role: props.model.id }), {
|
api.put(apiTo('permissions', { role: model.value.id }), {
|
||||||
data: {
|
data: {
|
||||||
permissions: permissions.value
|
permissions: permissions.value
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
Notify.success(Lang('register.edit.onSuccess'))
|
Notify.success(Lang('register.edit.onSuccess'))
|
||||||
|
|
||||||
emit('close');
|
close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Ciclos */
|
function getPermissions() {
|
||||||
onUpdated(() => {
|
|
||||||
api.get(route('permission-types.all-with-permissions'), {
|
api.get(route('permission-types.all-with-permissions'), {
|
||||||
onSuccess: (r) => permissionTypes.value = r.models
|
onSuccess: (r) => permissionTypes.value = r.models
|
||||||
});
|
});
|
||||||
|
|
||||||
api.get(apiTo('permissions', { role: props.model.id }), {
|
api.get(apiTo('permissions', { role: model.value.id }), {
|
||||||
onSuccess: (r) => {
|
onSuccess: (r) => {
|
||||||
if(r.permissions) {
|
if(r.permissions) {
|
||||||
permissions.value = r.permissions.map(p => p.id);
|
permissions.value = r.permissions.map(p => p.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Exposiciones */
|
||||||
|
defineExpose({
|
||||||
|
open: (data) => {
|
||||||
|
model.value = data;
|
||||||
|
getPermissions();
|
||||||
|
modalRef.value.open();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<EditModal
|
<EditModal
|
||||||
:show="show"
|
ref="modalRef"
|
||||||
@update="update"
|
@close="close"
|
||||||
@close="$emit('close')"
|
|
||||||
>
|
>
|
||||||
<Header
|
<div v-if="model">
|
||||||
:title="model.description"
|
<Header
|
||||||
/>
|
:title="model.description"
|
||||||
<div class="p-4">
|
/>
|
||||||
<div class="grid gap-4 grid-cols-2">
|
<div class="p-4">
|
||||||
<div v-for="permissionType in permissionTypes">
|
<div class="grid gap-4 grid-cols-2">
|
||||||
<p class="font-bold">{{ permissionType.name}}</p>
|
<div v-for="permissionType in permissionTypes">
|
||||||
<ul class="space-y-0.5 list-none">
|
<p class="font-bold">{{ permissionType.name}}</p>
|
||||||
<li v-for="permission in permissionType.permissions">
|
<ul class="space-y-0.5 list-none">
|
||||||
<Checkbox
|
<li v-for="permission in permissionType.permissions">
|
||||||
v-model="permissions"
|
<Checkbox
|
||||||
:title="permission.description"
|
v-model="permissions"
|
||||||
:value="permission.id"
|
:title="permission.description"
|
||||||
/>
|
:value="permission.id"
|
||||||
</li>
|
/>
|
||||||
</ul>
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<template #buttons>
|
||||||
|
<PrimaryButton
|
||||||
|
@click="update"
|
||||||
|
>
|
||||||
|
{{ $t('update') }}
|
||||||
|
</PrimaryButton>
|
||||||
|
</template>
|
||||||
</EditModal>
|
</EditModal>
|
||||||
</template>
|
</template>
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter, useRoute } from 'vue-router';
|
||||||
import { api, useForm } from '@Services/Api';
|
import { api, useForm } from '@Services/Api';
|
||||||
import { apiTo, transl, viewTo } from './Module';
|
import { apiTo, transl, viewTo } from './Module';
|
||||||
|
|
||||||
@ -50,7 +50,9 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<PageHeader :title="transl('create.title')">
|
<PageHeader
|
||||||
|
:title="transl('create.title')"
|
||||||
|
>
|
||||||
<RouterLink :to="viewTo({ name: 'index' })">
|
<RouterLink :to="viewTo({ name: 'index' })">
|
||||||
<IconButton
|
<IconButton
|
||||||
class="text-white"
|
class="text-white"
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import { can, apiTo, viewTo, transl } from './Module'
|
|
||||||
import { useSearcher } from '@Services/Api';
|
import { useSearcher } from '@Services/Api';
|
||||||
import { hasPermission } from '@Plugins/RolePermission';
|
import { hasPermission } from '@Plugins/RolePermission';
|
||||||
|
import { can, apiTo, viewTo, transl } from './Module'
|
||||||
import ModalController from '@Controllers/ModalController.js';
|
|
||||||
|
|
||||||
import IconButton from '@Holos/Button/Icon.vue'
|
import IconButton from '@Holos/Button/Icon.vue'
|
||||||
import DestroyView from '@Holos/Modal/Template/Destroy.vue';
|
import DestroyView from '@Holos/Modal/Template/Destroy.vue';
|
||||||
@ -12,16 +10,13 @@ import SearcherHead from '@Holos/Searcher.vue';
|
|||||||
import Table from '@Holos/Table.vue';
|
import Table from '@Holos/Table.vue';
|
||||||
import ShowView from './Modals/Show.vue';
|
import ShowView from './Modals/Show.vue';
|
||||||
|
|
||||||
/** Controladores */
|
|
||||||
const Modal = new ModalController();
|
|
||||||
|
|
||||||
/** Propiedades */
|
/** Propiedades */
|
||||||
const destroyModal = ref(Modal.destroyModal);
|
|
||||||
const showModal = ref(Modal.showModal);
|
|
||||||
const modelModal = ref(Modal.modelModal);
|
|
||||||
|
|
||||||
const models = ref([]);
|
const models = ref([]);
|
||||||
|
|
||||||
|
/** Referencias */
|
||||||
|
const showModal = ref(false);
|
||||||
|
const destroyModal = ref(false);
|
||||||
|
|
||||||
/** Métodos */
|
/** Métodos */
|
||||||
const searcher = useSearcher({
|
const searcher = useSearcher({
|
||||||
url: apiTo('index'),
|
url: apiTo('index'),
|
||||||
@ -106,7 +101,7 @@ onMounted(() => {
|
|||||||
<IconButton
|
<IconButton
|
||||||
icon="visibility"
|
icon="visibility"
|
||||||
:title="$t('crud.show')"
|
:title="$t('crud.show')"
|
||||||
@click="Modal.switchShowModal(model)"
|
@click="showModal.open(model)"
|
||||||
outline
|
outline
|
||||||
/>
|
/>
|
||||||
<RouterLink
|
<RouterLink
|
||||||
@ -124,7 +119,7 @@ onMounted(() => {
|
|||||||
v-if="can('destroy')"
|
v-if="can('destroy')"
|
||||||
icon="delete"
|
icon="delete"
|
||||||
:title="$t('crud.destroy')"
|
:title="$t('crud.destroy')"
|
||||||
@click="Modal.switchDestroyModal(model)"
|
@click="destroyModal.open(model)"
|
||||||
outline
|
outline
|
||||||
/>
|
/>
|
||||||
<RouterLink
|
<RouterLink
|
||||||
@ -166,18 +161,14 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ShowView
|
<ShowView
|
||||||
v-if="can('index')"
|
ref="showModal"
|
||||||
:show="showModal"
|
|
||||||
:model="modelModal"
|
|
||||||
@close="Modal.switchShowModal"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DestroyView
|
<DestroyView
|
||||||
v-if="can('destroy')"
|
v-if="can('destroy')"
|
||||||
|
ref="destroyModal"
|
||||||
subtitle="last_name"
|
subtitle="last_name"
|
||||||
:model="modelModal"
|
|
||||||
:show="destroyModal"
|
|
||||||
:to="(user) => apiTo('destroy', { user })"
|
:to="(user) => apiTo('destroy', { user })"
|
||||||
@close="Modal.switchDestroyModal"
|
|
||||||
@update="searcher.search()"
|
@update="searcher.search()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,68 +1,89 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
import { getDateTime } from '@Controllers/DateController';
|
import { getDateTime } from '@Controllers/DateController';
|
||||||
|
|
||||||
import Header from '@Holos/Modal/Elements/Header.vue';
|
import Header from '@Holos/Modal/Elements/Header.vue';
|
||||||
import ShowModal from '@Holos/Modal/Show.vue';
|
import ShowModal from '@Holos/Modal/Show.vue';
|
||||||
import GoogleIcon from '@Shared/GoogleIcon.vue';
|
import GoogleIcon from '@Shared/GoogleIcon.vue';
|
||||||
|
|
||||||
/** Eventos */
|
/** Eventos */
|
||||||
defineEmits([
|
const emit = defineEmits([
|
||||||
'close',
|
'close',
|
||||||
|
'reload'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/** Propiedades */
|
/** Propiedades */
|
||||||
defineProps({
|
const model = ref(null);
|
||||||
show: Boolean,
|
|
||||||
model: Object
|
/** Referencias */
|
||||||
|
const modalRef = ref(null);
|
||||||
|
|
||||||
|
/** Métodos */
|
||||||
|
function close() {
|
||||||
|
model.value = null;
|
||||||
|
|
||||||
|
emit('close');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Exposiciones */
|
||||||
|
defineExpose({
|
||||||
|
open: (data) => {
|
||||||
|
model.value = data;
|
||||||
|
modalRef.value.open();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ShowModal
|
<ShowModal
|
||||||
:show="show"
|
ref="modalRef"
|
||||||
@close="$emit('close')"
|
@close="close"
|
||||||
>
|
>
|
||||||
<Header
|
<div v-if="model">
|
||||||
:title="model.name"
|
<Header
|
||||||
:subtitle="model.last_name"
|
:title="model.name"
|
||||||
>
|
:subtitle="model.last_name"
|
||||||
<div class="flex w-full flex-col">
|
>
|
||||||
<div class="flex w-full justify-center items-center">
|
<div class="flex w-full flex-col">
|
||||||
<img :src="model.profile_photo_url" alt="Photo" class="w-24 h-24 rounded-full">
|
<div class="flex w-full justify-center items-center">
|
||||||
|
<img :src="model.profile_photo_url" alt="Photo" class="w-24 h-24 rounded-full">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Header>
|
||||||
|
<div class="flex w-full p-4">
|
||||||
|
<GoogleIcon
|
||||||
|
class="text-xl text-success"
|
||||||
|
name="contact_mail"
|
||||||
|
/>
|
||||||
|
<div class="pl-3">
|
||||||
|
<p class="font-bold text-lg leading-none pb-2">
|
||||||
|
{{ $t('details') }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>{{ $t('name') }}: </b>
|
||||||
|
{{ model.full_name }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>{{ $t('phone') }}: </b>
|
||||||
|
<a :href="`tel:${model.phone}`" target="_blank" class="hover:text-danger">
|
||||||
|
{{ model.phone ?? '-' }}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>{{ $t('email.title') }}: </b>
|
||||||
|
<a :href="`mailto:${model.email}`" target="_blank" class="hover:text-danger">
|
||||||
|
{{ model.email }}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>{{ $t('created_at') }}: </b>
|
||||||
|
{{ getDateTime(model.created_at) }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>{{ $t('updated_at') }}: </b>
|
||||||
|
{{ getDateTime(model.updated_at) }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</Header>
|
|
||||||
<div class="flex w-full p-4">
|
|
||||||
<GoogleIcon
|
|
||||||
class="text-xl text-success"
|
|
||||||
name="contact_mail"
|
|
||||||
/>
|
|
||||||
<div class="pl-3">
|
|
||||||
<p class="font-bold text-lg leading-none pb-2">
|
|
||||||
{{ $t('details') }}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<b>{{ $t('name') }}: </b>
|
|
||||||
{{ model.full_name }}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<b>{{ $t('phone') }}: </b>
|
|
||||||
<a :href="`tel:${model.phone}`" target="_blank" class="hover:text-danger">
|
|
||||||
{{ model.phone ?? '-' }}
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<b>{{ $t('email.title') }}: </b>
|
|
||||||
<a :href="`mailto:${model.email}`" target="_blank" class="hover:text-danger">
|
|
||||||
{{ model.email }}
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<b>{{ $t('created_at') }}: </b>
|
|
||||||
{{ getDateTime(model.created_at) }}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<b>{{ $t('updated_at') }}: </b>
|
|
||||||
{{ getDateTime(model.updated_at) }}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ShowModal>
|
</ShowModal>
|
||||||
|
|||||||
@ -3,21 +3,15 @@ import { ref } from 'vue';
|
|||||||
import { can, apiTo, viewTo, transl } from './Module'
|
import { can, apiTo, viewTo, transl } from './Module'
|
||||||
import { users } from '@Plugins/AuthUsers'
|
import { users } from '@Plugins/AuthUsers'
|
||||||
|
|
||||||
import ModalController from '@Controllers/ModalController.js';
|
|
||||||
|
|
||||||
import IconButton from '@Holos/Button/Icon.vue'
|
import IconButton from '@Holos/Button/Icon.vue'
|
||||||
import DestroyView from '@Holos/Modal/Template/Destroy.vue';
|
import DestroyView from '@Holos/Modal/Template/Destroy.vue';
|
||||||
import Header from '@Holos/PageHeader.vue';
|
import Header from '@Holos/PageHeader.vue';
|
||||||
import Table from '@Holos/TableSimple.vue';
|
import Table from '@Holos/TableSimple.vue';
|
||||||
import ShowView from './Modals/Show.vue';
|
import ShowView from './Modals/Show.vue';
|
||||||
|
|
||||||
/** Controladores */
|
|
||||||
const Modal = new ModalController();
|
|
||||||
|
|
||||||
/** Propiedades */
|
/** Propiedades */
|
||||||
const destroyModal = ref(Modal.destroyModal);
|
const destroyModal = ref(null);
|
||||||
const showModal = ref(Modal.showModal);
|
const showModal = ref(null);
|
||||||
const modelModal = ref(Modal.modelModal);
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -87,7 +81,7 @@ const modelModal = ref(Modal.modelModal);
|
|||||||
<IconButton
|
<IconButton
|
||||||
icon="visibility"
|
icon="visibility"
|
||||||
:title="$t('crud.show')"
|
:title="$t('crud.show')"
|
||||||
@click="Modal.switchShowModal(model)"
|
@click="showModal.open(model)"
|
||||||
outline
|
outline
|
||||||
/>
|
/>
|
||||||
<RouterLink
|
<RouterLink
|
||||||
@ -105,7 +99,7 @@ const modelModal = ref(Modal.modelModal);
|
|||||||
v-if="can('destroy')"
|
v-if="can('destroy')"
|
||||||
icon="delete"
|
icon="delete"
|
||||||
:title="$t('crud.destroy')"
|
:title="$t('crud.destroy')"
|
||||||
@click="Modal.switchDestroyModal(model)"
|
@click="destroyModal.open(model)"
|
||||||
outline
|
outline
|
||||||
/>
|
/>
|
||||||
<RouterLink
|
<RouterLink
|
||||||
@ -127,17 +121,14 @@ const modelModal = ref(Modal.modelModal);
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ShowView
|
<ShowView
|
||||||
v-if="can('index')"
|
ref="showModal"
|
||||||
:show="showModal"
|
|
||||||
:model="modelModal"
|
|
||||||
@close="Modal.switchShowModal"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DestroyView
|
<DestroyView
|
||||||
v-if="can('destroy')"
|
v-if="can('destroy')"
|
||||||
:model="modelModal"
|
ref="destroyModal"
|
||||||
:show="destroyModal"
|
subtitle="last_name"
|
||||||
:to="(user) => apiTo('destroy', { user })"
|
:to="(user) => apiTo('destroy', { user })"
|
||||||
@close="Modal.switchDestroyModal"
|
|
||||||
@update="searcher.search()"
|
@update="searcher.search()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -100,6 +100,24 @@ const changelogs = [
|
|||||||
'UPDATE: Actualización de dependencias.'
|
'UPDATE: Actualización de dependencias.'
|
||||||
],
|
],
|
||||||
date: '2025-05-23'
|
date: '2025-05-23'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
version: '0.9.11',
|
||||||
|
details: [
|
||||||
|
'FIX: El useApi clonaba comportamientos en instancias de la misma página.',
|
||||||
|
'UPDATE: Actualización de dependencias.'
|
||||||
|
],
|
||||||
|
date: '2025-05-23'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
version: '0.9.12',
|
||||||
|
details: [
|
||||||
|
'FIX: Token de sesión ahora se almacena en localStorage para mantener la sesión activa en el frontend por el tiempo de vida del token.',
|
||||||
|
'UPDATE: Actualización de dependencias.',
|
||||||
|
'UPDATE: Funcionamiento de los modals.',
|
||||||
|
'ADD: Breadcrumbs.'
|
||||||
|
],
|
||||||
|
date: '2025-07-14'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -2,25 +2,21 @@
|
|||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import { useSearcher } from '@Services/Api';
|
import { useSearcher } from '@Services/Api';
|
||||||
|
|
||||||
import ModalController from '@Controllers/ModalController.js';
|
|
||||||
import { getDateTime } from '@Controllers/DateController.js';
|
import { getDateTime } from '@Controllers/DateController.js';
|
||||||
|
|
||||||
import SearcherHead from '@Holos/Searcher.vue';
|
import SearcherHead from '@Holos/Searcher.vue';
|
||||||
import Table from '@Holos/Table.vue';
|
import Table from '@Holos/Table.vue';
|
||||||
import IconButton from '@Holos/Button/Icon.vue';
|
import IconButton from '@Holos/Button/Icon.vue';
|
||||||
import ShowView from '@Holos/Skeleton/Sidebar/Notification/Show.vue';
|
import DestroyModal from '@Holos/Modal/Template/Destroy.vue';
|
||||||
import GoogleIcon from '@Shared/GoogleIcon.vue';
|
import ShowModal from '@Holos/Skeleton/Sidebar/Notification/Show.vue';
|
||||||
|
|
||||||
/** Controladores */
|
|
||||||
const Modal = new ModalController();
|
|
||||||
|
|
||||||
/** Propiedades */
|
/** Propiedades */
|
||||||
// const destroyModal = ref(Modal.destroyModal);
|
const destroyModal = ref(null);
|
||||||
const showModal = ref(Modal.showModal);
|
const showModal = ref(false);
|
||||||
const modelModal = ref(Modal.modelModal);
|
|
||||||
|
|
||||||
const models = ref([]);
|
const models = ref([]);
|
||||||
|
|
||||||
|
// Servicios
|
||||||
const searcher = useSearcher({
|
const searcher = useSearcher({
|
||||||
url: route('system.notifications.all'),
|
url: route('system.notifications.all'),
|
||||||
onSuccess: (r) => models.value = r.models,
|
onSuccess: (r) => models.value = r.models,
|
||||||
@ -89,17 +85,15 @@ onMounted(() => {
|
|||||||
<IconButton
|
<IconButton
|
||||||
icon="visibility"
|
icon="visibility"
|
||||||
:title="$t('crud.show')"
|
:title="$t('crud.show')"
|
||||||
@click="Modal.switchShowModal(model)"
|
@click="showModal.open(model)"
|
||||||
outline
|
outline
|
||||||
/>
|
/>
|
||||||
<!-- <GoogleIcon
|
<IconButton
|
||||||
v-if="can('destroy')"
|
icon="delete"
|
||||||
class="btn-icon"
|
|
||||||
name="delete"
|
|
||||||
:title="$t('crud.destroy')"
|
:title="$t('crud.destroy')"
|
||||||
@click="Modal.switchDestroyModal(model)"
|
@click="destroyModal.open(model)"
|
||||||
outline
|
outline
|
||||||
/> -->
|
/>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -120,20 +114,15 @@ onMounted(() => {
|
|||||||
</Table>
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ShowView
|
<ShowModal
|
||||||
:show="showModal"
|
ref="showModal"
|
||||||
:model="modelModal"
|
|
||||||
@close="Modal.switchShowModal"
|
|
||||||
@reload="searcher.search()"
|
@reload="searcher.search()"
|
||||||
/>
|
/>
|
||||||
<!-- <DestroyView
|
<DestroyModal
|
||||||
v-if="can('destroy')"
|
ref="destroyModal"
|
||||||
:model="modelModal"
|
:to="(id) => route('system.notifications.destroy', { id })"
|
||||||
:show="destroyModal"
|
@update="searcher.search()"
|
||||||
:to="(user) => apiTo('destroy', { user })"
|
/>
|
||||||
@close="Modal.switchDestroyModal"
|
|
||||||
@update="getNotifications"
|
|
||||||
/> -->
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -5,11 +5,11 @@ import { logout } from '@Services/Page';
|
|||||||
|
|
||||||
import ActionSection from '@Holos/ActionSection.vue';
|
import ActionSection from '@Holos/ActionSection.vue';
|
||||||
import DangerButton from '@Holos/Button/Danger.vue';
|
import DangerButton from '@Holos/Button/Danger.vue';
|
||||||
import DialogModal from '@Holos/DialogModal.vue';
|
import DialogModal from '@Holos/Modal/Elements/Base.vue';
|
||||||
import SecondaryButton from '@Holos/Button/Secondary.vue';
|
import SecondaryButton from '@Holos/Button/Secondary.vue';
|
||||||
import Input from '@Holos/Form/Input.vue';
|
import Input from '@Holos/Form/Input.vue';
|
||||||
|
|
||||||
const confirmingUserDeletion = ref(false);
|
const modalRef = ref(null);
|
||||||
const passwordInput = ref(null);
|
const passwordInput = ref(null);
|
||||||
|
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
@ -17,7 +17,7 @@ const form = useForm({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const confirmUserDeletion = () => {
|
const confirmUserDeletion = () => {
|
||||||
confirmingUserDeletion.value = true;
|
modalRef.value.open();
|
||||||
|
|
||||||
setTimeout(() => passwordInput.value.focus(), 250);
|
setTimeout(() => passwordInput.value.focus(), 250);
|
||||||
};
|
};
|
||||||
@ -26,7 +26,7 @@ const deleteUser = () => {
|
|||||||
form.delete(route('user.destroy'), {
|
form.delete(route('user.destroy'), {
|
||||||
preserveScroll: true,
|
preserveScroll: true,
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
closeModal();
|
modalRef.value.close();
|
||||||
logout();
|
logout();
|
||||||
},
|
},
|
||||||
onError: () => passwordInput.value.focus(),
|
onError: () => passwordInput.value.focus(),
|
||||||
@ -34,9 +34,7 @@ const deleteUser = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeModal = () => {
|
const onCloseModal = () => {
|
||||||
confirmingUserDeletion.value = false;
|
|
||||||
|
|
||||||
form.reset();
|
form.reset();
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@ -63,7 +61,10 @@ const closeModal = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Delete Account Confirmation Modal -->
|
<!-- Delete Account Confirmation Modal -->
|
||||||
<DialogModal :show="confirmingUserDeletion" @close="closeModal">
|
<DialogModal
|
||||||
|
ref="modalRef"
|
||||||
|
@close="onCloseModal"
|
||||||
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
{{ $t('account.delete.title') }}
|
{{ $t('account.delete.title') }}
|
||||||
</template>
|
</template>
|
||||||
@ -86,7 +87,7 @@ const closeModal = () => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<SecondaryButton @click="closeModal">
|
<SecondaryButton @click="modalRef.close()">
|
||||||
{{ $t('cancel') }}
|
{{ $t('cancel') }}
|
||||||
</SecondaryButton>
|
</SecondaryButton>
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { ref } from 'vue';
|
|||||||
import { useForm } from '@Services/Api';
|
import { useForm } from '@Services/Api';
|
||||||
|
|
||||||
import ActionSection from '@Holos/ActionSection.vue';
|
import ActionSection from '@Holos/ActionSection.vue';
|
||||||
import DialogModal from '@Holos/DialogModal.vue';
|
import DialogModal from '@Holos/Modal/Elements/Base.vue';
|
||||||
import PrimaryButton from '@Holos/Button/Primary.vue';
|
import PrimaryButton from '@Holos/Button/Primary.vue';
|
||||||
import SecondaryButton from '@Holos/Button/Secondary.vue';
|
import SecondaryButton from '@Holos/Button/Secondary.vue';
|
||||||
import Input from '@Holos/Form/Input.vue';
|
import Input from '@Holos/Form/Input.vue';
|
||||||
|
|||||||
@ -17,16 +17,26 @@ const router = createRouter({
|
|||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
component: () => import('@Layouts/AppLayout.vue'),
|
component: () => import('@Layouts/AppLayout.vue'),
|
||||||
|
name: 'root',
|
||||||
|
meta: {
|
||||||
|
title: 'Inicio',
|
||||||
|
icon: 'home',
|
||||||
|
},
|
||||||
|
redirect: '/dashboard',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
name: 'index',
|
name: 'index',
|
||||||
redirect: '/dashboard'
|
redirect: '/dashboard',
|
||||||
|
meta: {
|
||||||
|
title: 'Inicio',
|
||||||
|
icon: 'home',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'dashboard',
|
path: 'dashboard',
|
||||||
name: 'dashboard.index',
|
name: 'dashboard.index',
|
||||||
component: () => import('@Pages/Dashboard/Index.vue')
|
component: () => import('@Pages/Dashboard/Index.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'profile',
|
path: 'profile',
|
||||||
@ -34,7 +44,11 @@ const router = createRouter({
|
|||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
name: 'profile.show',
|
name: 'profile.show',
|
||||||
component: () => import('@Pages/Profile/Show.vue')
|
component: () => import('@Pages/Profile/Show.vue'),
|
||||||
|
meta: {
|
||||||
|
title: 'Perfil',
|
||||||
|
icon: 'person',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'notifications',
|
path: 'notifications',
|
||||||
@ -52,16 +66,28 @@ const router = createRouter({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/admin',
|
path: '/admin',
|
||||||
|
name: 'admin',
|
||||||
component: () => import('@Layouts/AppLayout.vue'),
|
component: () => import('@Layouts/AppLayout.vue'),
|
||||||
|
meta: {
|
||||||
|
title: 'Inicio',
|
||||||
|
icon: 'home',
|
||||||
|
},
|
||||||
|
redirect: '/',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'users',
|
path: 'users',
|
||||||
|
name: 'admin.users',
|
||||||
|
meta: {
|
||||||
|
title: 'Usuarios',
|
||||||
|
icon: 'people',
|
||||||
|
},
|
||||||
|
redirect: '/admin/users',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
name: 'admin.users.index',
|
name: 'admin.users.index',
|
||||||
beforeEnter: (to, from, next) => can(next, 'users.index'),
|
beforeEnter: (to, from, next) => can(next, 'users.index'),
|
||||||
component: () => import('@Pages/Admin/Users/Index.vue')
|
component: () => import('@Pages/Admin/Users/Index.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'online',
|
path: 'online',
|
||||||
@ -73,41 +99,73 @@ const router = createRouter({
|
|||||||
path: 'create',
|
path: 'create',
|
||||||
name: 'admin.users.create',
|
name: 'admin.users.create',
|
||||||
beforeEnter: (to, from, next) => can(next, 'users.create'),
|
beforeEnter: (to, from, next) => can(next, 'users.create'),
|
||||||
|
meta: {
|
||||||
|
title: 'Crear',
|
||||||
|
icon: 'add',
|
||||||
|
},
|
||||||
component: () => import('@Pages/Admin/Users/Create.vue')
|
component: () => import('@Pages/Admin/Users/Create.vue')
|
||||||
}, {
|
}, {
|
||||||
path: ':id/edit',
|
path: ':id/edit',
|
||||||
name: 'admin.users.edit',
|
name: 'admin.users.edit',
|
||||||
beforeEnter: (to, from, next) => can(next, 'users.edit'),
|
beforeEnter: (to, from, next) => can(next, 'users.edit'),
|
||||||
|
meta: {
|
||||||
|
title: 'Editar',
|
||||||
|
icon: 'edit',
|
||||||
|
},
|
||||||
component: () => import('@Pages/Admin/Users/Edit.vue')
|
component: () => import('@Pages/Admin/Users/Edit.vue')
|
||||||
}, {
|
}, {
|
||||||
path: ':id/settings',
|
path: ':id/settings',
|
||||||
name: 'admin.users.settings',
|
name: 'admin.users.settings',
|
||||||
beforeEnter: (to, from, next) => can(next, 'users.settings'),
|
beforeEnter: (to, from, next) => can(next, 'users.settings'),
|
||||||
component: () => import('@Pages/Admin/Users/Settings.vue')
|
component: () => import('@Pages/Admin/Users/Settings.vue'),
|
||||||
|
meta: {
|
||||||
|
title: 'Configuración',
|
||||||
|
icon: 'settings',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'roles',
|
path: 'roles',
|
||||||
|
name: 'admin.roles',
|
||||||
|
meta: {
|
||||||
|
title: 'Roles',
|
||||||
|
icon: 'license',
|
||||||
|
},
|
||||||
|
redirect: '/admin/roles',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
name: 'admin.roles.index',
|
name: 'admin.roles.index',
|
||||||
component: () => import('@Pages/Admin/Roles/Index.vue')
|
component: () => import('@Pages/Admin/Roles/Index.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'create',
|
path: 'create',
|
||||||
name: 'admin.roles.create',
|
name: 'admin.roles.create',
|
||||||
component: () => import('@Pages/Admin/Roles/Create.vue')
|
component: () => import('@Pages/Admin/Roles/Create.vue'),
|
||||||
|
meta: {
|
||||||
|
title: 'Crear',
|
||||||
|
icon: 'add',
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
path: ':id/edit',
|
path: ':id/edit',
|
||||||
name: 'admin.roles.edit',
|
name: 'admin.roles.edit',
|
||||||
component: () => import('@Pages/Admin/Roles/Edit.vue')
|
component: () => import('@Pages/Admin/Roles/Edit.vue'),
|
||||||
|
meta: {
|
||||||
|
title: 'Editar',
|
||||||
|
icon: 'edit',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'activities',
|
path: 'activities',
|
||||||
|
name: 'admin.activities',
|
||||||
|
meta: {
|
||||||
|
title: 'Historial de acciones',
|
||||||
|
icon: 'event',
|
||||||
|
},
|
||||||
|
redirect: '/admin/activities',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
|
|||||||
@ -23,7 +23,7 @@ const failCodes = [
|
|||||||
/**
|
/**
|
||||||
* Servidor a utilizar
|
* Servidor a utilizar
|
||||||
*/
|
*/
|
||||||
const token = ref(sessionStorage.token);
|
const token = ref(localStorage.token);
|
||||||
const csrfToken = ref(localStorage.csrfToken);
|
const csrfToken = ref(localStorage.csrfToken);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,7 +31,7 @@ const csrfToken = ref(localStorage.csrfToken);
|
|||||||
*/
|
*/
|
||||||
const defineApiToken = (x) => {
|
const defineApiToken = (x) => {
|
||||||
token.value = x;
|
token.value = x;
|
||||||
sessionStorage.token = x;
|
localStorage.token = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,7 +47,7 @@ const defineCsrfToken = (x) => {
|
|||||||
*/
|
*/
|
||||||
const resetApiToken = () => {
|
const resetApiToken = () => {
|
||||||
token.value = undefined;
|
token.value = undefined;
|
||||||
sessionStorage.removeItem('token');
|
localStorage.removeItem('token');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -250,7 +250,7 @@ const api = {
|
|||||||
/**
|
/**
|
||||||
* Instancia de la API
|
* Instancia de la API
|
||||||
*/
|
*/
|
||||||
const useApi = () => reactive(api);
|
const useApi = () => reactive({...api});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instancia de la API para formularios
|
* Instancia de la API para formularios
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user