forked from verdnatura/hedera-web
Merge pull request 'Fixes primera revisión' (!86) from wbuezas/hedera-web-mindshore:bugfix/fixes-primera-review into 4922-vueMigration
Reviewed-on: verdnatura/hedera-web#86
This commit is contained in:
commit
622ce6ae28
|
@ -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,17 +18,23 @@ 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 class="no-padding content-container col-10">
|
||||
<div
|
||||
class="no-padding content-container"
|
||||
:class="$slots.actions ? 'col-9' : 'full-width'"
|
||||
>
|
||||
<slot name="prepend" />
|
||||
<div class="content">
|
||||
<slot name="content" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="no-padding flex full-width justify-center">
|
||||
<div class="no-padding flex column justify-center">
|
||||
<slot name="actions" />
|
||||
</div>
|
||||
</QItem>
|
||||
|
|
|
@ -93,7 +93,7 @@ const url = computed(() => {
|
|||
class="main-image"
|
||||
:src="url"
|
||||
v-bind="$attrs"
|
||||
@click="showZoom = !showZoom"
|
||||
@click.stop.prevent="showZoom = !showZoom"
|
||||
spinner-color="primary"
|
||||
:width="props.width"
|
||||
:height="props.height"
|
||||
|
|
|
@ -64,7 +64,7 @@ export default {
|
|||
Users: 'Usuaris',
|
||||
Connections: 'Connexions',
|
||||
Visits: 'Visites',
|
||||
News: 'Notícies',
|
||||
News: 'Gestió de noticies',
|
||||
Photos: 'Imatges',
|
||||
Images: 'Imatges',
|
||||
Items: 'Articles',
|
||||
|
@ -78,6 +78,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:
|
||||
|
@ -92,7 +93,6 @@ export default {
|
|||
delete: 'Esborrar',
|
||||
confirmDelete: 'Estàs segur que vols esborrar la línia?',
|
||||
emptyList: 'Llista buida',
|
||||
|
||||
logInAsGuest: `Accedir com a convidat`,
|
||||
haveForgottenPassword: '¿Has oblidat la teva contrasenya?',
|
||||
signUp: 'Registrar-me',
|
||||
|
@ -102,5 +102,34 @@ export default {
|
|||
remindMe: "Recorda'm",
|
||||
user: 'Usuari',
|
||||
password: 'Contrasenya',
|
||||
modify: 'Modificar'
|
||||
modify: 'Modificar',
|
||||
// Image related translations
|
||||
'Cant lock cache': 'No es pot bloquejar la memòria cau',
|
||||
'Bad file format': 'Format de fitxer no reconegut',
|
||||
'File not choosed': 'No has seleccionat cap fitxer',
|
||||
'Permission denied': 'No tens permís per pujar el fitxer',
|
||||
'File upload error':
|
||||
"No s'ha pogut pujar el fitxer, comprova que la mida no sigui massa gran",
|
||||
'File save error': "No s'ha pogut desar el fitxer: %s",
|
||||
'File size error': 'El fitxer no ha de superar %.2f MB',
|
||||
'Bad file name':
|
||||
"El nom del fitxer només ha de contenir lletres minúscules, dígits o el caràcter '_'",
|
||||
'Bad collection name': 'Nom de col·lecció no vàlid',
|
||||
'Collection not exists': 'La col·lecció no existeix',
|
||||
'Unreferenced file': 'El fitxer no està referenciat per la base de dades',
|
||||
'Cannot update matching id': "No es pot actualitzar l'id coincident",
|
||||
'Com error': 'Error de comunicació amb el servidor',
|
||||
'Image open error': "Error en obrir el fitxer d'imatge",
|
||||
'Operation disabled': 'Operació deshabilitada per seguretat',
|
||||
'Image added': 'Imatge afegida correctament',
|
||||
ErrIniSize: 'El fitxer supera la directiva upload_max_filesize a php.ini',
|
||||
ErrFormSize:
|
||||
'El fitxer supera el MAX_FILE_SIZE especificat al formulari HTML',
|
||||
ErrPartial: "El fitxer s'ha pujat parcialment",
|
||||
ErrNoFile: "No s'ha pujat cap fitxer",
|
||||
ErrNoTmpDir: 'Falta una carpeta temporal',
|
||||
ErrCantWrite: "No s'ha pogut escriure el fitxer al disc",
|
||||
ErrExtension: "La pujada del fitxer s'ha aturat per una extensió",
|
||||
ErrDefault: 'Error de pujada desconegut',
|
||||
'Sync complete': 'Sincronització completa'
|
||||
};
|
||||
|
|
|
@ -76,7 +76,7 @@ export default {
|
|||
Users: 'Users',
|
||||
Connections: 'Connections',
|
||||
Visits: 'Visits',
|
||||
News: 'News',
|
||||
News: 'News management',
|
||||
Photos: 'Images',
|
||||
Images: 'Images',
|
||||
Items: 'Items',
|
||||
|
@ -90,6 +90,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',
|
||||
|
@ -134,5 +135,33 @@ export default {
|
|||
loginMail: "{'info'}{'@'}{'verdnatura.es'}",
|
||||
remindMe: 'Remember me',
|
||||
password: 'Password',
|
||||
modify: 'Modify'
|
||||
modify: 'Modify',
|
||||
// Image related translations
|
||||
'Cant lock cache': 'The cache could not be blocked',
|
||||
'Bad file format': 'Unrecognized file format',
|
||||
'File not choosed': 'You have not selected any file',
|
||||
'Permission denied': 'You are not allowed to upload the file',
|
||||
'File upload error':
|
||||
'Failed to upload the file, check that size is not too large',
|
||||
'File save error': 'Failed to save the file: %s',
|
||||
'File size error': 'The file must be no longer than %.2f MB',
|
||||
'Bad file name':
|
||||
"The file name must contain only lowercase letters, digits or the '_' character",
|
||||
'Bad collection name': 'Invalid collection name',
|
||||
'Collection not exists': 'Collection does not exist',
|
||||
'Unreferenced file': 'The file is not referenced by the database',
|
||||
'Cannot update matching id': 'Cannot update matching id',
|
||||
'Com error': 'Error communicating with the server',
|
||||
'Image open error': 'Error opening the image file',
|
||||
'Operation disabled': 'Operation disabled for security',
|
||||
'Image added': 'Image added correctly',
|
||||
ErrIniSize: 'File exceeds the upload_max_filesize directive in php.ini',
|
||||
ErrFormSize: 'File exceeds the MAX_FILE_SIZE specified in the HTML form',
|
||||
ErrPartial: 'File was partially uploaded',
|
||||
ErrNoFile: 'No file was uploaded',
|
||||
ErrNoTmpDir: 'Missing a temporary folder',
|
||||
ErrCantWrite: 'Failed to write file to disk',
|
||||
ErrExtension: 'File upload stopped by extension',
|
||||
ErrDefault: 'Unknown upload error',
|
||||
'Sync complete': 'Synchronization complete'
|
||||
};
|
||||
|
|
|
@ -73,7 +73,7 @@ export default {
|
|||
Users: 'Usuarios',
|
||||
Connections: 'Conexiones',
|
||||
Visits: 'Visitas',
|
||||
News: 'Noticias',
|
||||
News: 'Gestión de noticias',
|
||||
Photos: 'Imágenes',
|
||||
Images: 'Imágenes',
|
||||
Items: 'Artículos',
|
||||
|
@ -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:
|
||||
|
@ -133,5 +134,34 @@ export default {
|
|||
save: 'Guardar',
|
||||
cancel: 'Cancelar',
|
||||
of: 'de',
|
||||
modify: 'Modificar'
|
||||
modify: 'Modificar',
|
||||
// Image related translations
|
||||
'Cant lock cache': 'La caché no pudo ser bloqueada',
|
||||
'Bad file format': 'Formato de archivo no reconocido',
|
||||
'File not choosed': 'No has seleccionado ningún archivo',
|
||||
'Permission denied': 'No tienes permiso para subir el fichero',
|
||||
'File upload error':
|
||||
'Error al subir el fichero, comprueba que su tamaño no sea demasiado grande',
|
||||
'File save error': 'Error al guardar el fichero: %s',
|
||||
'File size error': 'El fichero no debe ocupar más de %.2f MB',
|
||||
'Bad file name':
|
||||
"El nombre del archivo solo debe contener letras minúsculas, dígitos o el carácter '_'",
|
||||
'Bad collection name': 'Nombre de colección no válido',
|
||||
'Collection not exists': 'La colección no existe',
|
||||
'Unreferenced file': 'El archivo no está referenciado por la base de datos',
|
||||
'Cannot update matching id':
|
||||
'No es posible actualizar los ítems con id coincidente',
|
||||
'Com error': 'Error en la comunicación con el servidor',
|
||||
'Image open error': 'Error al abrir el archivo de imagen',
|
||||
'Operation disabled': 'Operación deshabilitada por seguridad',
|
||||
'Image added': 'Imagen añadida correctamente',
|
||||
ErrIniSize: 'File exceeds the upload_max_filesize directive in php.ini',
|
||||
ErrFormSize: 'File exceeds the MAX_FILE_SIZE specified in the HTML form',
|
||||
ErrPartial: 'File was partially uploaded',
|
||||
ErrNoFile: 'No file was uploaded',
|
||||
ErrNoTmpDir: 'Missing a temporary folder',
|
||||
ErrCantWrite: 'Failed to write file to disk',
|
||||
ErrExtension: 'File upload stopped by extension',
|
||||
ErrDefault: 'Unknown upload error',
|
||||
'Sync complete': 'Sincronización completada'
|
||||
};
|
||||
|
|
|
@ -64,7 +64,7 @@ export default {
|
|||
Users: 'Utilisateurs',
|
||||
Connections: 'Connexions',
|
||||
Visits: 'Visites',
|
||||
News: 'Nouvelles',
|
||||
News: 'Gestion des nouvelles',
|
||||
Photos: 'Images',
|
||||
Images: 'Images',
|
||||
Items: 'Articles',
|
||||
|
@ -78,6 +78,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:
|
||||
|
@ -90,9 +91,8 @@ export default {
|
|||
noData: 'Aucune donnée',
|
||||
confirm: 'Confirmer',
|
||||
delete: 'Effacer',
|
||||
emptyList: 'Vider la liste',
|
||||
confirmDelete: 'Voulez-vous vraiment supprimer la ligne?',
|
||||
emptyList: 'Liste vide',
|
||||
|
||||
logInAsGuest: `Entrez en tant qu'invité`,
|
||||
haveForgottenPassword: 'Avez-vous oublié votre mot de passe?',
|
||||
signUp: `S'inscrire`,
|
||||
|
@ -102,5 +102,37 @@ export default {
|
|||
remindMe: `Rappelle-moi`,
|
||||
user: 'Utilisateur',
|
||||
password: 'Mot de passe',
|
||||
modify: 'Modifier'
|
||||
modify: 'Modifier',
|
||||
// Image related translations
|
||||
'Cant lock cache': "Le cache n'a pas pu être verrouillé",
|
||||
'Bad file format': 'Format de fichier non reconnu',
|
||||
'File not choosed': "Vous n'avez sélectionné aucun fichier",
|
||||
'Permission denied': "Vous n'êtes pas autorisé à télécharger le fichier",
|
||||
'File upload error':
|
||||
"Échec du téléchargement du fichier, vérifiez que la taille n'est pas trop grande",
|
||||
'File save error': "Échec de l'enregistrement du fichier : %s",
|
||||
'File size error': 'Le fichier ne doit pas dépasser %.2f MB',
|
||||
'Bad file name':
|
||||
"Le nom du fichier ne doit contenir que des lettres minuscules, des chiffres ou le caractère '_'",
|
||||
'Bad collection name': 'Nom de collection invalide',
|
||||
'Collection not exists': "La collection n'existe pas",
|
||||
'Unreferenced file':
|
||||
"Le fichier n'est pas référencé par la base de données",
|
||||
'Cannot update matching id':
|
||||
"Impossible de mettre à jour l'ID correspondant",
|
||||
'Com error': 'Erreur de communication avec le serveur',
|
||||
'Image open error': "Erreur lors de l'ouverture du fichier image",
|
||||
'Operation disabled': 'Opération désactivée pour des raisons de sécurité',
|
||||
'Image added': 'Image ajoutée correctement',
|
||||
ErrIniSize:
|
||||
'Le fichier dépasse la directive upload_max_filesize dans php.ini',
|
||||
ErrFormSize:
|
||||
'Le fichier dépasse la taille maximale spécifiée dans le formulaire HTML',
|
||||
ErrPartial: 'Le fichier a été partiellement téléchargé',
|
||||
ErrNoFile: "Aucun fichier n'a été téléchargé",
|
||||
ErrNoTmpDir: 'Il manque un dossier temporaire',
|
||||
ErrCantWrite: "Échec de l'écriture du fichier sur le disque",
|
||||
ErrExtension: 'Téléchargement du fichier arrêté par extension',
|
||||
ErrDefault: 'Erreur de téléchargement inconnue',
|
||||
'Sync complete': 'Synchronisation terminée'
|
||||
};
|
||||
|
|
|
@ -63,7 +63,7 @@ export default {
|
|||
Users: 'Usuários',
|
||||
Connections: 'Conexões',
|
||||
Visits: 'Visitas',
|
||||
News: 'Notícias',
|
||||
News: 'Gestão de noticias',
|
||||
Photos: 'Imagens',
|
||||
Images: 'Imagens',
|
||||
Items: 'Artigos',
|
||||
|
@ -77,6 +77,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',
|
||||
|
@ -90,7 +91,6 @@ export default {
|
|||
delete: 'Eliminar',
|
||||
confirmDelete: 'Tens certeza que queres eliminar esta linha?',
|
||||
emptyList: 'Lista vazia',
|
||||
|
||||
logInAsGuest: 'Entrar como convidado',
|
||||
haveForgottenPassword: 'Esqueceu a senha?',
|
||||
signUp: 'Registar',
|
||||
|
@ -100,5 +100,33 @@ export default {
|
|||
remindMe: 'Lembrar-me',
|
||||
user: 'Utilizador',
|
||||
password: 'Senha',
|
||||
modify: 'Modificar'
|
||||
modify: 'Modificar',
|
||||
// Image related translations
|
||||
'Cant lock cache': 'O cache não pôde ser bloqueado',
|
||||
'Bad file format': 'Formato de arquivo inválido',
|
||||
'File not choosed': 'Não selecionastes nenhum arquivo',
|
||||
'Permission denied': 'Não estas autorizado a subir o arquivo',
|
||||
'File upload error': 'Erro ao subir o arquivo, verifique o tamanho',
|
||||
'File save error': 'Erro ao salvar o arquivo: %s',
|
||||
'File size error': 'O arquivo não deve ser maior que %.2f MB',
|
||||
'Bad file name':
|
||||
"O nome do arquivo deve conter somente letras minusculas, numeros ou '_'",
|
||||
'Bad collection name': 'Nome de coleção inválido',
|
||||
'Collection not exists': 'Coleção não existe',
|
||||
'Unreferenced file': 'O arquivo não é referenciado pelo banco de dados',
|
||||
'Cannot update matching id':
|
||||
'Não é possível atualizar os itens com id coincidente',
|
||||
'Com error': 'Erro de comunicação com o servidor',
|
||||
'Image open error': 'Erro ao abrir a imagem',
|
||||
'Operation disabled': 'Operação desativada por segurança',
|
||||
'Image added': 'Imagem adicionada corretamente',
|
||||
ErrIniSize: 'Arquivo supera o tamanho maximo de protocolo em php.ini',
|
||||
ErrFormSize: 'Arquivo supera o tamanho maximo de protocolo em HTML form',
|
||||
ErrPartial: 'Arquivo subido parcialmente',
|
||||
ErrNoFile: 'Nenhum arquivo subido',
|
||||
ErrNoTmpDir: 'Falta a pasta de arquivo temporal',
|
||||
ErrCantWrite: 'Erro ao gravar arquivo no disco',
|
||||
ErrExtension: 'Erro de extensão do arquivo',
|
||||
ErrDefault: 'Erro desconhecido ao subir arquivo',
|
||||
'Sync complete': 'Sincronização completa'
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -15,6 +15,7 @@ const { t } = useI18n();
|
|||
const jApi = inject('jApi');
|
||||
const appStore = useAppStore();
|
||||
const { isHeaderMounted } = storeToRefs(appStore);
|
||||
const { user } = storeToRefs(userStore);
|
||||
|
||||
const vnFormRef = ref(null);
|
||||
const vnFormRef2 = ref(null);
|
||||
|
@ -43,6 +44,15 @@ const fetchLanguagesSql = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
const updateUserNickname = async nickname => {
|
||||
try {
|
||||
await vnFormRef.value.submit();
|
||||
user.value.nickname = nickname;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => fetchLanguagesSql());
|
||||
</script>
|
||||
|
||||
|
@ -90,8 +100,8 @@ onMounted(() => fetchLanguagesSql());
|
|||
<VnInput
|
||||
v-model="data.nickname"
|
||||
:label="t('nickname')"
|
||||
@keyup.enter="vnFormRef.submit()"
|
||||
@blur="vnFormRef.submit()"
|
||||
@keyup.enter="updateUserNickname(data.nickname)"
|
||||
@blur="updateUserNickname(data.nickname)"
|
||||
/>
|
||||
<VnSelect
|
||||
v-model="data.lang"
|
||||
|
|
|
@ -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">
|
||||
|
@ -124,7 +125,7 @@ onBeforeUnmount(() => clearInterval(intervalId.value));
|
|||
icon="people"
|
||||
flat
|
||||
rounded
|
||||
@click="supplantUser(connection.user)"
|
||||
@click.stop.prevent="supplantUser(connection.user)"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('supplantUser') }}
|
||||
|
@ -132,6 +133,7 @@ onBeforeUnmount(() => clearInterval(intervalId.value));
|
|||
</QBtn>
|
||||
</template>
|
||||
</CardList>
|
||||
<pre>{{ connections }}</pre>
|
||||
</QList>
|
||||
</QPage>
|
||||
</template>
|
||||
|
|
|
@ -65,7 +65,7 @@ onMounted(async () => getNews());
|
|||
<QTooltip>{{ t('addNew') }}</QTooltip>
|
||||
</QBtn>
|
||||
</Teleport>
|
||||
<QPage class="vn-w-xs">
|
||||
<QPage class="vn-w-sm">
|
||||
<QList class="flex justify-center">
|
||||
<QSpinner
|
||||
v-if="loading"
|
||||
|
|
|
@ -13,11 +13,24 @@ const { t } = useI18n();
|
|||
const { notify } = useNotify();
|
||||
|
||||
const fileUploaderRef = ref(null);
|
||||
|
||||
const statusIcons = {
|
||||
uploading: 'cloud_upload',
|
||||
fulfilled: 'cloud_done',
|
||||
rejected: 'error',
|
||||
pending: 'add'
|
||||
uploading: {
|
||||
icon: 'cloud_upload',
|
||||
tooltip: 'Uploading'
|
||||
},
|
||||
fulfilled: {
|
||||
icon: 'cloud_done',
|
||||
tooltip: 'imageUploaded'
|
||||
},
|
||||
rejected: {
|
||||
icon: 'error',
|
||||
tooltip: 'Error'
|
||||
},
|
||||
pending: {
|
||||
icon: 'add',
|
||||
tooltip: 'pendingUpload'
|
||||
}
|
||||
};
|
||||
const formInitialData = reactive({
|
||||
schema: 'catalog',
|
||||
|
@ -72,6 +85,12 @@ const onSubmit = async data => {
|
|||
results.forEach((result, index) => {
|
||||
const fileIndex = filteredFiles[index].index;
|
||||
addedFiles.value[fileIndex].uploadStatus = result.status;
|
||||
|
||||
if (result.status === 'rejected') {
|
||||
addedFiles.value[fileIndex].errorMessage = t(
|
||||
result.reason?.response?.data?.data?.message
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const allSuccessful = results.every(
|
||||
|
@ -122,10 +141,10 @@ onMounted(async () => getImageCollections());
|
|||
<QPage class="vn-w-sm">
|
||||
<VnForm
|
||||
ref="vnFormRef"
|
||||
:defaultActions="false"
|
||||
:formInitialData="formInitialData"
|
||||
separationBetweenInputs="md"
|
||||
showBottomActions
|
||||
:default-actions="false"
|
||||
:form-initial-data="formInitialData"
|
||||
separation-between-inputs="md"
|
||||
show-bottom-actions
|
||||
>
|
||||
<template #form="{ data }">
|
||||
<VnSelect
|
||||
|
@ -146,7 +165,7 @@ onMounted(async () => getImageCollections());
|
|||
hide-upload-btn
|
||||
@added="onFilesAdded"
|
||||
>
|
||||
<template v-slot:list="scope">
|
||||
<template #list="scope">
|
||||
<QList v-if="addedFiles.length" separator>
|
||||
<QItem
|
||||
v-for="(file, index) in scope.files"
|
||||
|
@ -182,10 +201,22 @@ onMounted(async () => getImageCollections());
|
|||
:name="
|
||||
statusIcons[
|
||||
addedFiles[index].uploadStatus
|
||||
]
|
||||
].icon
|
||||
"
|
||||
size="sm"
|
||||
/>
|
||||
>
|
||||
<QTooltip>
|
||||
{{
|
||||
addedFiles[index].errorMessage ||
|
||||
t(
|
||||
statusIcons[
|
||||
addedFiles[index]
|
||||
.uploadStatus
|
||||
].tooltip
|
||||
)
|
||||
}}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
<QBtn
|
||||
v-if="
|
||||
addedFiles[index].uploadStatus !==
|
||||
|
@ -198,7 +229,9 @@ onMounted(async () => getImageCollections());
|
|||
round
|
||||
icon="delete"
|
||||
@click="removeFile(file, index)"
|
||||
/>
|
||||
>
|
||||
<QTooltip>{{ t('remove') }}</QTooltip>
|
||||
</QBtn>
|
||||
</QItem>
|
||||
</QList>
|
||||
</template>
|
||||
|
@ -239,6 +272,8 @@ en-US:
|
|||
uploadSuccess: Upload finished successfully
|
||||
uploadError: Some errors happened on upload
|
||||
noFilesToUpload: There are no files to upload
|
||||
pendingUpload: Pending upload
|
||||
imageUploaded: Image uploaded
|
||||
es-ES:
|
||||
collection: Colección
|
||||
updateMatching: Actualizar artículos con id coincidente
|
||||
|
@ -248,6 +283,8 @@ es-ES:
|
|||
uploadSuccess: Imágenes subidas correctamente
|
||||
uploadError: Ocurrieron errores al subir alguna de las imágenes
|
||||
noFilesToUpload: No se han seleccionado archivos para subir
|
||||
pendingUpload: Subida pendiente
|
||||
imageUploaded: Imagen subida
|
||||
ca-ES:
|
||||
collection: Col·lecció
|
||||
updateMatching: Actualitzar els elements amb id coincident
|
||||
|
@ -257,6 +294,8 @@ ca-ES:
|
|||
uploadSuccess: Imatges pujades correctament
|
||||
uploadError: Van ocórrer errors en pujar alguna de les imatges
|
||||
noFilesToUpload: No s'ha seleccionat arxius per pujar
|
||||
pendingUpload: Pujada pendent
|
||||
imageUploaded: Imatge pujada
|
||||
fr-FR:
|
||||
collection: Collection
|
||||
updateMatching: Mettre à jour les éléments avec l'identifiant correspondant
|
||||
|
@ -266,6 +305,8 @@ fr-FR:
|
|||
uploadSuccess: Les images téléchargées correctement
|
||||
uploadError: Des erreurs sont survenues lors du téléchargement des images
|
||||
noFilesToUpload: Aucun fichier sélectionné pour télécharger
|
||||
pendingUpload: Téléchargement en attente
|
||||
imageUploaded: Image téléchargée
|
||||
pt-PT:
|
||||
collection: Coleção
|
||||
updateMatching: Atualizar itens com id correspondente
|
||||
|
@ -275,4 +316,6 @@ pt-PT:
|
|||
uploadSuccess: Upload concluído com sucesso
|
||||
uploadError: Ocorreram erros ao subir alguma das imagens
|
||||
noFilesToUpload: Não há arquivos selecionados para upload
|
||||
pendingUpload: Upload pendente
|
||||
imageUploaded: Imagem carregada
|
||||
</i18n>
|
||||
|
|
|
@ -9,14 +9,12 @@ import VnSearchBar from 'src/components/ui/VnSearchBar.vue';
|
|||
import { useAppStore } from 'stores/app';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useUserStore } from 'stores/user';
|
||||
import useNotify from 'src/composables/useNotify.js';
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
const appStore = useAppStore();
|
||||
const { isHeaderMounted } = storeToRefs(appStore);
|
||||
const { notify } = useNotify();
|
||||
|
||||
const loading = ref(false);
|
||||
const users = ref([]);
|
||||
|
@ -37,7 +35,6 @@ const supplantUser = async user => {
|
|||
router.push({ name: 'confirmedOrders' });
|
||||
} catch (error) {
|
||||
console.error('Error supplanting user:', error);
|
||||
notify(error.message, 'negative');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@ -67,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">
|
||||
|
@ -77,14 +74,17 @@ const supplantUser = async user => {
|
|||
</template>
|
||||
<template #actions>
|
||||
<QBtn
|
||||
v-if="user.active"
|
||||
icon="people"
|
||||
flat
|
||||
rounded
|
||||
@click="supplantUser(user.name)"
|
||||
><QTooltip>
|
||||
{{ t('Impersonate user') }}
|
||||
</QTooltip></QBtn
|
||||
@click.stop.prevent="supplantUser(user.name)"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Impersonate user') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
<QBadge v-else color="negative">{{ t('Disabled') }}</QBadge>
|
||||
</template>
|
||||
</CardList>
|
||||
</QList>
|
||||
|
|
|
@ -85,9 +85,7 @@ onMounted(async () => {
|
|||
>
|
||||
<template #content>
|
||||
<QItemLabel class="text-bold q-mb-sm">
|
||||
{{
|
||||
formatDateTitle(order.sent)
|
||||
}}
|
||||
{{ formatDateTitle(order.sent) }}
|
||||
</QItemLabel>
|
||||
<QItemLabel> #{{ order.id }} </QItemLabel>
|
||||
<QItemLabel>{{ order.nickname }}</QItemLabel>
|
||||
|
@ -106,13 +104,17 @@ onMounted(async () => {
|
|||
() => removeOrder(order.id, index)
|
||||
)
|
||||
"
|
||||
/>
|
||||
>
|
||||
<QTooltip>{{ t('deleteOrder') }}</QTooltip>
|
||||
</QBtn>
|
||||
<QBtn
|
||||
icon="shopping_bag"
|
||||
flat
|
||||
rounded
|
||||
@click.stop.prevent="loadOrder(order.id)"
|
||||
/>
|
||||
>
|
||||
<QTooltip>{{ t('loadOrderIntoCart') }}</QTooltip>
|
||||
</QBtn>
|
||||
</template>
|
||||
</CardList>
|
||||
</QPage>
|
||||
|
@ -124,16 +126,26 @@ onMounted(async () => {
|
|||
en-US:
|
||||
newOrder: New order
|
||||
areYouSureDeleteOrder: Are you sure you want to delete the order?
|
||||
deleteOrder: Delete order
|
||||
loadOrderIntoCart: Load order into cart
|
||||
es-ES:
|
||||
newOrder: Nuevo pedido
|
||||
areYouSureDeleteOrder: ¿Seguro que quieres borrar el pedido?
|
||||
deleteOrder: Eliminar pedido
|
||||
loadOrderIntoCart: Cargar pedido en la cesta
|
||||
ca-ES:
|
||||
newOrder: Nova comanda
|
||||
areYouSureDeleteOrder: Segur que vols esborrar la comanda?
|
||||
deleteOrder: Eliminar comanda
|
||||
loadOrderIntoCart: Carregar comanda a la cistella
|
||||
fr-FR:
|
||||
newOrder: Nouvelle commande
|
||||
areYouSureDeleteOrder: Êtes-vous sûr de vouloir supprimer la commande?
|
||||
deleteOrder: Supprimer la commande
|
||||
loadOrderIntoCart: Charger la commande dans le panier
|
||||
pt-PT:
|
||||
newOrder: Novo pedido
|
||||
areYouSureDeleteOrder: Tem certeza de que deseja excluir o pedido?
|
||||
deleteOrder: Excluir pedido
|
||||
loadOrderIntoCart: Carregar pedido no carrinho
|
||||
</i18n>
|
||||
|
|
|
@ -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