Se agregó la vista de accesos rapidos

This commit is contained in:
Juan Felipe Zapata Moreno 2025-08-18 12:27:23 -06:00
parent f1a276cf01
commit 52e8dc8153
5 changed files with 221 additions and 40 deletions

View File

@ -10,15 +10,15 @@
/**
* Siembra usuarios de forma segura
*
*
* Siembra usuarios sin la necesidad de escribir una contraseña que quede registrada en el código.
* El usuario será generado con una contraseña que puede ser consultado en el log. Esto permite
* evitar el escribir las contraseñas en código. Esto permite que los usuarios de prueba sean seguros
* y de proyecto en proyecto no sea una brecha de seguridad tener contraseñas dentro del código en caso
* de que este pueda llegar a ser vulnerado.
*
*
* @author Moisés de Jesús Cortés Castellanos <ing.moisesdejesuscortesc@notsoweb.com>
*
*
* @version 1.0.0
*/
class UserSeeder extends Seeder
@ -35,36 +35,28 @@ public function run()
[
$developerEmail,
$developerPass
] = UserSecureSupport::new('developer@notsoweb.com');
] = UserSecureSupport::new('developer@golsystems.com');
User::create([
'name' => 'Developer',
'paternal' => 'Notsoweb',
'paternal' => 'golsystems',
'email' => $developerEmail,
'phone' => '5631809090',
'password' => $developerPass,
])->assignRole('developer');
// Usuario administrador
[
$adminEmail,
$adminPass
] = UserSecureSupport::new('admin@notsoweb.com');
] = UserSecureSupport::new('admin@comalcalco.com');
User::create([
'name' => 'Administrador',
'paternal' => 'Notsoweb',
'paternal' => 'comalcalco',
'email' => $adminEmail,
'password' => $adminPass
])->assignRole('admin');
// Usuario de prueba
User::create([
'name' => 'Demo',
'paternal' => 'Notsoweb',
'email' => 'demo@notsoweb.com',
'password' => Hash::make('Demo')
]);
});
}
}

View File

