0
1
Fork 0

Create VnList

This commit is contained in:
William Buezas 2024-09-26 15:02:40 -03:00
parent 4358ef70c0
commit 577a6281b8
14 changed files with 137 additions and 116 deletions

View File

@ -0,0 +1,38 @@
<script setup>
import { useI18n } from 'vue-i18n';
defineProps({
emptyMessage: {
type: String,
default: 'emptyList'
},
emptyIcon: {
type: String,
default: 'block'
},
rows: {
type: Array,
default: () => []
},
loading: {
type: Boolean,
default: false
}
});
const { t } = useI18n();
</script>
<template>
<QList v-bind="$attrs" class="column items-center">
<span
v-if="!rows?.length"
class="flex items-center q-pa-md justify-center items-center"
>
<QIcon :name="emptyIcon" size="sm" class="q-mr-sm" />
{{ t(emptyMessage) }}
</span>
<QSpinner v-if="loading" color="primary" size="3em" :thickness="2" />
<slot v-else />
</QList>
</template>

View File

@ -106,6 +106,8 @@ export default {
shoppingCart: 'Cistella de la compra', shoppingCart: 'Cistella de la compra',
available: 'Disponible', available: 'Disponible',
minQuantity: 'Quantitat mínima', minQuantity: 'Quantitat mínima',
introduceSearchTerm: 'Introdueix un terme de cerca',
noOrdersFound: `No s'han trobat comandes`,
// Image related translations // Image related translations
'Cant lock cache': 'No es pot bloquejar la memòria cau', 'Cant lock cache': 'No es pot bloquejar la memòria cau',
'Bad file format': 'Format de fitxer no reconegut', 'Bad file format': 'Format de fitxer no reconegut',

View File

@ -139,6 +139,8 @@ export default {
shoppingCart: 'Shopping cart', shoppingCart: 'Shopping cart',
available: 'Available', available: 'Available',
minQuantity: 'Minimum quantity', minQuantity: 'Minimum quantity',
introduceSearchTerm: 'Enter a search term',
noOrdersFound: 'No orders found',
// Image related translations // Image related translations
'Cant lock cache': 'The cache could not be blocked', 'Cant lock cache': 'The cache could not be blocked',
'Bad file format': 'Unrecognized file format', 'Bad file format': 'Unrecognized file format',

View File

@ -138,6 +138,8 @@ export default {
shoppingCart: 'Cesta de la compra', shoppingCart: 'Cesta de la compra',
available: 'Disponible', available: 'Disponible',
minQuantity: 'Cantidad mínima', minQuantity: 'Cantidad mínima',
introduceSearchTerm: 'Introduce un término de búsqueda',
noOrdersFound: 'No se encontrado pedidos',
// Image related translations // Image related translations
'Cant lock cache': 'La caché no pudo ser bloqueada', 'Cant lock cache': 'La caché no pudo ser bloqueada',
'Bad file format': 'Formato de archivo no reconocido', 'Bad file format': 'Formato de archivo no reconocido',

View File

@ -106,6 +106,8 @@ export default {
shoppingCart: 'Panier', shoppingCart: 'Panier',
available: 'Disponible', available: 'Disponible',
minQuantity: 'Quantité minimum', minQuantity: 'Quantité minimum',
introduceSearchTerm: 'Entrez un terme de recherche',
noOrdersFound: 'Aucune commande trouvée',
// Image related translations // Image related translations
'Cant lock cache': "Le cache n'a pas pu être verrouillé", 'Cant lock cache': "Le cache n'a pas pu être verrouillé",
'Bad file format': 'Format de fichier non reconnu', 'Bad file format': 'Format de fichier non reconnu',

View File

@ -104,6 +104,8 @@ export default {
shoppingCart: 'Cesta da compra', shoppingCart: 'Cesta da compra',
available: 'Disponível', available: 'Disponível',
minQuantity: 'Quantidade mínima', minQuantity: 'Quantidade mínima',
introduceSearchTerm: 'Digite um termo de pesquisa',
noOrdersFound: 'Nenhum pedido encontrado',
// Image related translations // Image related translations
'Cant lock cache': 'O cache não pôde ser bloqueado', 'Cant lock cache': 'O cache não pôde ser bloqueado',
'Bad file format': 'Formato de arquivo inválido', 'Bad file format': 'Formato de arquivo inválido',

View File

@ -4,6 +4,7 @@ import { ref, onMounted, inject } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import CardList from 'src/components/ui/CardList.vue'; import CardList from 'src/components/ui/CardList.vue';
import VnList from 'src/components/ui/VnList.vue';
import useNotify from 'src/composables/useNotify.js'; import useNotify from 'src/composables/useNotify.js';
import { useVnConfirm } from 'src/composables/useVnConfirm.js'; import { useVnConfirm } from 'src/composables/useVnConfirm.js';
@ -104,7 +105,11 @@ onMounted(async () => {
</QBtn> </QBtn>
</Teleport> </Teleport>
<QPage class="vn-w-sm"> <QPage class="vn-w-sm">
<QList class="rounded-borders shadow-1 shadow-transition" separator> <VnList
class="rounded-borders shadow-1 shadow-transition"
separator
:rows="addresses"
>
<CardList <CardList
v-for="(address, index) in addresses" v-for="(address, index) in addresses"
:key="index" :key="index"
@ -158,7 +163,7 @@ onMounted(async () => {
</QBtn> </QBtn>
</template> </template>
</CardList> </CardList>
</QList> </VnList>
</QPage> </QPage>
</template> </template>

View File

@ -3,6 +3,7 @@ import { onMounted, inject, ref } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import CardList from 'src/components/ui/CardList.vue'; import CardList from 'src/components/ui/CardList.vue';
import VnList from 'src/components/ui/VnList.vue';
import { formatDateTitle } from 'src/lib/filters.js'; import { formatDateTitle } from 'src/lib/filters.js';
@ -72,7 +73,7 @@ onMounted(async () => {
<span>{{ user?.phone }} </span> <span>{{ user?.phone }} </span>
</template> </template>
</CardList> </CardList>
<QList> <VnList :rows="accessLogs">
<CardList <CardList
v-for="(accessLog, index) in accessLogs" v-for="(accessLog, index) in accessLogs"
:key="index" :key="index"
@ -101,6 +102,6 @@ onMounted(async () => {
</span> </span>
</template> </template>
</CardList> </CardList>
</QList> </VnList>
</QPage> </QPage>
</template> </template>

View File

@ -4,6 +4,7 @@ import { useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import CardList from 'src/components/ui/CardList.vue'; import CardList from 'src/components/ui/CardList.vue';
import VnList from 'src/components/ui/VnList.vue';
import { date as qdate } from 'quasar'; import { date as qdate } from 'quasar';
import { useUserStore } from 'stores/user'; import { useUserStore } from 'stores/user';
@ -80,15 +81,12 @@ onBeforeUnmount(() => clearInterval(intervalId.value));
</div> </div>
</Teleport> </Teleport>
<QPage class="vn-w-xs"> <QPage class="vn-w-xs">
<QList class="flex justify-center"> <VnList
<QSpinner class="flex justify-center"
v-if="loading" :loading="loading"
color="primary" :rows="connections"
size="3em" >
:thickness="2"
/>
<CardList <CardList
v-else
v-for="(connection, index) in connections" v-for="(connection, index) in connections"
:key="index" :key="index"
:to="{ name: 'accessLog', params: { id: connection.userId } }" :to="{ name: 'accessLog', params: { id: connection.userId } }"
@ -133,8 +131,7 @@ onBeforeUnmount(() => clearInterval(intervalId.value));
</QBtn> </QBtn>
</template> </template>
</CardList> </CardList>
<pre>{{ connections }}</pre> </VnList>
</QList>
</QPage> </QPage>
</template> </template>

View File

@ -1,15 +1,14 @@
<script setup> <script setup>
import { ref } from 'vue'; import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import CardList from 'src/components/ui/CardList.vue'; import CardList from 'src/components/ui/CardList.vue';
import VnImg from 'src/components/ui/VnImg.vue'; import VnImg from 'src/components/ui/VnImg.vue';
import VnSearchBar from 'src/components/ui/VnSearchBar.vue'; import VnSearchBar from 'src/components/ui/VnSearchBar.vue';
import VnList from 'src/components/ui/VnList.vue';
import { useAppStore } from 'stores/app'; import { useAppStore } from 'stores/app';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
const { t } = useI18n();
const appStore = useAppStore(); const appStore = useAppStore();
const { isHeaderMounted } = storeToRefs(appStore); const { isHeaderMounted } = storeToRefs(appStore);
@ -39,19 +38,14 @@ const onSearch = data => (items.value = data || []);
/> />
</Teleport> </Teleport>
<QPage class="vn-w-xs"> <QPage class="vn-w-xs">
<QList class="flex justify-center"> <VnList
<span v-if="!loading && !items.length" class="flex items-center"> class="flex justify-center"
<QIcon name="refresh" size="sm" class="q-mr-sm" /> empty-message="introduceSearchTerm"
{{ t('introduceSearchTerm') }} empty-icon="refresh"
</span> :loading="loading"
<QSpinner :rows="items"
v-if="loading" >
color="primary"
size="3em"
:thickness="2"
/>
<CardList <CardList
v-else
v-for="(item, index) in items" v-for="(item, index) in items"
:key="index" :key="index"
:clickable="false" :clickable="false"
@ -82,19 +76,6 @@ const onSearch = data => (items.value = data || []);
<span>{{ item.image }}</span> <span>{{ item.image }}</span>
</template> </template>
</CardList> </CardList>
</QList> </VnList>
</QPage> </QPage>
</template> </template>
<i18n lang="yaml">
en-US:
introduceSearchTerm: Enter a search term
es-ES:
introduceSearchTerm: Introduce un término de búsqueda
ca-ES:
introduceSearchTerm: Introdueix un terme de cerca
fr-FR:
introduceSearchTerm: Entrez un terme de recherche
pt-PT:
introduceSearchTerm: Digite um termo de pesquisa
</i18n>

View File

@ -4,6 +4,7 @@ import { useI18n } from 'vue-i18n';
import CardList from 'src/components/ui/CardList.vue'; import CardList from 'src/components/ui/CardList.vue';
import VnImg from 'src/components/ui/VnImg.vue'; import VnImg from 'src/components/ui/VnImg.vue';
import VnList from 'src/components/ui/VnList.vue';
import { useAppStore } from 'stores/app'; import { useAppStore } from 'stores/app';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
@ -22,12 +23,14 @@ const news = ref([]);
const getNews = async () => { const getNews = async () => {
try { try {
loading.value = true;
news.value = await jApi.query( news.value = await jApi.query(
`SELECT n.id, u.nickname, n.priority, n.image, n.title `SELECT n.id, u.nickname, n.priority, n.image, n.title
FROM news n FROM news n
JOIN account.user u ON u.id = n.userFk JOIN account.user u ON u.id = n.userFk
ORDER BY priority, n.created DESC` ORDER BY priority, n.created DESC`
); );
loading.value = false;
} catch (error) { } catch (error) {
console.error('Error getting news:', error); console.error('Error getting news:', error);
} }
@ -66,15 +69,8 @@ onMounted(async () => getNews());
</QBtn> </QBtn>
</Teleport> </Teleport>
<QPage class="vn-w-sm"> <QPage class="vn-w-sm">
<QList class="flex justify-center"> <VnList class="flex justify-center" :loading="loading" :rows="news">
<QSpinner
v-if="loading"
color="primary"
size="3em"
:thickness="2"
/>
<CardList <CardList
v-else
v-for="(newsItem, index) in news" v-for="(newsItem, index) in news"
:key="index" :key="index"
:to="{ name: 'adminNewsDetails', params: { id: newsItem.id } }" :to="{ name: 'adminNewsDetails', params: { id: newsItem.id } }"
@ -115,7 +111,7 @@ onMounted(async () => getNews());
</QBtn> </QBtn>
</template> </template>
</CardList> </CardList>
</QList> </VnList>
</QPage> </QPage>
</template> </template>

View File

@ -5,6 +5,7 @@ import { useRouter } from 'vue-router';
import CardList from 'src/components/ui/CardList.vue'; import CardList from 'src/components/ui/CardList.vue';
import VnSearchBar from 'src/components/ui/VnSearchBar.vue'; import VnSearchBar from 'src/components/ui/VnSearchBar.vue';
import VnList from 'src/components/ui/VnList.vue';
import { useAppStore } from 'stores/app'; import { useAppStore } from 'stores/app';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
@ -49,19 +50,14 @@ const supplantUser = async user => {
/> />
</Teleport> </Teleport>
<QPage class="vn-w-xs"> <QPage class="vn-w-xs">
<QList class="flex justify-center"> <VnList
<span v-if="!loading && !users.length" class="flex items-center"> class="flex justify-center"
<QIcon name="refresh" size="sm" class="q-mr-sm" /> empty-message="noData"
{{ t('noData') }} empty-icon="refresh"
</span> :loading="loading"
<QSpinner :rows="users"
v-if="loading" >
color="primary"
size="3em"
:thickness="2"
/>
<CardList <CardList
v-else
v-for="(user, index) in users" v-for="(user, index) in users"
:key="index" :key="index"
:to="{ name: 'accessLog', params: { id: user.id } }" :to="{ name: 'accessLog', params: { id: user.id } }"
@ -87,7 +83,7 @@ const supplantUser = async user => {
<QBadge v-else color="negative">{{ t('Disabled') }}</QBadge> <QBadge v-else color="negative">{{ t('Disabled') }}</QBadge>
</template> </template>
</CardList> </CardList>
</QList> </VnList>
</QPage> </QPage>
</template> </template>

View File

@ -6,6 +6,7 @@ import { useI18n } from 'vue-i18n';
import CardList from 'src/components/ui/CardList.vue'; import CardList from 'src/components/ui/CardList.vue';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
import VnConfirm from 'src/components/ui/VnConfirm.vue'; import VnConfirm from 'src/components/ui/VnConfirm.vue';
import VnList from 'src/components/ui/VnList.vue';
import useNotify from 'src/composables/useNotify.js'; import useNotify from 'src/composables/useNotify.js';
import { currency, formatDateTitle } from 'src/lib/filters.js'; import { currency, formatDateTitle } from 'src/lib/filters.js';
@ -90,13 +91,7 @@ const onConfirmPay = async () => {
</QBtn> </QBtn>
</Teleport> </Teleport>
<QPage class="vn-w-sm"> <QPage class="vn-w-sm">
<div <VnList empty-message="noOrdersFound" :loading="loading" :rows="orders">
v-if="!orders?.length"
class="text-subtitle1 text-center text-grey-7 q-pa-md"
>
{{ t('noOrdersFound') }}
</div>
<QList v-if="orders?.length">
<CardList <CardList
v-for="order in orders" v-for="order in orders"
:key="order.id" :key="order.id"
@ -115,7 +110,7 @@ const onConfirmPay = async () => {
<QItemLabel>{{ order.agency }}</QItemLabel> <QItemLabel>{{ order.agency }}</QItemLabel>
</template> </template>
</CardList> </CardList>
</QList> </VnList>
<QPageSticky> <QPageSticky>
<QBtn <QBtn
fab fab
@ -172,7 +167,6 @@ const onConfirmPay = async () => {
<i18n lang="yaml"> <i18n lang="yaml">
en-US: en-US:
startOrder: Start order startOrder: Start order
noOrdersFound: No orders found
makePayment: Make payment makePayment: Make payment
balance: 'Balance:' balance: 'Balance:'
paymentInfo: >- paymentInfo: >-
@ -184,7 +178,6 @@ en-US:
amountError: The amount must be a positive number less than or equal to the outstanding amount amountError: The amount must be a positive number less than or equal to the outstanding amount
es-ES: es-ES:
startOrder: Empezar pedido startOrder: Empezar pedido
noOrdersFound: No se encontrado pedidos
makePayment: Realizar pago makePayment: Realizar pago
balance: 'Saldo:' balance: 'Saldo:'
paymentInfo: >- paymentInfo: >-
@ -197,7 +190,6 @@ es-ES:
amountError: La cantidad debe ser un número positivo e inferior o igual al importe pendiente amountError: La cantidad debe ser un número positivo e inferior o igual al importe pendiente
ca-ES: ca-ES:
startOrder: Començar encàrrec startOrder: Començar encàrrec
noOrdersFound: No s'han trobat comandes
makePayment: Realitzar pagament makePayment: Realitzar pagament
balance: 'Saldo:' balance: 'Saldo:'
paymentInfo: >- paymentInfo: >-
@ -210,7 +202,6 @@ ca-ES:
amountError: La quantitat ha de ser un nombre positiu i inferior o igual a l'import pendent amountError: La quantitat ha de ser un nombre positiu i inferior o igual a l'import pendent
fr-FR: fr-FR:
startOrder: Acheter startOrder: Acheter
noOrdersFound: Aucune commande trouvée
makePayment: Effectuer un paiement makePayment: Effectuer un paiement
balance: 'Balance:' balance: 'Balance:'
paymentInfo: >- paymentInfo: >-
@ -223,7 +214,6 @@ fr-FR:
amountError: La quantité doit être un neméro positif et inférieur ou égal à la somme restant à payer amountError: La quantité doit être un neméro positif et inférieur ou égal à la somme restant à payer
pt-PT: pt-PT:
startOrder: Iniciar encomenda startOrder: Iniciar encomenda
noOrdersFound: Nenhum pedido encontrado
makePayment: Realizar pagamento makePayment: Realizar pagamento
balance: 'Saldo:' balance: 'Saldo:'
paymentInfo: >- paymentInfo: >-

View File

@ -4,6 +4,8 @@ import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import CardList from 'src/components/ui/CardList.vue'; import CardList from 'src/components/ui/CardList.vue';
import VnList from 'src/components/ui/VnList.vue';
import { currency, formatDateTitle } from 'src/lib/filters.js'; import { currency, formatDateTitle } from 'src/lib/filters.js';
import { useVnConfirm } from 'src/composables/useVnConfirm.js'; import { useVnConfirm } from 'src/composables/useVnConfirm.js';
import useNotify from 'src/composables/useNotify.js'; import useNotify from 'src/composables/useNotify.js';
@ -18,10 +20,12 @@ const appStore = useAppStore();
const { isHeaderMounted } = storeToRefs(appStore); const { isHeaderMounted } = storeToRefs(appStore);
const router = useRouter(); const router = useRouter();
const loading = ref(false);
const orders = ref([]); const orders = ref([]);
const getOrders = async () => { const getOrders = async () => {
try { try {
loading.value = true;
orders.value = await jApi.query( orders.value = await jApi.query(
`SELECT o.id, o.sent, o.deliveryMethodFk, o.taxableBase, `SELECT o.id, o.sent, o.deliveryMethodFk, o.taxableBase,
a.nickname, am.description agency a.nickname, am.description agency
@ -31,6 +35,7 @@ const getOrders = async () => {
WHERE NOT o.isConfirmed WHERE NOT o.isConfirmed
ORDER BY o.sent DESC` ORDER BY o.sent DESC`
); );
loading.value = false;
} catch (error) { } catch (error) {
console.error('Error getting orders:', error); console.error('Error getting orders:', error);
} }
@ -78,45 +83,47 @@ onMounted(async () => {
</QBtn> </QBtn>
</Teleport> </Teleport>
<QPage class="vn-w-sm"> <QPage class="vn-w-sm">
<CardList <VnList :rows="orders" :loading="loading">
v-for="(order, index) in orders" <CardList
:key="index" v-for="(order, index) in orders"
:to="{ name: 'basket', params: { id: order.id } }" :key="index"
> :to="{ name: 'basket', params: { id: order.id } }"
<template #content> >
<QItemLabel class="text-bold q-mb-sm"> <template #content>
{{ formatDateTitle(order.sent) }} <QItemLabel class="text-bold q-mb-sm">
</QItemLabel> {{ formatDateTitle(order.sent) }}
<QItemLabel> #{{ order.id }} </QItemLabel> </QItemLabel>
<QItemLabel>{{ order.nickname }}</QItemLabel> <QItemLabel> #{{ order.id }} </QItemLabel>
<QItemLabel>{{ order.agency }}</QItemLabel> <QItemLabel>{{ order.nickname }}</QItemLabel>
<QItemLabel>{{ currency(order.taxableBase) }}</QItemLabel> <QItemLabel>{{ order.agency }}</QItemLabel>
</template> <QItemLabel>{{ currency(order.taxableBase) }}</QItemLabel>
<template #actions> </template>
<QBtn <template #actions>
icon="delete" <QBtn
flat icon="delete"
rounded flat
@click.stop.prevent=" rounded
openConfirmationModal( @click.stop.prevent="
null, openConfirmationModal(
t('areYouSureDeleteOrder'), null,
() => removeOrder(order.id, index) t('areYouSureDeleteOrder'),
) () => removeOrder(order.id, index)
" )
> "
<QTooltip>{{ t('deleteOrder') }}</QTooltip> >
</QBtn> <QTooltip>{{ t('deleteOrder') }}</QTooltip>
<QBtn </QBtn>
icon="shopping_bag" <QBtn
flat icon="shopping_bag"
rounded flat
@click.stop.prevent="loadOrder(order.id)" rounded
> @click.stop.prevent="loadOrder(order.id)"
<QTooltip>{{ t('loadOrderIntoCart') }}</QTooltip> >
</QBtn> <QTooltip>{{ t('loadOrderIntoCart') }}</QTooltip>
</template> </QBtn>
</CardList> </template>
</CardList>
</VnList>
</QPage> </QPage>
</template> </template>