Import lines & responsive layout
gitea/salix-front/pipeline/head This commit looks good Details

This commit is contained in:
Joan Sanchez 2023-03-27 14:56:12 +02:00
parent fd4b2bf926
commit e1cfe14121
3 changed files with 181 additions and 79 deletions

View File

@ -66,7 +66,7 @@ async function confirm() {
<q-btn icon="close" :disable="isLoading" flat round dense v-close-popup />
</q-card-section>
<q-card-section class="row items-center">
{{ message }}
<span v-html="message"></span>
</q-card-section>
<q-card-actions align="right">
<q-btn

View File

@ -107,10 +107,6 @@ const columns = computed(() => [
format: (value) => toCurrency(value),
sortable: true,
},
{
name: 'actions',
label: t('Actions'),
},
]);
const selected = ref([]);
@ -145,22 +141,40 @@ function onUpdateDiscount(response) {
});
}
async function confirmRemove(id, index) {
async function confirmRemove() {
const rows = selected.value;
const count = rows.length;
if (count === 0) {
return quasar.notify({
message: 'You must select at least one row',
type: 'warning',
});
}
quasar
.dialog({
component: VnConfirm,
componentProps: {
title: t('Delete claimed sale'),
data: { id },
title: t('Delete claimed sales'),
message: t('You are about to remove {count} rows', count, { count }),
data: { rows },
promise: remove,
},
})
.onOk(() => store.data.splice(index, 1));
.onOk(() => {
for (const row of rows) {
const orgData = store.data;
const index = orgData.findIndex((item) => item.id === row.id);
store.data.splice(index, 1);
}
});
}
async function remove({ id }) {
if (!id) return;
await axios.delete(`ClaimBeginnings/${id}`);
async function remove({ rows }) {
if (!rows.length) return;
const body = { deletes: rows.map((row) => row.id) };
await axios.post(`ClaimBeginnings/crud`, body);
quasar.notify({
type: 'positive',
message: t('globals.rowRemoved'),
@ -172,23 +186,29 @@ function showImportDialog() {
.dialog({
component: ClaimLinesImport,
})
.onOk(() => {});
.onOk(() => arrayData.refresh());
}
</script>
<template>
<q-page-sticky position="top" :offset="[0, 0]" expand>
<q-toolbar class="bg-dark text-white">
<q-toolbar-title class="row q-gutter-md">
<q-toolbar-title> Lines </q-toolbar-title>
<q-space />
<div class="row q-gutter-md">
<div>
{{ t('Amount') }}
<q-chip>{{ toCurrency(amount) }}</q-chip>
<q-chip :dense="$q.screen.lt.sm">
{{ toCurrency(amount) }}
</q-chip>
</div>
<q-separator dark vertical />
<div>
{{ t('Amount Claimed') }}
<q-chip color="positive">{{ toCurrency(amountClaimed) }}</q-chip>
<q-chip color="positive" :dense="$q.screen.lt.sm">
{{ toCurrency(amountClaimed) }}
</q-chip>
</div>
</q-toolbar-title>
</div>
</q-toolbar>
</q-page-sticky>
@ -217,6 +237,7 @@ function showImportDialog() {
selection="multiple"
v-model:selected="selected"
hide-pagination
:grid="$q.screen.lt.md"
>
<template #body-cell-claimed="{ row, value }">
<q-td auto-width align="right" class="dimmed">
@ -273,20 +294,6 @@ function showImportDialog() {
/>
</q-td>
</template>
<template #body-cell-actions="{ row, rowIndex }">
<q-td auto-width class="text-center">
<q-btn
icon="vn:deleteline"
color="primary"
flat
round
dense
@click="confirmRemove(row.id, rowIndex)"
>
<q-tooltip>Delete claimed sale</q-tooltip>
</q-btn>
</q-td>
</template>
</q-table>
</template>
</VnPaginate>
@ -294,26 +301,46 @@ function showImportDialog() {
</div>
<Teleport
v-if="stateStore.isHeaderMounted() && !quasar.platform.is.mobile"
v-if="stateStore.isHeaderMounted() && $q.screen.gt.sm"
to="#actions-prepend"
>
<div class="row q-gutter-x-sm">
<q-btn @click="showImportDialog" icon="add" color="primary" dense rounded>
<q-btn
v-if="selected.length > 0"
@click="confirmRemove"
icon="delete"
color="primary"
flat
dense
rounded
>
<q-tooltip bottom> {{ t('globals.remove') }} </q-tooltip>
</q-btn>
<q-btn
@click="showImportDialog"
icon="add"
color="primary"
flat
dense
rounded
>
<q-tooltip bottom> {{ t('globals.add') }} </q-tooltip>
</q-btn>
<q-separator vertical />
</div>
</Teleport>
<q-page-sticky
v-if="quasar.platform.is.mobile"
position="bottom"
:offset="[0, 0]"
expand
>
<!-- v-if="quasar.platform.is.mobile" -->
<q-page-sticky v-if="$q.screen.lt.sm" position="bottom" :offset="[0, 0]" expand>
<q-toolbar class="bg-primary text-white q-pa-none">
<q-tabs class="full-width" align="justify" inline-label narrow-indicator>
<q-tab @click="addRow()" icon="add_circle" :label="t('globals.add')" />
<q-tab @click="showImportDialog" icon="add" :label="t('globals.add')" />
<q-separator vertical inset />
<q-tab
@click="confirmRemove"
icon="delete"
:label="t('globals.remove')"
:disable="selected.length === 0"
/>
</q-tabs>
</q-toolbar>
</q-page-sticky>
@ -322,11 +349,16 @@ function showImportDialog() {
<style lang="scss" scoped>
.list {
padding-top: 50px;
max-width: 900px;
width: 100%;
}
</style>
<i18n>
en:
You are about to remove {count} rows: '
You are about to remove <strong>{count}</strong> row |
You are about to remove <strong>{count}</strong> rows'
es:
Delivered: Entregado
Quantity: Cantidad
@ -337,7 +369,11 @@ es:
Actions: Acciones
Amount: Total
Amount Claimed: Cantidad reclamada
Delete claimed sale: Eliminar venta reclamada
Delete claimed sales: Eliminar ventas reclamadas
Discount updated: Descuento actualizado
Claimed quantity: Cantidad reclamada
row: 'línea | líneas'
You are about to remove {count} rows: '
Vas a eliminar <strong>{count}</strong> línea |
Vas a eliminar <strong>{count}</strong> líneas'
</i18n>

View File

@ -1,80 +1,139 @@
<script setup>
import { ref, computed } from 'vue';
import { useDialogPluginComponent } from 'quasar';
import { useQuasar, useDialogPluginComponent } from 'quasar';
import { useI18n } from 'vue-i18n';
import VnPaginate from 'components/ui/VnPaginate.vue';
import { toDate } from 'filters';
import { useRoute } from 'vue-router';
import FetchData from 'components/FetchData.vue';
import { toDate, toCurrency, toPercentage } from 'filters';
import axios from 'axios';
defineEmits([...useDialogPluginComponent.emits]);
const { dialogRef, onDialogOK } = useDialogPluginComponent();
const { dialogRef, onDialogOK, onDialogCancel } = useDialogPluginComponent();
const route = useRoute();
const quasar = useQuasar();
const { t } = useI18n();
const columns = computed(() => [
{
name: 'delivered',
label: 'Delivered',
label: t('Delivered'),
field: (row) => row.landed,
format: (value) => toDate(value),
sortable: true,
},
{
name: 'quantity',
label: 'Quantity',
label: t('Quantity'),
field: (row) => row.quantity,
sortable: true,
},
{
name: 'description',
label: 'Description',
label: t('Description'),
field: (row) => row.concept,
},
{
name: 'price',
label: 'Price',
label: t('Price'),
field: (row) => row.price,
format: (value) => toCurrency(value),
sortable: true,
},
{
name: 'discount',
label: 'Discount',
label: t('Discount'),
field: (row) => row.discount,
format: (value) => toPercentage(value),
sortable: true,
},
]);
const selected = ref([]);
const scrollable = ref();
const claimableSales = ref([]);
const isLoading = ref(false);
let canceller;
async function importLines() {
const sales = selected.value;
if (!sales.length) {
return quasar.notify({
message: 'You must select at least one',
type: 'warning',
});
}
const body = sales.map((row) => ({
claimFk: route.params.id,
saleFk: row.saleFk,
quantity: row.quantity,
}));
canceller = new AbortController();
isLoading.value = true;
const { data } = await axios.post('ClaimBeginnings', body, {
signal: canceller.signal,
});
quasar.notify({
message: 'Lines added to claim',
type: 'positive',
});
onDialogOK(data);
canceller = null;
isLoading.value = false;
}
function cancel() {
if (canceller) {
canceller.abort();
canceller = null;
}
onDialogCancel();
}
</script>
<template>
<fetch-data
url="Sales/getClaimableFromTicket?ticketFk=16"
@on-fetch="(data) => (claimableSales = data)"
auto-load
/>
<q-dialog ref="dialogRef" persistent>
<q-card>
<q-card-section class="row items-center">
<span class="text-h6 text-grey">{{ t('Available Sales') }}</span>
<span class="text-h6 text-grey">{{ t('Available sales lines') }}</span>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-table
class="my-sticky-header-table"
:columns="columns"
:rows="claimableSales"
:pagination="{ rowsPerPage: 10 }"
row-key="saleFk"
selection="multiple"
v-model:selected="selected"
square
flat
></q-table>
<q-separator />
<VnPaginate data-key="ClaimableSales" url="Sales" :offset="50" auto-load>
<template #body="{ rows }">
<q-table
ref="scrollable"
class="my-sticky-header-table"
:columns="columns"
:rows="rows"
:pagination="{ rowsPerPage: 0 }"
row-key="saleFk"
selection="multiple"
v-model:selected="selected"
hide-pagination
square
flat
></q-table>
</template>
</VnPaginate>
<q-card-actions align="right">
<q-btn :label="t('globals.cancel')" color="primary" flat v-close-popup />
<q-btn
:label="t('globals.cancel')"
color="primary"
flat
@click="cancel"
/>
<q-btn
:label="t('globals.confirm')"
color="primary"
:loading="isLoading"
@click="confirm"
@click="importLines"
unelevated
/>
</q-card-actions>
@ -91,17 +150,12 @@ const scrollable = ref();
<style lang="scss">
.my-sticky-header-table {
height: 400px;
.q-table__top,
.q-table__bottom,
thead tr:first-child th {
/* bg color is important for th; just specify one */
background-color: $primary;
}
thead tr th {
position: sticky;
z-index: 1;
}
thead tr:first-child th {
/* this is when the loading indicator appears */
top: 0;
@ -119,3 +173,15 @@ const scrollable = ref();
}
}
</style>
<i18n>
es:
Available sales lines: Líneas de venta disponibles
Delivered: Entrega
Quantity: Cantidad
Description: Descripción
Price: Precio
Discount: Descuento
Lines added to claim: Lineas añadidas a la reclamación
You must select at least one: Debes seleccionar al menos una
</i18n>