feat: refs #6897 add tabs and string checkbox
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details

This commit is contained in:
Pablo Natek 2024-10-26 10:02:12 +02:00
parent 54ace8c682
commit 11e570360d
8 changed files with 245 additions and 215 deletions

View File

@ -8,7 +8,6 @@ const props = defineProps({
validator: (value) => value.length <= 3, validator: (value) => value.length <= 3,
}, },
}); });
const sectionHeight = computed(() => `${100 / props.colors.length}%`);
</script> </script>
<template> <template>
<div class="color-div"> <div class="color-div">
@ -17,18 +16,16 @@ const sectionHeight = computed(() => `${100 / props.colors.length}%`);
:key="index" :key="index"
:style="{ :style="{
backgroundColor: color, backgroundColor: color,
height: sectionHeight, height: '10px',
width: '100%',
flexShrink: 0,
}" }"
/> >
&nbsp;
</div>
</div> </div>
</template> </template>
<style scoped> <style scoped>
.color-div { .color-div {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100vh;
width: 100%;
} }
</style> </style>

View File

@ -327,7 +327,6 @@ const editingRow = ref(null);
const editingField = ref(null); const editingField = ref(null);
const handleClick = (event) => { const handleClick = (event) => {
console.log('event: ', event);
const clickedElement = event.target.closest('td'); const clickedElement = event.target.closest('td');
if (!clickedElement) return; if (!clickedElement) return;
@ -341,7 +340,6 @@ const handleClick = (event) => {
}; };
const vnEditableCell = ref(null); const vnEditableCell = ref(null);
const startEditing = async (rowId, field) => { const startEditing = async (rowId, field) => {
console.log('entrando a startEditing');
const col = $props.columns.find((col) => col.name === field); const col = $props.columns.find((col) => col.name === field);
if (col?.isEditable === false) return; if (col?.isEditable === false) return;
editingRow.value = rowId; editingRow.value = rowId;
@ -359,48 +357,23 @@ const stopEditing = (rowIndex, field) => {
editingField.value = null; editingField.value = null;
}; };
const findNextEditableColumnIndex = (columns, startIndex) => {
let index = startIndex;
console.log('columns: ', columns);
console.log('index: ', index);
console.log(
'columns[index]?.isVisible === false || columns[index]?.isEditable === false: ',
columns[index]?.isVisible === false || columns[index]?.isEditable === false
);
while (columns[index]?.isVisible === false && columns[index]?.isEditable === false) {
index++;
if (index >= columns.length) {
index = 0;
}
if (index === startIndex) {
return -1;
}
}
console.log('index: ', index);
return index;
};
const handleTab = async (rowIndex, colName) => { const handleTab = async (rowIndex, colName) => {
console.log('colName: ', colName);
console.log('rowIndex: ', rowIndex);
const columns = $props.columns; const columns = $props.columns;
console.log('columns: ', columns);
if (!Array.isArray(columns) || columns.length === 0) return;
let currentColumnIndex = columns.findIndex((col) => col.name === colName); let currentColumnIndex = columns.findIndex((col) => col.name === colName);
if (currentColumnIndex === -1) return; let newColumnIndex = currentColumnIndex + 1;
while (
currentColumnIndex++; columns[newColumnIndex]?.visible === false ||
if (currentColumnIndex >= columns.length) { columns[newColumnIndex]?.isEditable === false ||
currentColumnIndex = 0; !columns[newColumnIndex]?.component
rowIndex++; ) {
newColumnIndex++;
if (newColumnIndex >= columns.length) newColumnIndex = 0;
} }
currentColumnIndex = findNextEditableColumnIndex(columns, currentColumnIndex); if (currentColumnIndex >= newColumnIndex) rowIndex++;
if (currentColumnIndex === -1) return;
await startEditing(rowIndex, columns[currentColumnIndex].name); await startEditing(rowIndex, columns[newColumnIndex].name);
}; };
const handleShiftTab = async (rowIndex, colName) => { const handleShiftTab = async (rowIndex, colName) => {
@ -438,19 +411,25 @@ const handleShiftTab = async (rowIndex, colName) => {
await startEditing(prevRowIndex, columns[prevColumnIndex]?.name); await startEditing(prevRowIndex, columns[prevColumnIndex]?.name);
console.log('finishHandleShiftTab'); console.log('finishHandleShiftTab');
}; };
const handleTabKey = async (event, rowIndex, colName) => { const handleTabKey = async (event, rowIndex, colName) => {
console.log('colName: ', colName);
console.log('rowIndex: ', rowIndex);
console.log('event: ', event);
if (event.shiftKey) await handleShiftTab(rowIndex, colName); if (event.shiftKey) await handleShiftTab(rowIndex, colName);
else await handleTab(rowIndex, colName); else await handleTab(rowIndex, colName);
}; };
function getCheckboxIcon(value) { function getCheckboxIcon(value) {
switch (value) { switch (typeof value) {
case true: case 'boolean':
return 'check'; return value ? 'check' : 'close';
case false: case 'string':
return 'close'; return value.toLowerCase() === 'partial'
? 'indeterminate_check_box'
: 'unknown_med';
case 'number':
return value > 0 ? 'check' : 'close';
case 'object':
return value === null ? 'help_outline' : 'unknown_med';
case 'undefined':
return 'help_outline';
default: default:
return 'unknown_med'; return 'unknown_med';
} }
@ -458,7 +437,7 @@ function getCheckboxIcon(value) {
function shouldDisplayReadonly(col, rowIndex) { function shouldDisplayReadonly(col, rowIndex) {
return ( return (
col?.isEditable === false || !col?.component ||
editingRow.value !== rowIndex || editingRow.value !== rowIndex ||
editingField.value !== col?.name editingField.value !== col?.name
); );
@ -549,7 +528,11 @@ function shouldDisplayReadonly(col, rowIndex) {
<template #body="{ rows }"> <template #body="{ rows }">
<QTable <QTable
v-bind="table" v-bind="table"
:class="['vnTable', table ? 'selection-cell' : '']" :class="[
'vnTable',
table ? 'selection-cell' : '',
$props.footer ? 'last-row-sticky' : '',
]"
wrap-cells wrap-cells
:columns="splittedColumns.columns" :columns="splittedColumns.columns"
:rows="rows" :rows="rows"
@ -571,12 +554,6 @@ function shouldDisplayReadonly(col, rowIndex) {
@click="handleClick" @click="handleClick"
> >
<template #top-left v-if="!$props.withoutHeader"> <template #top-left v-if="!$props.withoutHeader">
<QIcon
v-if="$props.isEditable"
name="edit"
color="primary"
size="sm"
/>
<slot name="top-left"> </slot> <slot name="top-left"> </slot>
</template> </template>
<template #top-right v-if="!$props.withoutHeader"> <template #top-right v-if="!$props.withoutHeader">
@ -667,7 +644,6 @@ function shouldDisplayReadonly(col, rowIndex) {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
vertical-align: middle;
" "
> >
<slot <slot
@ -682,15 +658,18 @@ function shouldDisplayReadonly(col, rowIndex) {
style="color: var(--vn-text-color)" style="color: var(--vn-text-color)"
size="var(--font-size)" size="var(--font-size)"
:class=" :class="
isEditable && (col?.isEditable ?? 'editable-text') isEditable &&
(col?.component ? 'editable-text' : '')
" "
/> />
<span <span
v-else v-else
:class=" :class="
isEditable && (col?.isEditable ?? 'editable-text') isEditable &&
(col?.component ? 'editable-text' : '')
" "
:style="col?.style ? col.style(row) : null" :style="col?.style ? col.style(row) : null"
style="bottom: 0"
> >
{{ {{
col?.format col?.format
@ -700,7 +679,7 @@ function shouldDisplayReadonly(col, rowIndex) {
</span> </span>
</slot> </slot>
</div> </div>
<div v-else-if="isEditable"> <div v-else>
<VnTableColumn <VnTableColumn
ref="vnEditableCell" ref="vnEditableCell"
:column="col" :column="col"
@ -1073,6 +1052,9 @@ es:
table tbody th { table tbody th {
position: relative; position: relative;
} }
}
.last-row-sticky {
tbody:nth-last-child(1) { tbody:nth-last-child(1) {
@extend .bg-header; @extend .bg-header;
position: sticky; position: sticky;

View File

@ -88,28 +88,28 @@ const columns = [
width: '35px', width: '35px',
}, },
{ {
align: 'center',
label: 'Pack', label: 'Pack',
name: 'packing', name: 'packing',
component: 'number', component: 'number',
width: '35px', width: '35px',
style: (row) => { style: (row) => {
if (row.groupingMode === 'grouping') { if (row.groupingMode === 'grouping')
return { color: 'var(--vn-label-color)' }; return { color: 'var(--vn-label-color)' };
}
}, },
}, },
{ {
align: 'center',
label: 'Group', label: 'Group',
name: 'grouping', name: 'grouping',
component: 'number', component: 'number',
width: '35px', width: '35px',
style: (row) => { style: (row) => {
if (row.groupingMode === 'packing') { if (row.groupingMode === 'packing') return { color: 'var(--vn-label-color)' };
return { color: 'var(--vn-label-color)' };
}
}, },
}, },
{ {
align: 'center',
label: t('Quantity'), label: t('Quantity'),
name: 'quantity', name: 'quantity',
component: 'number', component: 'number',
@ -120,18 +120,30 @@ const columns = [
}, },
}, },
{ {
label: t('Amount'), align: 'center',
name: 'amount', label: 'Cost.',
name: 'buyingValue',
component: 'number', component: 'number',
width: '50px', width: '50px',
}, },
{ {
align: 'center',
label: t('Amount'),
name: 'amount',
width: '50px',
style: () => {
return { color: 'var(--vn-label-color)' };
},
},
{
align: 'center',
label: t('Package'), label: t('Package'),
name: 'price2', name: 'price2',
component: 'number', component: 'number',
width: '35px', width: '35px',
}, },
{ {
align: 'center',
label: t('Box'), label: t('Box'),
name: 'price3', name: 'price3',
component: 'number', component: 'number',
@ -144,12 +156,12 @@ const columns = [
component: 'number', component: 'number',
width: '35px', width: '35px',
style: (row) => { style: (row) => {
if (row?.hasMinPrice) { if (row?.hasMinPrice)
return { backgroundColor: 'var(--q-positive)', color: 'black' }; return { backgroundColor: 'var(--q-positive)', color: 'black' };
}
}, },
}, },
{ {
align: 'center',
label: t('P.Sen'), label: t('P.Sen'),
name: 'packingOut', name: 'packingOut',
component: 'number', component: 'number',
@ -163,10 +175,13 @@ const columns = [
width: '55px', width: '55px',
}, },
{ {
align: 'center',
label: 'Prod.', label: 'Prod.',
name: 'subName', name: 'subName',
component: 'input',
width: '45px', width: '45px',
style: () => {
return { color: 'var(--vn-label-color)' };
},
}, },
{ {
align: 'center', align: 'center',
@ -174,13 +189,11 @@ const columns = [
name: 'tags', name: 'tags',
width: '120px', width: '120px',
columnSearch: false, columnSearch: false,
isEditable: false,
}, },
{ {
align: 'center', align: 'center',
label: 'Comp.', label: 'Comp.',
name: 'company_name', name: 'company_name',
component: 'input',
width: '35px', width: '35px',
}, },
]; ];
@ -195,6 +208,11 @@ onMounted(() => {
data-key="EntryBuys" data-key="EntryBuys"
:url="`Entries/${route.params.id}/getBuys`" :url="`Entries/${route.params.id}/getBuys`"
:disable-option="{ card: true }" :disable-option="{ card: true }"
v-model:selected="selectedRows"
:table="{
'row-key': 'id',
selection: 'multiple',
}"
:right-search="false" :right-search="false"
:row-click="false" :row-click="false"
:columns="columns" :columns="columns"
@ -230,7 +248,7 @@ onMounted(() => {
</style> </style>
<i18n> <i18n>
es: es:
Article: Artículo Article: Artículo3
Size: Med. Size: Med.
Sti.: Eti. Sti.: Eti.
Bucket: Cubo Bucket: Cubo

View File

@ -1,11 +1,12 @@
<script setup> <script setup>
import { ref, computed, watch, onMounted } from 'vue'; import { ref, computed, onMounted } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import CardDescriptor from 'components/ui/CardDescriptor.vue'; import CardDescriptor from 'components/ui/CardDescriptor.vue';
import VnLv from 'src/components/ui/VnLv.vue'; import VnLv from 'src/components/ui/VnLv.vue';
import useCardDescription from 'src/composables/useCardDescription'; import useCardDescription from 'src/composables/useCardDescription';
import TravelDescriptorProxy from 'src/pages/Travel/Card/TravelDescriptorProxy.vue';
import { useState } from 'src/composables/useState'; import { useState } from 'src/composables/useState';
import { toDate } from 'src/filters'; import { toDate } from 'src/filters';
@ -101,8 +102,6 @@ const getEntryRedirectionFilter = (entry) => {
const showEntryReport = () => { const showEntryReport = () => {
openReport(`Entries/${route.params.id}/entry-order-pdf`); openReport(`Entries/${route.params.id}/entry-order-pdf`);
}; };
watch;
</script> </script>
<template> <template>
@ -122,16 +121,14 @@ watch;
</QItem> </QItem>
</template> </template>
<template #body="{ entity }"> <template #body="{ entity }">
<VnLv <VnLv :label="t('invoiceInFk')" :value="entity?.invoiceInFk" />
:label="t('entry.descriptor.agency')" <VnLv :label="t('supplierFk')" :value="entity?.supplier?.name" />
:value="entity.travel?.agency?.name" <VnLv :label="t('travelFk')" :value="entity.travel?.id">
/> <template #value>
<VnLv :label="t('shipped')" :value="toDate(entity.travel?.shipped)" /> <span class="link">{{ entity.travel?.agency?.name }}</span>
<VnLv :label="t('landed')" :value="toDate(entity.travel?.landed)" /> <TravelDescriptorProxy :id="entity.travel?.id" />
<VnLv </template>
:label="t('entry.descriptor.warehouseOut')" </VnLv>
:value="entity.travel?.warehouseOut?.name"
/>
</template> </template>
<template #icons> <template #icons>
<QCardActions class="q-gutter-x-md"> <QCardActions class="q-gutter-x-md">
@ -204,4 +201,6 @@ es:
Go to module index: Ir al índice del modulo Go to module index: Ir al índice del modulo
Inventory entry: Es inventario Inventory entry: Es inventario
Virtual entry: Es una redada Virtual entry: Es una redada
shipped: Enviado
landed: Recibido
</i18n> </i18n>

View File

@ -184,26 +184,30 @@ const fetchEntryBuys = async () => {
{{ t('globals.summary.basicData') }} {{ t('globals.summary.basicData') }}
<QIcon name="open_in_new" /> <QIcon name="open_in_new" />
</router-link> </router-link>
<VnLv :label="t('entry.summary.commission')" :value="entry.commission" /> <div class="card-group">
<div class="card-content">
<VnLv
:label="t('entry.summary.commission')"
:value="entry.commission"
/>
<VnLv <VnLv
:label="t('entry.summary.currency')" :label="t('entry.summary.currency')"
:value="entry.currency?.name" :value="entry.currency?.name"
/> />
<VnLv :label="t('entry.summary.company')" :value="entry.company.code" /> <VnLv
<VnLv :label="t('entry.summary.reference')" :value="entry.reference" /> :label="t('entry.summary.company')"
:value="entry.company.code"
/>
<VnLv
:label="t('entry.summary.reference')"
:value="entry.reference"
/>
<VnLv <VnLv
:label="t('entry.summary.invoiceNumber')" :label="t('entry.summary.invoiceNumber')"
:value="entry.invoiceNumber" :value="entry.invoiceNumber"
/> />
</QCard> </div>
<QCard class="vn-one"> <div class="card-content">
<router-link
:to="{ name: 'EntryBasicData', params: { id: entityId } }"
class="header header-link"
>
{{ t('globals.summary.basicData') }}
<QIcon name="open_in_new" />
</router-link>
<VnLv :label="t('entry.summary.travelReference')"> <VnLv :label="t('entry.summary.travelReference')">
<template #value> <template #value>
<span class="link"> <span class="link">
@ -216,26 +220,31 @@ const fetchEntryBuys = async () => {
:label="t('entry.summary.travelAgency')" :label="t('entry.summary.travelAgency')"
:value="entry.travel.agency?.name" :value="entry.travel.agency?.name"
/> />
<VnLv :label="t('shipped')" :value="toDate(entry.travel.shipped)" /> <VnLv
:label="t('shipped')"
:value="toDate(entry.travel.shipped)"
/>
<VnLv <VnLv
:label="t('entry.summary.travelWarehouseOut')" :label="t('entry.summary.travelWarehouseOut')"
:value="entry.travel.warehouseOut?.name" :value="entry.travel.warehouseOut?.name"
/> />
<QCheckbox
:label="t('entry.summary.travelDelivered')"
v-model="entry.travel.isDelivered"
:disable="true"
/>
<VnLv :label="t('landed')" :value="toDate(entry.travel.landed)" /> <VnLv :label="t('landed')" :value="toDate(entry.travel.landed)" />
<VnLv <VnLv
:label="t('entry.summary.travelWarehouseIn')" :label="t('entry.summary.travelWarehouseIn')"
:value="entry.travel.warehouseIn?.name" :value="entry.travel.warehouseIn?.name"
/> />
<QCheckbox
:label="t('entry.summary.travelDelivered')"
v-model="entry.travel.isDelivered"
:disable="true"
/>
<QCheckbox <QCheckbox
:label="t('entry.summary.travelReceived')" :label="t('entry.summary.travelReceived')"
v-model="entry.travel.isReceived" v-model="entry.travel.isReceived"
:disable="true" :disable="true"
/> />
</div>
</div>
</QCard> </QCard>
<QCard class="vn-one"> <QCard class="vn-one">
<router-link <router-link
@ -279,6 +288,24 @@ const fetchEntryBuys = async () => {
.separation-row { .separation-row {
background-color: var(--vn-section-color) !important; background-color: var(--vn-section-color) !important;
} }
.card-group {
display: flex;
flex-direction: column;
}
.card-content {
margin-bottom: 16px; /* Para dar espacio entre las secciones */
}
@media (min-width: 1010px) {
.card-group {
flex-direction: row; /* Coloca los contenidos en fila cuando el ancho es mayor a 600px */
}
.card-content {
flex: 1; /* Haz que las secciones ocupen el mismo espacio */
margin-right: 16px; /* Espaciado entre las dos primeras tarjetas */
}
}
</style> </style>
<i18n> <i18n>

View File

@ -69,8 +69,9 @@ const columns = computed(() => [
format: (row) => row?.name, format: (row) => row?.name,
}, },
{ {
align: 'left', align: 'center',
name: 'isConfirmed', name: 'isConfirmed',
component: 'checkbox',
label: t('module.isConfirmed'), label: t('module.isConfirmed'),
}, },
{ {
@ -93,7 +94,9 @@ const columns = computed(() => [
columnField: { columnField: {
component: null, component: null,
}, },
style: 'color="positive"', style: () => {
return { color: 'positive' };
},
}, },
{ {
align: 'left', align: 'left',

View File

@ -3,7 +3,7 @@ import { computed, ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useSummaryDialog } from 'src/composables/useSummaryDialog'; import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
import { toDate } from 'src/filters'; import { toDate, toHour } from 'src/filters';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { usePrintService } from 'src/composables/usePrintService'; import { usePrintService } from 'src/composables/usePrintService';
@ -38,7 +38,7 @@ const routeFilter = {
}; };
const columns = computed(() => [ const columns = computed(() => [
{ {
align: 'left', align: 'center',
name: 'id', name: 'id',
label: 'Id', label: 'Id',
chip: { chip: {
@ -48,7 +48,7 @@ const columns = computed(() => [
columnFilter: false, columnFilter: false,
}, },
{ {
align: 'left', align: 'center',
name: 'workerFk', name: 'workerFk',
label: t('route.Worker'), label: t('route.Worker'),
create: true, create: true,
@ -71,7 +71,7 @@ const columns = computed(() => [
format: (row, dashIfEmpty) => dashIfEmpty(row.travelRef), format: (row, dashIfEmpty) => dashIfEmpty(row.travelRef),
}, },
{ {
align: 'left', align: 'center',
name: 'agencyModeFk', name: 'agencyModeFk',
label: t('route.Agency'), label: t('route.Agency'),
isTitle: true, isTitle: true,
@ -89,7 +89,7 @@ const columns = computed(() => [
columnClass: 'expand', columnClass: 'expand',
}, },
{ {
align: 'left', align: 'center',
name: 'vehicleFk', name: 'vehicleFk',
label: t('route.Vehicle'), label: t('route.Vehicle'),
cardVisible: true, cardVisible: true,
@ -110,27 +110,27 @@ const columns = computed(() => [
}, },
}, },
{ {
align: 'left', align: 'center',
name: 'created', name: 'created',
label: t('route.Date'), label: t('route.Date'),
columnFilter: false, columnFilter: false,
cardVisible: true, cardVisible: true,
create: true, create: true,
component: 'date', component: 'date',
format: ({ date }) => toDate(date), format: ({ created }) => toDate(created),
}, },
{ {
align: 'left', align: 'center',
name: 'from', name: 'from',
label: t('route.From'), label: t('route.From'),
visible: false, visible: false,
cardVisible: true, cardVisible: true,
create: true, create: true,
component: 'date', component: 'date',
format: ({ date }) => toDate(date), format: ({ from }) => toDate(from),
}, },
{ {
align: 'left', align: 'center',
name: 'to', name: 'to',
label: t('route.To'), label: t('route.To'),
visible: false, visible: false,
@ -147,18 +147,20 @@ const columns = computed(() => [
columnClass: 'shrink', columnClass: 'shrink',
}, },
{ {
align: 'left', align: 'center',
name: 'started', name: 'started',
label: t('route.hourStarted'), label: t('route.hourStarted'),
component: 'time', component: 'time',
columnFilter: false, columnFilter: false,
format: ({ hourStarted }) => toHour(hourStarted),
}, },
{ {
align: 'left', align: 'center',
name: 'finished', name: 'finished',
label: t('route.hourFinished'), label: t('route.hourFinished'),
component: 'time', component: 'time',
columnFilter: false, columnFilter: false,
format: ({ hourFinished }) => toHour(hourFinished),
}, },
{ {
align: 'center', align: 'center',
@ -177,7 +179,7 @@ const columns = computed(() => [
visible: false, visible: false,
}, },
{ {
align: 'left', align: 'center',
name: 'description', name: 'description',
label: t('route.Description'), label: t('route.Description'),
isTitle: true, isTitle: true,
@ -186,7 +188,7 @@ const columns = computed(() => [
field: 'description', field: 'description',
}, },
{ {
align: 'left', align: 'center',
name: 'isOk', name: 'isOk',
label: t('route.Served'), label: t('route.Served'),
component: 'checkbox', component: 'checkbox',
@ -301,6 +303,7 @@ const openTicketsDialog = (id) => {
<RouteFilter data-key="RouteList" /> <RouteFilter data-key="RouteList" />
</template> </template>
</RightMenu> </RightMenu>
<QPage class="q-px-md">
<VnTable <VnTable
class="route-list" class="route-list"
ref="tableRef" ref="tableRef"
@ -357,4 +360,5 @@ const openTicketsDialog = (id) => {
</QBtn> </QBtn>
</template> </template>
</VnTable> </VnTable>
</QPage>
</template> </template>

View File

@ -252,7 +252,7 @@ const getLink = (param) => `#/travel/${entityId.value}/${param}`;
data-key="TravelSummary" data-key="TravelSummary"
> >
<template #header> <template #header>
<span>{{ travel.ref }} - {{ travel.id }}</span> <span>{{ travel.id }} - {{ travel.ref }}</span>
</template> </template>
<template #body> <template #body>