refs #6157 claimAction
gitea/salix-front/pipeline/head This commit looks good Details

This commit is contained in:
Carlos Satorres 2023-10-17 17:32:47 +02:00
parent a5710e66e1
commit f230fcbca2
8 changed files with 526 additions and 16 deletions

View File

@ -4,7 +4,7 @@ const emit = defineEmits(['update:modelValue', 'update:options']);
const $props = defineProps({ const $props = defineProps({
modelValue: { modelValue: {
type: [String, Number], type: [String, Number, Object],
default: null, default: null,
}, },
options: { options: {

View File

@ -2,6 +2,7 @@
import { onMounted, useSlots, ref, watch } from 'vue'; import { onMounted, useSlots, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import axios from 'axios'; import axios from 'axios';
import { useArrayData } from 'src/composables/useArrayData';
import SkeletonDescriptor from 'components/ui/SkeletonDescriptor.vue'; import SkeletonDescriptor from 'components/ui/SkeletonDescriptor.vue';
const $props = defineProps({ const $props = defineProps({
@ -26,18 +27,21 @@ const $props = defineProps({
default: 0, default: 0,
}, },
}); });
const arrayData = useArrayData('claimData');
const store = arrayData.store;
console.log('eee', store.data);
const slots = useSlots(); const slots = useSlots();
const { t } = useI18n(); const { t } = useI18n();
const entity = ref(); const entity = ref(null);
let lastUrl = ref(null);
onMounted(async () => { onMounted(async () => {
await fetch(); entity.value = await store.data;
}); });
const emit = defineEmits(['onFetch']); const emit = defineEmits(['onFetch']);
async function fetch() { async function fetch() {
lastUrl.value = $props.url;
const params = {}; const params = {};
if ($props.filter) params.filter = JSON.stringify($props.filter); if ($props.filter) params.filter = JSON.stringify($props.filter);
@ -49,6 +53,7 @@ async function fetch() {
} }
watch($props, async () => { watch($props, async () => {
if (lastUrl.value == $props.url) return;
entity.value = null; entity.value = null;
await fetch(); await fetch();
}); });

View File

@ -269,6 +269,7 @@ export default {
development: 'Development', development: 'Development',
log: 'Audit logs', log: 'Audit logs',
notes: 'Notes', notes: 'Notes',
action: 'Action',
}, },
list: { list: {
customer: 'Customer', customer: 'Customer',

View File

@ -268,6 +268,7 @@ export default {
photos: 'Fotos', photos: 'Fotos',
log: 'Registros de auditoría', log: 'Registros de auditoría',
notes: 'Notas', notes: 'Notas',
action: 'Action',
}, },
list: { list: {
customer: 'Cliente', customer: 'Cliente',

View File

@ -0,0 +1,454 @@
<script setup>
import { ref, computed, watchEffect, onMounted, onUnmounted } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import axios from 'axios';
import { useStateStore } from 'src/stores/useStateStore';
import { toDate, toPercentage, toCurrency } from 'filters/index';
import CrudModel from 'src/components/CrudModel.vue';
import FetchData from 'src/components/FetchData.vue';
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
import { useArrayData } from 'src/composables/useArrayData';
const { t } = useI18n();
const route = useRoute();
const stateStore = computed(() => useStateStore());
const claimId = route.params.id;
const dialog = ref(false);
const dialogOption = ref(null);
const resolvedStateId = ref(null);
const claimActionsForm = ref();
const rows = ref([]);
const selectedRows = ref([]);
const destinationTypes = ref([]);
const destinations = ref([]);
const totalClaimed = ref(null);
const responsibility = ref(5); // pending to get from ClaimDescriptor
const manaCharger = ref(false); // pending to get from ClaimDescriptor
const claimData = useArrayData('claimData');
// ClaimEnds/filter?filter={ claimFk: route.param.id}
// for update responsability and mana /Claims/id/updateClaimAction
// onMounted(() => (stateStore.value.rightDrawer = true));
// onUnmounted(() => (stateStore.value.rightDrawer = false));
const columns = computed(() => [
{
name: 'Id',
label: t('Id'),
field: (row) => row.itemFk,
},
{
name: 'ticket',
label: t('Ticket'),
field: (row) => row.ticketFk,
align: 'center',
},
{
name: 'destination',
label: t('Destination'),
field: (row) => getDestination(row.claimDestinationFk),
align: 'left',
},
{
name: 'Landed',
label: t('Landed'),
field: (row) => toDate(row.landed),
},
{
name: 'quantity',
label: t('Quantity'),
field: (row) => row.quantity,
},
{
name: 'concept',
label: t('Description'),
field: (row) => row.concept,
align: 'left',
},
{
name: 'price',
label: t('Price'),
field: (row) => row.price,
format: (value) => value,
align: 'center',
},
{
name: 'discount',
label: t('Discount'),
field: (row) => row.discount,
format: (value) => toPercentage(value / 100),
align: 'left',
},
{
name: 'total',
label: t('Total'),
field: (row) => row.total,
format: (value) => value,
align: 'center',
},
{
name: 'delete',
},
]);
console.log(claimData.store.data);
watchEffect(() => {
if (rows.value.length) {
destinations.value = rows.value.map((row) =>
getDestination(row.claimDestinationFk)
);
totalClaimed.value = rows.value.reduce((total, row) => total + row.total, 0);
}
});
function getDestination(destinationId) {
return destinationTypes.value.find((type) => type.id == destinationId);
}
async function updateDestination(claimDestinationFk, row) {
if (claimDestinationFk) {
await axios.post('Claims/updateClaimDestination', {
claimDestinationFk,
rows: [row],
});
}
}
async function deleteSale(sale) {
await axios.post(`ClaimEnds/deleteClamedSales`, { sales: [sale] });
claimActionsForm.value.reload();
}
async function updateDestinations(claimDestinationFk) {
if (claimDestinationFk) {
await axios.post('Claims/updateClaimDestination', {
claimDestinationFk,
rows: [...selectedRows.value],
});
claimActionsForm.value.reload();
}
}
</script>
<template>
<template v-if="stateStore.isHeaderMounted()">
<Teleport to="#actions-append">
<div class="row q-gutter-x-sm">
<QBtn
flat
@click="stateStore.toggleRightDrawer()"
round
dense
icon="menu"
>
<QTooltip bottom anchor="bottom right">
{{ t('globals.collapseMenu') }}
</QTooltip>
</QBtn>
</div>
</Teleport>
</template>
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="300" show-if-above>
<QScrollArea class="fit text-grey-8 q-mt-lg">
<div class="totalClaim q-mb-md">
{{ `${t('Total claimed')}: ${toCurrency(totalClaimed)}` }}
</div>
<QCard class="q-mb-md q-pa-sm">
<QItem class="justify-between">
<QItemLabel class="slider-container">
<p class="text-primary">
{{ t('claim.summary.actions') }}
</p>
<QSlider
class="responsability"
v-model="responsibility"
label
:label-value="t('claim.summary.responsibility')"
label-always
color="primary"
markers
:marker-labels="[
{ value: 1, label: t('claim.summary.company') },
{ value: 5, label: t('claim.summary.person') },
]"
:min="1"
:max="5"
/>
</QItemLabel>
</QItem>
</QCard>
<QItemLabel class="mana q-mb-md">
<QCheckbox v-model="manaCharger" />
<span>{{ t('mana') }}</span>
</QItemLabel>
</QScrollArea>
</QDrawer>
<FetchData
url="ClaimDestinations"
auto-load
@on-fetch="(data) => (destinationTypes = data)"
/>
<FetchData
:url="`ClaimStates/findOne`"
:where="{ code: 'resolved' }"
auto-load
@on-fetch="(data) => (resolvedStateId = data)"
/>
<Teleport to="#st-data" v-if="stateStore.isSubToolbarShown()">
<QToolbar>
<QBtn
color="primary"
text-color="white"
class="q-mx-sm"
:unelevated="true"
:disable="!selectedRows.length"
:label="t('Change destination')"
@click="dialog = !dialog"
/>
</QToolbar>
</Teleport>
<div class="claim-action">
<CrudModel
data-key="ClaimEnds"
url="ClaimEnds/filter"
save-url="ClaimEnds/crud"
ref="claimActionsForm"
v-model:selected="selectedRows"
:filter="{ where: { claimFk: claimId } }"
:default-remove="true"
:default-save="false"
:default-reset="false"
@on-fetch="(data) => (rows = data)"
auto-load
>
<template #body>
<QTable
:columns="columns"
:rows="rows"
:dense="$q.screen.lt.md"
:pagination="{ rowsPerPage: 0 }"
row-key="id"
selection="multiple"
v-model:selected="selectedRows"
hide-pagination
:grid="$q.screen.lt.md"
>
<template #body-cell-ticket="{ value }">
<QTd align="center">
<span class="link">
{{ value }}
<TicketDescriptorProxy :id="value" />
</span>
</QTd>
</template>
<template #body-cell-destination="{ rowIndex }">
<QTd>
<VnSelectFilter
v-model="destinations[rowIndex]"
:options="destinationTypes"
option-value="id"
option-label="description"
@update:model-value="
(value) => updateDestination(value, rows[rowIndex])
"
/>
</QTd>
</template>
<template #body-cell-price="{ value }">
<QTd align="center">
{{ toCurrency(value) }}
</QTd>
</template>
<template #body-cell-total="{ value }">
<QTd align="center">
{{ toCurrency(value) }}
</QTd>
</template>
<template #body-cell-delete="{ rowIndex }">
<QTd>
<QBtn
icon="delete"
color="primary"
padding="xs"
round
flat
@click="deleteSale(rows[rowIndex])"
>
<QTooltip>
{{ t('Remove line') }}
</QTooltip>
</QBtn>
</QTd>
</template>
<!-- View for grid mode -->
<template #item="props">
<div class="q-mb-md col-12 grid-style-transition">
<QCard>
<QCardSection class="row justify-between">
<QCheckbox v-model="props.selected" />
<QBtn color="primary" icon="delete" flat round />
</QCardSection>
<QSeparator inset />
<QList dense>
<QItem
v-for="column of props.cols"
:key="column.name"
>
<QItemSection>
<QItemLabel caption>
{{ column.label }}
</QItemLabel>
</QItemSection>
<QItemSection side>
<QItemLabel
v-if="column.name === 'destination'"
>
{{ column.value.description }}
</QItemLabel>
<QItemLabel v-else>
{{ column.value }}
</QItemLabel>
</QItemSection>
</QItem>
</QList>
</QCard>
</div>
</template>
</QTable>
</template>
<template #moreActions>
<QBtn
color="primary"
text-color="white"
class="q-mx-sm"
:unelevated="true"
:label="t('Regularize')"
/>
<!--disabled="(ClaimDescriptor)claimStateFk == resolvedStateId"-->
<QBtn
color="primary"
text-color="white"
class="q-mx-sm"
:unelevated="true"
:disable="!selectedRows.length"
:label="t('Change destination')"
@click="dialog = !dialog"
/>
<QBtn
color="primary"
text-color="white"
class="q-mx-sm"
:unelevated="true"
:label="t('Import claim')"
/>
<!--disabled="(ClaimDescriptor)claimStateFk == resolvedStateId"-->
</template>
</CrudModel>
<QDialog v-model="dialog">
<QCard>
<QCardSection>
<QItem class="q-pa-none">
<span class="q-dialog__title text-white">
{{ t('dialog title') }}
</span>
<QBtn icon="close" flat round dense v-close-popup />
</QItem>
</QCardSection>
<QCardSection>
<VnSelectFilter
v-model="dialogOption"
:options="destinationTypes"
option-label="description"
option-value="id"
/>
</QCardSection>
<QCardActions class="justify-end q-mr-sm">
<QBtn
flat
:label="t('globals.close')"
color="primary"
v-close-popup
/>
<QBtn
:disable="!dialogOption"
:label="t('globals.save')"
color="primary"
v-close-popup
@click="updateDestinations(dialogOption)"
/>
</QCardActions>
</QCard>
</QDialog>
</div>
</template>
<style lang="scss">
.claim-action {
.q-table {
.q-select .q-field__input {
display: none !important;
}
}
}
</style>
<style lang="scss" scoped>
.slider-container {
width: 50%;
}
@media (max-width: $breakpoint-xs) {
.slider-container {
width: 90%;
}
}
.q-table {
.q-item {
min-height: min-content;
height: 0;
}
}
.q-dialog {
.q-btn {
height: min-content;
}
}
.totalClaim {
border: 3px solid black;
color: white;
padding: 10px;
margin: 5px;
}
.responsability {
max-width: 100%;
margin-left: 40px;
}
.mana {
color: white;
float: inline-start;
}
.qdrawer {
}
</style>
<i18n>
en:
mana: Is paid with mana
dialog title: Change destination to all selected rows
es:
mana: Cargado al maná
Delivered: Descripción
Quantity: Cantidad
Claimed: Rec
Description: Description
Price: Precio
Discount: Dto.
Destination: Destino
Landed: F.entrega
Remove line: Eliminar línea
Total claimed: Total reclamado
Regularize: Regularizar
Change destination: Cambiar destino
Import claim: Importar reclamación
dialog title: Cambiar destino en todas las filas seleccionadas
Remove: Eliminar
</i18n>

View File

@ -1,17 +1,58 @@
<script setup> <script setup>
import LeftMenu from 'components/LeftMenu.vue'; import { onMounted, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { useStateStore } from 'stores/useStateStore';
import { useArrayData } from 'src/composables/useArrayData';
import { getUrl } from 'composables/getUrl'; import { getUrl } from 'composables/getUrl';
import VnSearchbar from 'src/components/ui/VnSearchbar.vue'; import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
import { useStateStore } from 'stores/useStateStore'; import LeftMenu from 'components/LeftMenu.vue';
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import ClaimDescriptor from './ClaimDescriptor.vue'; import ClaimDescriptor from './ClaimDescriptor.vue';
import { onMounted } from 'vue';
const stateStore = useStateStore(); const stateStore = useStateStore();
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute(); const route = useRoute();
const filter = {
include: [
{
relation: 'client',
scope: {
include: { relation: 'salesPersonUser' },
},
},
{
relation: 'claimState',
},
{
relation: 'ticket',
scope: {
include: [
{ relation: 'zone' },
{
relation: 'address',
scope: {
include: { relation: 'province' },
},
},
],
},
},
{
relation: 'worker',
scope: {
include: { relation: 'user' },
},
},
],
};
const arrayData = useArrayData('claimData', {
url: `Claims/${route.params.id}`,
filter,
});
const entityId = computed(() => {
return $props.id || route.params.id;
});
const $props = defineProps({ const $props = defineProps({
id: { id: {
type: Number, type: Number,
@ -19,13 +60,11 @@ const $props = defineProps({
default: null, default: null,
}, },
}); });
const entityId = computed(() => {
return $props.id || route.params.id;
});
let salixUrl; let salixUrl;
onMounted(async () => { onMounted(async () => {
salixUrl = await getUrl(`claim/${entityId.value}`); salixUrl = await getUrl(`claim/${entityId.value}`);
await arrayData.fetch({ append: false });
}); });
</script> </script>
<template> <template>

View File

@ -68,7 +68,7 @@ function viewSummary(id) {
</div> </div>
</Teleport> </Teleport>
</template> </template>
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above> <QDrawer v-model="stateStore.rightDrawer" side="right" :width="256">
<QScrollArea class="fit text-grey-8"> <QScrollArea class="fit text-grey-8">
<TicketFilter data-key="TicketList" /> <TicketFilter data-key="TicketList" />
</QScrollArea> </QScrollArea>

View File

@ -19,6 +19,7 @@ export default {
'ClaimLog', 'ClaimLog',
'ClaimNotes', 'ClaimNotes',
'ClaimDevelopment', 'ClaimDevelopment',
'ClaimAction',
], ],
}, },
children: [ children: [
@ -130,6 +131,15 @@ export default {
}, },
component: () => import('src/pages/Claim/Card/ClaimNotes.vue'), component: () => import('src/pages/Claim/Card/ClaimNotes.vue'),
}, },
{
name: 'ClaimAction',
path: 'action',
meta: {
title: 'action',
icon: 'vn:actions',
},
component: () => import('src/pages/Claim/Card/ClaimAction.vue'),
},
], ],
}, },
], ],