@ -63,7 +63,7 @@ const submit = () => {
/>
<div class="block mt-4">
<label class="flex items-center">
<Checkbox
<Checkbox
name="remember"
v-model:checked="form.remember"
/>
@ -76,24 +76,24 @@ const submit = () => {
<div class="flex flex-col items-center justify-end space-y-2 mt-4">
<PrimaryButton
class="w-full"
:class="{ 'opacity-25': form.processing }"
:class="{ 'opacity-25': form.processing }"
:disabled="form.processing"
v-text="$t('auth.login')"
/>
<Link
<!-- <Link
class="w-full"
:href="route('register')"
:href="route('register')"
>
<PrimaryButton
class="w-full"
:class="{ 'opacity-25': form.processing }"
:class="{ 'opacity-25': form.processing }"
:disabled="form.processing"
v-text="$t('register.signUp')"
/>
</Link>
</Link>-->
<Link v-if="canResetPassword"
class="underline text-sm"
:href="route('password.request')"
class="underline text-sm"
:href="route('password.request')"
>
{{ $t('auth.forgotPassword.ask') }}
</Link>

View File

@ -1,12 +1,169 @@
<script setup>
import Welcome from '@/Components/Dashboard/Welcome.vue';
import Layout from '@/Layouts/DashboardLayout.vue';
import { router } from '@inertiajs/vue3';
import GoogleIcon from "@/Components/Shared/GoogleIcon.vue";
import NotificationController from '@/Controllers/NotificationController';
const notificationCtl = NotificationController;
const logout = () => {
router.post(route('logout'), {}, {
onBefore: () => {
notificationCtl.stop();
}
});
};
</script>
<template>
<Layout title="Dashboard">
<div class="py-4">
<Welcome />
<div
class="min-h-screen font-sans bg-gradient-to-br from-[#621132] via-[#621132] to-[#621132] text-[#621132] antialiased"
>
<div class="flex items-center justify-end p-5 text-white">
<div class="border p-1 rounded">
<button type="button" @click.prevent="logout">
{{ $t("auth.logout") }}
</button>
</div>
</div>
<main class="grid min-h-screen place-items-center p-4">
<!-- Tarjeta -->
<section
class="w-full max-w-2xl rounded-3xl border border-white/10 bg-white/5 p-6 sm:p-8 shadow-2xl backdrop-blur supports-[backdrop-filter]:bg-white/10"
>
<!-- Encabezado -->
<header class="mb-6 sm:mb-8">
<h1 class="text-2xl sm:text-3xl font-bold tracking-tight text-white">
Accesos rápidos
</h1>
<p class="mt-2 text-sm sm:text-base text-white">
Selecciona un destino.
</p>
</header>
<!-- Grid de botones -->
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4">
<!-- Botón 1 -->
<a
:href="route('dashboard.api-tramite')"
target="_blank"
class="group relative overflow-hidden rounded-2xl border border-white/10 bg-white/10 p-4 sm:p-5 transition hover:bg-white/15 focus:outline-none focus-visible:ring-2 focus-visible:ring-sky-400 active:scale-[0.99]"
aria-label="Ir al sitio 1"
>
<div class="flex items-center gap-3">
<!-- Ícono externo simple -->
<span class="rounded-xl bg-white/10 p-2">
<GoogleIcon name="open_in_new" class="text-white" />
</span>
<div class="min-w-0">
<h2 class="font-semibold text-white">
Reporte Especial de Trámites
</h2>
<p class="text-sm text-slate-300">
Resumen de trámites por unidad administrativa
</p>
</div>
</div>
<!-- Efecto -->
<span
class="pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-500 group-hover:opacity-100"
style="
background: radial-gradient(
600px circle at var(--x, 50%) var(--y, 50%),
rgba(199, 12, 12, 0.12),
transparent 40%
);
"
></span>
</a>
<!-- Botón 2 -->
<a
href="https://apoyos.comalcalco.gob.mx/beneficiaries/dashboard?department=1&period=week&type=almacen"
target="_blank"
class="group relative overflow-hidden rounded-2xl border border-white/10 bg-white/10 p-4 sm:p-5 transition hover:bg-white/15 focus:outline-none focus-visible:ring-2 focus-visible:ring-emerald-400 active:scale-[0.99]"
aria-label="Ir al sitio 2"
>
<div class="flex items-center gap-3">
<span class="rounded-xl bg-white/10 p-2">
<GoogleIcon name="open_in_new" class="text-white" />
</span>
<div class="min-w-0">
<h2 class="font-semibold text-white">Apoyo a Beneficiarios</h2>
<p class="text-sm text-slate-300">
Dashboard de apoyo a Beneficiarios
</p>
</div>
</div>
<span
class="pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-500 group-hover:opacity-100"
style="
background: radial-gradient(
600px circle at var(--x, 50%) var(--y, 50%),
rgba(98, 17, 50, 0.12),
transparent 40%
);
"
></span>
</a>
<!-- Botón 3 -->
<a
:href="route('dashboard.api-obra')"
target="_blank"
class="group relative overflow-hidden rounded-2xl border border-white/10 bg-white/10 p-4 sm:p-5 transition hover:bg-white/15 focus:outline-none focus-visible:ring-2 focus-visible:ring-fuchsia-400 active:scale-[0.99]"
aria-label="Ir al sitio 3"
>
<div class="flex items-center gap-3">
<span class="rounded-xl bg-white/10 p-2">
<GoogleIcon name="open_in_new" class="text-white" />
</span>
<div class="min-w-0">
<h2 class="font-semibold text-white">Información de Obras</h2>
<p class="text-sm text-slate-300">Proyectos en seguimiento</p>
</div>
</div>
<span
class="pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-500 group-hover:opacity-100"
style="
background: radial-gradient(
600px circle at var(--x, 50%) var(--y, 50%),
rgba(255, 255, 255, 0.12),
transparent 40%
);
"
></span>
</a>
<!-- Botón 4 -->
<a
href="https://apoyos.comalcalco.gob.mx/beneficiaries/dashboard?department=3&period=week&type=almacen"
target="_blank"
class="group relative overflow-hidden rounded-2xl border border-white/10 bg-white/10 p-4 sm:p-5 transition hover:bg-white/15 focus:outline-none focus-visible:ring-2 focus-visible:ring-amber-400 active:scale-[0.99]"
aria-label="Ir al sitio 4"
>
<div class="flex items-center gap-3">
<span class="rounded-xl bg-white/10 p-2">
<GoogleIcon name="open_in_new" class="text-white" />
</span>
<div class="min-w-0">
<h2 class="font-semibold text-white">DIF</h2>
<p class="text-sm text-slate-300">Dashboard de DIF</p>
</div>
</div>
<span
class="pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-500 group-hover:opacity-100"
style="
background: radial-gradient(
600px circle at var(--x, 50%) var(--y, 50%),
rgba(255, 255, 255, 0.12),
transparent 40%
);
"
></span>
</a>
</div>
</Layout>
</section>
</main>
</div>
</template>

View File

@ -25,7 +25,7 @@ const pieChartData = ref({ labels: [], datasets: [] });
// opciones reutilizables
const barChartOptions = {
responsive: true,
makeDataset : (label, values) => ({
makeDataset: (label, values) => ({
label,
data: values,
backgroundColor: "rgba(75,192,192,0.2)",
@ -69,7 +69,9 @@ let debounceId = null;
const fetchReport = async ({ start, end }) => {
// cancelar petición previa
if (cancelTokenSource) {
try { cancelTokenSource.cancel('cancel'); } catch (e) {}
try {
cancelTokenSource.cancel("cancel");
} catch (e) {}
}
cancelTokenSource = axios.CancelToken.source();
@ -77,10 +79,10 @@ const fetchReport = async ({ start, end }) => {
if (start) params.start = start;
if (end) params.end = end;
const res = await axios.get('/api/reporte-especial', {
const res = await axios.get("/api/reporte-especial", {
params,
cancelToken: cancelTokenSource.token,
headers: { 'X-Requested-With': 'XMLHttpRequest' }
headers: { "X-Requested-With": "XMLHttpRequest" },
});
// axios lanza en error si status >= 400, aquí devolvemos data directamente
@ -174,8 +176,38 @@ const togglePie = () => (showPie.value = !showPie.value);
<template>
<div>
<div v-if="loading">Cargando...</div>
<div v-else-if="error">Error: {{ error }}</div>
<header>
<div class="bg-gray-100 py-2">
<div class="text-left container mx-auto sm:px-6 lg:px-8">
<span class="text-sm text-gray-700 font-bold">COMALCALCO.GOB.MX</span>
</div>
</div>
<div style="background-color: #621132" class="shadow-lg">
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex items-center h-28">
<img
src="https://apoyos.comalcalco.gob.mx/images/logo_blanco.png"
alt="Logo Comalcalco"
class="h-24 w-auto object-contain"
/>
</div>
</div>
</div>
</header>
<!-- Loading Overlay -->
<div
v-if="loading"
class="fixed inset-0 bg-white bg-opacity-90 flex items-center justify-center z-50"
>
<div class="text-center">
<div
class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto"
></div>
<p class="mt-4 text-gray-600">Cargando datos...</p>
</div>
</div>
<div v-else>
<div class="min-h-screen bg-gray-50 py-8">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
@ -474,7 +506,7 @@ const togglePie = () => (showPie.value = !showPie.value);
class="max-w-7xl mx-auto mt-12 px-4 sm:px-6 lg:px-8 mb-8 bg-white rounded-lg shadow p-6"
>
<!-- DateRange mejorado -->
<DateRange v-model="dateRange" :presets="true" class="mb-12"/>
<DateRange v-model="dateRange" :presets="true" class="mb-12" />
<Bars :chartData="barChartData" :chartOptions="barChartOptions" />
<p class="text-sm text-gray-500 mt-2">Modo actual: {{ mode }}</p>
</div>

View File

@ -16,7 +16,7 @@ module.exports = {
theme: {
extend: {
fontFamily: {
sans: ['Nunito', ...defaultTheme.fontFamily.sans],
sans: ['Inter', 'ui-sans-serif', 'system-ui', 'Segoe UI', 'Roboto'],
'google-icon':['Material Icons'],
'google-icon-outlined':['Material Symbols Outlined']
},