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

540 lines
18 KiB
Vue

<script setup>
import { computed, nextTick, onMounted, onUnmounted, ref, toRefs } from 'vue';
import { useI18n } from 'vue-i18n';
import { QBtn, QCheckbox, useQuasar } from 'quasar';
import axios from 'axios';
import HandleSplited from 'pages/Ticket/Negative/components/HandleSplited.vue';
import ChangeQuantityDialog from 'pages/Ticket/Negative/components/ChangeQuantityDialog.vue';
import ChangeStateDialog from 'pages/Ticket/Negative/components/ChangeStateDialog.vue';
import ItemProposal from 'pages/Item/components/ItemProposal.vue';
import { useVnConfirm } from 'composables/useVnConfirm';
import VnPaginate from 'src/components/ui/VnPaginate.vue';
import FetchData from 'src/components/FetchData.vue';
import VnSelect from 'components/common/VnSelect.vue';
import VnInput from 'src/components/common/VnInput.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import { toDate, toHour } from 'src/filters';
import useNotify from 'src/composables/useNotify.js';
import { useStateStore } from 'stores/useStateStore';
import { useDialogPluginComponent } from 'quasar';
import { useSession } from 'src/composables/useSession';
import ZoneDescriptorProxy from 'pages/Zone/Card/ZoneDescriptorProxy.vue';
const { openConfirmationModal } = useVnConfirm();
const { t } = useI18n();
const URL_KEY = 'Tickets/ItemLack';
const editableStates = ref([]);
const { notify } = useNotify();
const stateStore = useStateStore();
const proposalDialogRef = ref();
const splitDialogRef = ref();
const changeStateDialogRef = ref();
const changeQuantityDialogRef = ref();
const showSplitDialog = ref(false);
const showProposalDialog = ref(false);
const showChangeQuantityDialog = ref(false);
const showChangeStateDialog = ref(false);
const componentIsRendered = ref(false);
const showFree = ref(true);
const resultSplit = ref([]);
const selectedRows = ref([]);
const session = useSession();
const token = session.getTokenMultimedia();
const originalRowDataCopy = ref(null);
const $props = defineProps({
item: {
type: Number,
required: true,
},
filter: {
type: Object,
required: false,
default: () => {
true;
},
},
});
onMounted(() => {
stateStore.rightDrawer = false;
nextTick(() => {
componentIsRendered.value = true;
});
});
onUnmounted(() => (stateStore.rightDrawer = true));
const copyOriginalRowsData = (rows) => {
originalRowDataCopy.value = JSON.parse(JSON.stringify(rows));
};
const getInputEvents = (colField, props) => ({
'update:modelValue': () => saveChange(colField, props),
'keyup.enter': () => saveChange(colField, props),
});
const saveChange = async (field, { rowIndex, row }) => {
try {
switch (field) {
// case 'split':
// showSplitDialog.value =true
// // await split({ simple: true }, [row]);
// break;
case 'code':
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;
default:
console.error(field, { rowIndex, row });
break;
}
notify('globals.dataSaved', 'positive');
} catch (err) {
console.error('Error saving changes', err);
}
};
const entityId = computed(() => $props.item.itemFk);
function isComponentVn(col) {
return tableColumnComponents?.value[col.name]?.component === 'span' ?? false;
}
// const onDetailDialogHide = (evt) => {
// if (evt?.type === 'refresh') ticketDetailRef.value.reload();
// };
const tableColumnComponents = computed(() => ({
status: {
component: 'span',
props: {},
event: () => ({}),
sortable: false,
},
ticketFk: {
component: QBtn,
props: { color: 'blue', sortable: true, flat: true },
event: () => ({}),
sortable: true,
},
shipped: {
component: 'span',
props: {},
event: () => ({}),
},
theoreticalhour: {
component: 'span',
props: {},
event: () => ({}),
},
state: {
style: 'width: 160px',
component: VnSelect,
type: 'select',
filterValue: null,
props: {
'option-value': 'code',
'option-label': 'name',
'emit-value': true,
'map-options': true,
'use-input': true,
'hide-selected': true,
dense: true,
options: editableStates.value,
},
event: getInputEvents,
},
zoneName: {
component: QBtn,
props: { color: 'blue', sortable: true, flat: true },
event: () => ({}),
},
nickname: {
component: 'span',
props: {},
event: () => ({}),
},
quantity: {
component: VnInput,
props: {
type: 'number',
min: 0,
class: 'input-number',
},
event: getInputEvents,
style: 'width: 100px',
},
alertLevelCode: {
component: 'span',
props: {},
event: () => ({}),
},
}));
const columns = computed(() => [
{
name: 'status',
align: 'center',
sortable: false,
},
{
name: 'ticketFk',
label: t('negative.detail.ticketFk'),
field: 'ticketFk',
align: 'left',
sortable: true,
},
{
name: 'shipped',
label: t('negative.detail.shipped'),
field: 'shipped',
align: 'left',
format: (val) => toDate(val),
sortable: true,
},
{
name: 'theoreticalhour',
label: t('negative.detail.theoreticalhour'),
field: 'theoreticalhour',
align: 'left',
sortable: true,
format: (val) => toHour(val),
},
{
name: 'state',
label: t('negative.detail.state'),
field: 'code',
align: 'left',
sortable: true,
},
{
name: 'zoneName',
label: t('negative.detail.zoneName'),
field: 'zoneName',
align: 'left',
sortable: true,
},
{
name: 'nickname',
label: t('negative.detail.nickname'),
field: 'nickname',
align: 'left',
sortable: true,
},
{
name: 'quantity',
label: t('negative.detail.quantity'),
field: 'quantity',
align: 'left',
sortable: true,
style: 'width: 100px',
},
]);
const { dialogRef, onDialogHide } = useDialogPluginComponent();
const { filter } = toRefs($props);
const emit = defineEmits([...useDialogPluginComponent.emits, 'selection', 'close']);
function rowsHasSelected(selection) {
emit(
'selection',
selection
//.map(({ ticketFk }) => ticketFk)
);
}
const itemLackForm = ref();
// const split = async ({ simple }, data = []) => {
// openConfirmationModal(
// t('negative.detail.split.confirmSplitSelected'),
// t('negative.detail.split.splitQuestion'),
// null,
// () => {
// showSplitDialog.value = true;
// resultSplit.value = [{}];
// // const body = simple ? data : selectedRows.value;
// // axios.post(`Tickets/split`, body).then((data) => {
// // resultSplit.value = data;
// // });
// }
// );
// };
// const split = async ({ simple }, data = []) => {
// openConfirmationModal(
// t('negative.modalSplit.title'),
// t('splitQuestion'),
// () => {
// const body = simple ? data : selectedRows.value;
// axios.post(`Tickets/split`, body).then((data) => {
// resultSplit.value = data;
// });
// }
// );
// };
const reload = async () => {
itemLackForm.value.fetch();
};
defineExpose({ reload });
// Función de comparación
function freeFirst({ alertLevel: a }, { alertLevel: b }) {
const DEFAULT = 0;
// Si el estado de 'a' es 'free' y el de 'b' no lo es, 'a' viene primero
if (a === DEFAULT && b !== DEFAULT) {
return -1;
}
// Si el estado de 'b' es 'free' y el de 'a' no lo es, 'b' viene primero
if (b === DEFAULT && a !== DEFAULT) {
return 1;
}
// En cualquier otro caso, no se cambia el orden
return 0;
}
const handleRows = (rows) => {
if (showFree.value) return rows.filter(({ alertLevel }) => alertLevel === 0);
return rows.sort(freeFirst);
};
const quasar = useQuasar();
const split = async () => {
const body = selectedRows.value;
// const {data} = await axios.post(`Tickets/split`, body);
// resultSplit.value = data;
resultSplit.value = [
{ ticket: 32, newTicket: 1000005, status: 'split' },
{ ticket: 32, newTicket: 1000006, status: 'noSplit' },
{ ticket: 32, newTicket: 1000007, status: 'error' },
];
quasar.dialog({
component: HandleSplited,
componentProps: {
tickets: resultSplit.value,
},
});
};
</script>
<template>
<FetchData
url="States/editableStates"
@on-fetch="(data) => (editableStates = data)"
auto-load
/>
<Teleport to="#st-actions" v-if="stateStore?.isSubToolbarShown()">
<QBtnGroup push style="column-gap: 1px"
><QBtn
:label="t('globals.cancel')"
@click="emit('close')"
color="primary"
flat
icon="close"
>
<QTooltip>{{ t('globals.cancel') }}</QTooltip>
</QBtn></QBtnGroup
>
</Teleport>
<Teleport to="#st-data" v-if="stateStore?.isSubToolbarShown()">
<QSpace />
<QBtnGroup push style="column-gap: 1px">
<QBtn
color="primary"
:label="t('Change state')"
:disable="selectedRows.length < 2"
@click="showChangeStateDialog = true"
>
<QTooltip bottom anchor="bottom right">
{{ t('Change state') }}
</QTooltip>
</QBtn>
<QBtn
color="primary"
:label="t('Change quantity')"
@click="showChangeQuantityDialog = true"
:disable="selectedRows.length < 2"
>
<QTooltip bottom anchor="bottom right">
{{ t('Change quantity') }}
</QTooltip>
</QBtn>
<QBtn
color="primary"
@click="
openConfirmationModal(
t('negative.detail.modal.split.title'),
t('negative.detail.modal.split.subTitle'),
split,
() => (showSplitDialog = true)
)
"
:disable="selectedRows.length < 1"
icon="call_split"
>
<QTooltip bottom anchor="bottom right">
{{ t('globals.split') }}
</QTooltip>
</QBtn>
<QBtn
icon="vn:splitline"
color="primary"
:disable="selectedRows.length < 1"
@click="showProposalDialog = true"
>
<QTooltip bottom anchor="bottom right">
{{ t('Item proposal') }}
</QTooltip>
</QBtn>
</QBtnGroup>
<QCheckbox v-model="showFree" :label="t('negative.detail.showFree')" />
</Teleport>
<VnPaginate
:data-key="URL_KEY"
:url="`${URL_KEY}/${entityId}/detail`"
ref="itemLackForm"
@on-fetch="copyOriginalRowsData($event)"
auto-load
>
<!-- :rows="rows" -->
<template #body="{ rows }">
<QImg
:src="`/api/Images/catalog/50x50/${item.itemFk}/download?access_token=${token}`"
spinner-color="primary"
:ratio="1"
height="50px"
width="50px"
class="image remove-bg"
:alt="'asdads'"
/>
<span class="text-h6">{{ item.longName }}</span>
<QTable
ref="tableRef"
:columns="columns"
:rows="handleRows(rows)"
row-key="ticketFk"
selection="multiple"
v-model:selected="selectedRows"
@update:selected="rowsHasSelected"
:grid="$q.screen.lt.md"
hide-bottom
>
<template #body="props">
<QTr>
<QTd>
<!-- <QIcon
v-if="resultSplit.length > 0"
:name="getIcon(props.key, 'name')"
:color="getIcon(props.key, 'color')"
class="fill-icon q-mr-sm"
size="xs"
style="font-weight: bold"
/> -->
<QCheckbox v-model="props.selected" />
</QTd>
<QTd v-for="col in props.cols" :key="col.name">
<template v-if="tableColumnComponents[col.name]?.component">
<component
:is="tableColumnComponents[col.name].component"
v-bind="tableColumnComponents[col.name].props"
v-model="props.row[col.field]"
v-on="
tableColumnComponents[col.name].event(
col.field,
props
)
"
:style="tableColumnComponents[col.name].style"
>
<template v-if="isComponentVn(col)">{{
col.value
}}</template>
<template v-if="col.name === 'status'">
<QIcon
v-if="props.row.isRookie"
name="vn:person"
size="xs"
color="primary"
class="cursor-pointer"
>
<QTooltip>{{
t('negative.detail.isRookie')
}}</QTooltip>
</QIcon>
<QIcon
v-if="props.row.peticionCompra"
name="vn:buyrequest"
size="xs"
color="primary"
class="cursor-pointer"
>
<QTooltip>{{
t('negative.detail.peticionCompra')
}}</QTooltip>
</QIcon>
<QIcon
v-if="props.row.turno"
name="vn:calendar"
size="xs"
color="primary"
class="cursor-pointer"
>
<QTooltip>{{
t('negative.detail.turno')
}}</QTooltip>
</QIcon>
</template>
<template v-if="col.name === 'ticketFk'"
>{{ col.value }}
<ItemDescriptorProxy :id="$props.entityId"
/></template>
<template v-if="col.name === 'zoneName'">
{{ col.value }}
<ZoneDescriptorProxy :id="props.row.zoneFk" />
</template>
</component>
</template>
</QTd>
</QTr>
</template>
</QTable>
</template>
</VnPaginate>
<ChangeStateDialog
ref="changeStateDialogRef"
@hide="onDetailDialogHide"
v-model="showChangeStateDialog"
:selected-rows="selectedRows"
></ChangeStateDialog>
<ChangeQuantityDialog
ref="changeQuantityDialogRef"
@hide="onDetailDialogHide"
v-model="showChangeQuantityDialog"
:selected-rows="selectedRows"
>
</ChangeQuantityDialog>
<!--<HandleSplited
ref="splitDialogRef"
@hide="onDialogHide"
v-model="showSplitDialog"
:tickets="resultSplit"
></HandleSplited>-->
<ItemProposal
ref="proposalDialogRef"
@hide="onDialogHide"
v-model="showProposalDialog"
:item="item"
:tickets="selectedRows"
></ItemProposal>
</template>