forked from verdnatura/hedera-web
Create access log view
This commit is contained in:
parent
85eee7bb7a
commit
cc44041e31
|
@ -1,7 +1,7 @@
|
|||
<script setup>
|
||||
const props = defineProps({
|
||||
clickable: { type: Boolean, default: true },
|
||||
rounded: { type: Boolean, default: true }
|
||||
rounded: { type: Boolean, default: false }
|
||||
});
|
||||
|
||||
const emit = defineEmits(['click']);
|
||||
|
@ -18,8 +18,11 @@ const handleClick = () => {
|
|||
v-bind="$attrs"
|
||||
v-ripple="clickable"
|
||||
:clickable="clickable"
|
||||
class="full-width row items-center justify-between card no-border-radius bg-white"
|
||||
:class="{ 'cursor-pointer': clickable, 'no-radius': !rounded }"
|
||||
class="full-width row items-center justify-between card bg-white"
|
||||
:class="[
|
||||
rounded ? 'default-radius' : 'no-radius',
|
||||
{ 'cursor-pointer': clickable }
|
||||
]"
|
||||
@click="handleClick()"
|
||||
>
|
||||
<div
|
||||
|
|
|
@ -69,6 +69,7 @@ export default {
|
|||
Checkout: `Configurar l'encarrec`,
|
||||
'Address details': 'Configuració',
|
||||
'Admin news details': `Afegir o editar notícia`,
|
||||
'Access log': 'Registre d’accés',
|
||||
//
|
||||
orderLoadedIntoBasket: 'Comanda carregada a la cistella!',
|
||||
loadAnOrder:
|
||||
|
|
|
@ -81,6 +81,7 @@ export default {
|
|||
Checkout: 'Configure order',
|
||||
'Address details': 'Configuration',
|
||||
'Admin news details': 'Add or edit new',
|
||||
'Access log': 'Access log',
|
||||
//
|
||||
orderLoadedIntoBasket: 'Order loaded into basket!',
|
||||
loadAnOrder: 'Please load a pending order to the cart or start a new one',
|
||||
|
|
|
@ -87,6 +87,7 @@ export default {
|
|||
Checkout: 'Configurar pedido',
|
||||
'Address details': 'Configuración',
|
||||
'Admin news details': 'Añadir o editar noticia',
|
||||
'Access log': 'Registro de accesos',
|
||||
//
|
||||
orderLoadedIntoBasket: '¡Pedido cargado en la cesta!',
|
||||
loadAnOrder:
|
||||
|
|
|
@ -69,6 +69,7 @@ export default {
|
|||
Checkout: 'Configurer la commande',
|
||||
'Address details': 'Configuration',
|
||||
'Admin news details': 'Ajouter ou éditer une nouvelle',
|
||||
'Access log': "Journal d'accès",
|
||||
//
|
||||
orderLoadedIntoBasket: 'Commande chargée dans le panier!',
|
||||
loadAnOrder:
|
||||
|
|
|
@ -68,6 +68,7 @@ export default {
|
|||
Checkout: 'Configurar encomenda',
|
||||
'Address details': 'Configuração',
|
||||
'Admin news details': 'Adicionar ou editar notícia',
|
||||
'Access log': 'Registo de acessos',
|
||||
//
|
||||
orderLoadedIntoBasket: 'Pedido carregado na cesta!',
|
||||
loadAnOrder: 'Carregue um pedido pendente no carrinho ou inicie um novo',
|
||||
|
|
|
@ -31,7 +31,13 @@ export const formatDate = (timeStamp, format = 'YYYY-MM-DD') => {
|
|||
*/
|
||||
export const formatDateTitle = (
|
||||
timeStamp,
|
||||
options = { showTime: false, showSeconds: false, shortDay: false }
|
||||
options = {
|
||||
showTime: false,
|
||||
showSeconds: false,
|
||||
shortDay: false,
|
||||
shortMonth: false,
|
||||
includeOfString: true
|
||||
}
|
||||
) => {
|
||||
if (!timeStamp) return '';
|
||||
const { t } = i18n.global;
|
||||
|
@ -42,8 +48,10 @@ export const formatDateTitle = (
|
|||
: ` [${t('at')}] HH:mm`
|
||||
: '';
|
||||
const day = options.shortDay ? 'dd' : 'dddd';
|
||||
const month = options.shortMonth ? 'MMM' : 'MMMM';
|
||||
const ofString = options.includeOfString ? ` [${t('of')}] ` : '';
|
||||
|
||||
const formatString = `${day}, D [${t('of')}] MMMM [${t('of')}] YYYY${timeFormat}`;
|
||||
const formatString = `${day}, D${ofString} ${month}${ofString} YYYY${timeFormat}`;
|
||||
|
||||
const formattedString = formatDate(timeStamp, formatString);
|
||||
return formattedString;
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
<script setup>
|
||||
import { onMounted, inject, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import CardList from 'src/components/ui/CardList.vue';
|
||||
|
||||
import { formatDateTitle } from 'src/lib/filters.js';
|
||||
|
||||
const jApi = inject('jApi');
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const accessLogs = ref([]);
|
||||
const user = ref(null);
|
||||
|
||||
const getUser = async () => {
|
||||
try {
|
||||
if (!route.params.id) return;
|
||||
const [data] = await jApi.query(
|
||||
`SELECT u.id, u.name user, u.nickname, u.email, c.phone, r.name role
|
||||
FROM account.user u
|
||||
JOIN account.role r ON r.id = u.role
|
||||
LEFT JOIN vn.client c ON c.id = u.id
|
||||
WHERE u.id = #user`,
|
||||
{ user: route.params.id }
|
||||
);
|
||||
user.value = data;
|
||||
} catch (error) {
|
||||
console.error('Error getting user:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const getAccessLogs = async () => {
|
||||
try {
|
||||
accessLogs.value = await jApi.query(
|
||||
`SELECT u.stamp, a.platform, a.browser, a.version, a.javascript, a.cookies
|
||||
FROM visitUser u
|
||||
JOIN visitAccess c ON c.id = u.accessFk
|
||||
JOIN visitAgent a ON a.id = c.agentFk
|
||||
WHERE u.userFk = #user
|
||||
ORDER BY u.stamp DESC
|
||||
LIMIT 8`,
|
||||
{ user: route.params.id }
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Error getting access logs:', error);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
getUser();
|
||||
getAccessLogs();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<QPage class="vn-w-xs">
|
||||
<CardList
|
||||
v-if="user"
|
||||
:key="index"
|
||||
:clickable="false"
|
||||
rounded
|
||||
class="q-mb-md"
|
||||
>
|
||||
<template #content>
|
||||
<span class="text-bold text-h5 q-mb-sm">
|
||||
{{ user?.nickname }}
|
||||
</span>
|
||||
<span>#{{ user?.id }} - {{ user.user }} </span>
|
||||
<span>{{ user?.role }} </span>
|
||||
<span>{{ user?.email }} </span>
|
||||
<span>{{ user?.phone }} </span>
|
||||
</template>
|
||||
</CardList>
|
||||
<QList>
|
||||
<CardList
|
||||
v-for="(accessLog, index) in accessLogs"
|
||||
:key="index"
|
||||
:clickable="false"
|
||||
>
|
||||
<template #content>
|
||||
<span>
|
||||
{{
|
||||
formatDateTitle(accessLog.stamp, {
|
||||
showTime: true,
|
||||
shortDay: true,
|
||||
shortMonth: true,
|
||||
showSeconds: true
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
<span
|
||||
v-if="
|
||||
accessLog.platform &&
|
||||
accessLog.browser &&
|
||||
accessLog.version
|
||||
"
|
||||
>
|
||||
{{ accessLog.platform }} - {{ accessLog.browser }} -
|
||||
{{ accessLog.version }}
|
||||
</span>
|
||||
</template>
|
||||
</CardList>
|
||||
</QList>
|
||||
</QPage>
|
||||
</template>
|
|
@ -91,6 +91,7 @@ onBeforeUnmount(() => clearInterval(intervalId.value));
|
|||
v-else
|
||||
v-for="(connection, index) in connections"
|
||||
:key="index"
|
||||
:to="{ name: 'accessLog', params: { id: connection.userId } }"
|
||||
>
|
||||
<template #content>
|
||||
<span class="text-bold q-mb-sm">
|
||||
|
@ -132,6 +133,7 @@ onBeforeUnmount(() => clearInterval(intervalId.value));
|
|||
</QBtn>
|
||||
</template>
|
||||
</CardList>
|
||||
<pre>{{ connections }}</pre>
|
||||
</QList>
|
||||
</QPage>
|
||||
</template>
|
||||
|
|
|
@ -64,7 +64,7 @@ const supplantUser = async user => {
|
|||
v-else
|
||||
v-for="(user, index) in users"
|
||||
:key="index"
|
||||
:clickable="false"
|
||||
:to="{ name: 'accessLog', params: { id: user.id } }"
|
||||
>
|
||||
<template #content>
|
||||
<span class="text-bold q-mb-sm">
|
||||
|
|
|
@ -143,12 +143,20 @@ const routes = [
|
|||
},
|
||||
{
|
||||
name: 'adminUsers',
|
||||
path: 'admin/users',
|
||||
path: 'admin/users:/:id?',
|
||||
meta: {
|
||||
title: 'Users'
|
||||
},
|
||||
component: () => import('pages/Admin/UsersView.vue')
|
||||
},
|
||||
{
|
||||
name: 'accessLog',
|
||||
path: 'admin/access-log/:id?',
|
||||
meta: {
|
||||
title: 'Access log'
|
||||
},
|
||||
component: () => import('pages/Admin/AccessLogView.vue')
|
||||
},
|
||||
{
|
||||
name: 'adminConnections',
|
||||
path: 'admin/connections',
|
||||
|
|
Loading…
Reference in New Issue