salix-front/src/pages/Ticket/Negative/TicketLackTable.vue

357 lines
11 KiB
Vue

<script setup>
import FetchedTags from 'components/ui/FetchedTags.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import { computed, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import axios from 'axios';
import FetchData from 'src/components/FetchData.vue';
import { toDate, toHour } from 'src/filters';
import useNotify from 'src/composables/useNotify.js';
import ZoneDescriptorProxy from 'pages/Zone/Card/ZoneDescriptorProxy.vue';
import { useRoute } from 'vue-router';
import VnTable from 'src/components/VnTable/VnTable.vue';
import TicketDescriptorProxy from '../Card/TicketDescriptorProxy.vue';
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
const $props = defineProps({
filter: {
type: Object,
default: () => ({}),
},
});
watch(
() => $props.filter,
(v) => {
filterLack.value.where = v;
tableRef.value.reload(filterLack);
},
);
const filterLack = ref({
include: [
{
relation: 'workers',
scope: {
fields: ['id', 'firstName'],
},
},
],
where: { ...$props.filter },
order: 'ts.alertLevelCode ASC',
});
const selectedRows = ref([]);
const { t } = useI18n();
const { notify } = useNotify();
const entityId = computed(() => route.params.id);
const item = ref({});
const route = useRoute();
const columns = computed(() => [
{
name: 'status',
align: 'center',
sortable: false,
columnClass: 'shrink',
columnFilter: false,
},
{
name: 'ticketFk',
label: t('negative.detail.ticketFk'),
align: 'center',
sortable: true,
columnFilter: {
component: 'input',
type: 'number',
},
},
{
name: 'shipped',
label: t('negative.detail.shipped'),
field: 'shipped',
align: 'center',
format: ({ shipped }) => toDate(shipped),
sortable: true,
columnFilter: {
component: 'date',
columnClass: 'shrink',
},
},
{
name: 'minTimed',
label: t('negative.detail.theoreticalhour'),
field: 'minTimed',
align: 'center',
sortable: true,
component: 'time',
columnFilter: {},
},
{
name: 'alertLevelCode',
label: t('negative.detail.state'),
columnFilter: {
name: 'alertLevelCode',
component: 'select',
attrs: {
url: 'AlertLevels',
fields: ['name', 'code'],
optionLabel: 'code',
optionValue: 'code',
},
},
align: 'center',
sortable: true,
},
{
name: 'zoneName',
label: t('negative.detail.zoneName'),
field: 'zoneName',
align: 'center',
sortable: true,
},
{
name: 'nickname',
label: t('negative.detail.nickname'),
field: 'nickname',
align: 'center',
sortable: true,
},
{
name: 'quantity',
label: t('negative.detail.quantity'),
field: 'quantity',
sortable: true,
component: 'input',
type: 'number',
},
]);
const emit = defineEmits(['update:selection']);
const itemLack = ref(null);
const fetchItemLack = ref(null);
const tableRef = ref(null);
defineExpose({ tableRef, itemLack });
watch(selectedRows, () => emit('update:selection', selectedRows));
const getInputEvents = ({ col, ...rows }) => ({
'update:modelValue': () => saveChange(col.name, rows),
'keyup.enter': () => saveChange(col.name, rows),
});
const saveChange = async (field, { row }) => {
try {
switch (field) {
case 'alertLevelCode':
await axios.post(`Tickets/state`, {
ticketFk: row.ticketFk,
code: row[field],
});
break;
case 'quantity':
await axios.post(`Sales/${row.saleFk}/updateQuantity`, {
quantity: +row.quantity,
});
break;
}
notify('globals.dataSaved', 'positive');
fetchItemLack.value.fetch();
} catch (err) {
console.error('Error saving changes', err);
f;
}
};
function onBuysFetched(data) {
Object.assign(item.value, data[0]);
}
</script>
<template>
<FetchData
ref="fetchItemLack"
:url="`Tickets/itemLack`"
:params="{ id: entityId }"
@on-fetch="(data) => (itemLack = data[0])"
auto-load
/>
<FetchData
:url="`Items/${entityId}/getCard`"
:fields="['longName']"
@on-fetch="(data) => (item = data)"
auto-load
/>
<FetchData
:url="`Buys/latestBuysFilter`"
:fields="['longName']"
:filter="{ where: { 'i.id': entityId } }"
@on-fetch="onBuysFetched"
auto-load
/>
<VnTable
ref="tableRef"
data-key="NegativeItem"
:map-key="false"
:url="`Tickets/itemLack/${entityId}`"
:columns="columns"
auto-load
:create="false"
:create-as-dialog="false"
:use-model="true"
:filter="filterLack"
:order="['ts.alertLevelCode ASC']"
:table="{
'row-key': 'id',
selection: 'multiple',
}"
dense
:is-editable="true"
:row-click="false"
:right-search="false"
:right-search-icon="false"
v-model:selected="selectedRows"
:disable-option="{ card: true }"
>
<template #top-left>
<div style="display: flex; align-items: center" v-if="itemLack">
<!-- <VnImg :id="itemLack.itemFk" class="rounded image-wrapper"></VnImg> -->
<div class="flex column" style="align-items: center">
<QBadge
ref="badgeLackRef"
class="q-ml-xs"
text-color="white"
:color="itemLack.lack === 0 ? 'positive' : 'negative'"
:label="itemLack.lack"
/>
</div>
<div class="flex column left" style="align-items: flex-start">
<QBtn flat class="link">
{{ item?.longName ?? item.name }}
<ItemDescriptorProxy :id="entityId" />
<FetchedTags class="q-ml-md" :item="item" :columns="7" />
</QBtn>
</div>
</div>
</template>
<template #top-right>
<slot name="top-right" />
</template>
<template #column-status="{ row }">
<QTd style="min-width: 150px">
<div class="icon-container">
<QIcon
v-if="row.isBasket"
name="vn:basket"
color="primary"
class="cursor-pointer"
size="xs"
>
<QTooltip>{{ t('negative.detail.isBasket') }}</QTooltip>
</QIcon>
<QIcon
v-if="row.hasToIgnore"
name="star"
color="primary"
class="cursor-pointer fill-icon"
size="xs"
>
<QTooltip>{{ t('negative.detail.hasToIgnore') }}</QTooltip>
</QIcon>
<QIcon
v-if="row.hasObservation"
name="change_circle"
color="primary"
class="cursor-pointer"
size="xs"
>
<QTooltip>{{
t('negative.detail.hasObservation')
}}</QTooltip> </QIcon
><QIcon
v-if="row.isRookie"
name="vn:Person"
size="xs"
color="primary"
class="cursor-pointer"
>
<QTooltip>{{ t('negative.detail.isRookie') }}</QTooltip>
</QIcon>
<QIcon
v-if="row.peticionCompra"
name="vn:buyrequest"
size="xs"
color="primary"
class="cursor-pointer"
>
<QTooltip>{{ t('negative.detail.peticionCompra') }}</QTooltip>
</QIcon>
<QIcon
v-if="row.turno"
name="vn:calendar"
size="xs"
color="primary"
class="cursor-pointer"
>
<QTooltip>{{ t('negative.detail.turno') }}</QTooltip>
</QIcon>
</div></QTd
>
</template>
<template #column-nickname="{ row }">
<span class="link" @click.stop>
{{ row.nickname }}
<CustomerDescriptorProxy :id="row.customerId" />
</span>
</template>
<template #column-ticketFk="{ row }">
<span class="q-pa-sm link">
{{ row.id }}
<TicketDescriptorProxy :id="row.id" />
</span>
</template>
<template #column-alertLevelCode="props">
<VnSelect
url="States/editableStates"
auto-load
hide-selected
option-value="id"
option-label="name"
v-model="props.row.alertLevelCode"
v-on="getInputEvents(props)"
/>
</template>
<template #column-zoneName="{ row }">
<span class="link">{{ row.zoneName }}</span>
<ZoneDescriptorProxy :id="row.zoneFk" />
</template>
<template #column-quantity="props">
<VnInputNumber
v-model.number="props.row.quantity"
v-on="getInputEvents(props)"
></VnInputNumber>
</template>
</VnTable>
</template>
<style lang="scss" scoped>
.icon-container {
display: grid;
grid-template-columns: repeat(3, 0.2fr);
row-gap: 5px; /* Ajusta el espacio entre los iconos según sea necesario */
}
.icon-container > * {
width: 100%;
height: auto;
}
.list-enter-active,
.list-leave-active {
transition: all 1s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
background-color: $primary;
}
</style>