#6321 - Negative ticket #158

Open
jsegarra wants to merge 220 commits from 6321_negative_tickets into dev
7 changed files with 206 additions and 50 deletions
Showing only changes of commit 24eaaacb19 - Show all commits

View File

@ -18,8 +18,7 @@ const $props = defineProps({
}, },
columns: { columns: {
type: Number, type: Number,
required: false, default: 3,
default: null,
}, },
}); });
@ -30,10 +29,7 @@ const tags = computed(() => {
const n = tag.split(`${$props.tag}`)[1]; const n = tag.split(`${$props.tag}`)[1];
const key = `${$props.tag}${n}`; const key = `${$props.tag}${n}`;
const value = `${$props.value}${n}`; const value = `${$props.value}${n}`;
const val = $props.item[value] ?? ''; acc[$props.item[key] ?? key] = $props.item[value] ?? '';
const match = $props.item[`match${n}`] ?? '';
const style = match ? 'color:green' : '';
acc[$props.item[key] ?? key] = { val, style, match };
return acc; return acc;
}, {}); }, {});
}); });
@ -51,18 +47,15 @@ const columnStyle = computed(() => {
<template> <template>
<div class="fetchedTags"> <div class="fetchedTags">
<pre>{{ $props.item }}</pre>
<div class="wrap" :style="columnStyle"> <div class="wrap" :style="columnStyle">
<div <div
v-for="(tag, key) in tags" v-for="(val, key) in tags"
:key="key" :key="key"
class="inline-tag" class="inline-tag"
:title="`${key}: ${tag.val}`" :title="`${key}: ${val}`"
:class="{ empty: !tag.val }" :class="{ empty: !val }"
> >
<span class="text" :style="tag.style" <span class="text">{{ val }} </span>
>{{ tag.val }}// {{ tag.match }}
</span>
</div> </div>
</div> </div>
</div> </div>

View File

@ -7,7 +7,8 @@ import { isDialogOpened } from 'src/filters';
const arrayDataStore = useArrayDataStore(); const arrayDataStore = useArrayDataStore();
export function useArrayData(key = useRoute().meta.moduleName, userOptions) { export function useArrayData(key, userOptions) {
key ??= useRoute().meta.moduleName;
if (!key) throw new Error('ArrayData: A key is required to use this composable'); if (!key) throw new Error('ArrayData: A key is required to use this composable');
if (!arrayDataStore.get(key)) arrayDataStore.set(key); if (!arrayDataStore.get(key)) arrayDataStore.set(key);

View File

@ -12,17 +12,22 @@ import VnInput from 'src/components/common/VnInput.vue';
const MATCH_VALUES = [5, 6, 7, 8]; const MATCH_VALUES = [5, 6, 7, 8];
const { t } = useI18n(); const { t } = useI18n();
const extractNumericValue = (percentageString) => {
const match = percentageString.match(/(\d+(\.\d+)?)/);
return match ? parseFloat(match[0]) : null;
};
const primaryColor = '#f5b351'; const primaryColor = '#f5b351';
const colorSpacer = '#ecf0f1'; const colorSpacer = '#ecf0f1';
const compatibilityItem = (value) => `${100 * (value / MATCH_VALUES.length)}%`; const compatibilityItem = (value) => `${100 * (value / MATCH_VALUES.length)}%`;
const gradientStyle = (value) => { const gradientStyle = (value) => {
let color = 'white'; let color = 'white';
switch (value) { console.error(value, extractNumericValue(compatibilityItem(value)));
case value >= 0 && value < 33: const perc = extractNumericValue(compatibilityItem(value));
switch (true) {
case perc >= 0 && perc < 33:
color = 'orange'; color = 'orange';
break; break;
case value >= 33 && value < 66: case perc >= 33 && perc < 66:
color = 'yellow'; color = 'yellow';
break; break;
@ -62,7 +67,6 @@ const statusConditionalValue = (row) => {
const total = MATCH_VALUES.reduce((acc, i) => acc + row[`match${i}`], 0); const total = MATCH_VALUES.reduce((acc, i) => acc + row[`match${i}`], 0);
return total; return total;
}; };
const popupProxyRef = ref(null);
const proposalTableRef = ref(null); const proposalTableRef = ref(null);
const emit = defineEmits(['onDialogClosed', 'itemReplaced']); const emit = defineEmits(['onDialogClosed', 'itemReplaced']);
@ -146,6 +150,22 @@ const columns = computed(() => [
name: 'located', name: 'located',
field: 'located', field: 'located',
}, },
{
name: 'tableActions',
align: 'left',
actions: [
{
title: t('Open details'),
jgallego marked this conversation as resolved Outdated

Aqui no veo correcto usar las variables de colores definidos

Aqui no veo correcto usar las variables de colores definidos

yo lo que no veo correcto es usar el amarillo que nos de javascript sin saber cual és, creemos una variable amarillo porque tal vez en el dark o en el light lo queramos hacer amarillo pero no el mismo tono

yo lo que no veo correcto es usar el amarillo que nos de javascript sin saber cual és, creemos una variable amarillo porque tal vez en el dark o en el light lo queramos hacer amarillo pero no el mismo tono

ok, vale, cambio de style por class

ok, vale, cambio de style por class
icon: 'change_circle',
show: (row) => isSelectionAvailable(row),
action: (row) => {
proposalSelected.value = [row];
confirm();
},
isPrimary: true,
},
],
},
]); ]);
async function confirm() { async function confirm() {
@ -161,7 +181,7 @@ async function confirm() {
// schema: 'vn', // schema: 'vn',
// params, // params,
// }); // });
proposalTableRef.value.reload(); // proposalTableRef.value.reload();
emit('itemReplaced', { emit('itemReplaced', {
type: 'refresh', type: 'refresh',
quantity: quantity.value, quantity: quantity.value,
@ -169,7 +189,6 @@ async function confirm() {
...params, ...params,
}); });
proposalSelected.value = []; proposalSelected.value = [];
popupProxyRef.value.hide();
} catch (error) { } catch (error) {
jsegarra marked this conversation as resolved
Review

30 ?

30 ?
Review

Lo habia reemplazado arroba y faltaba esta

Lo habia reemplazado arroba y faltaba esta
console.error(error); console.error(error);
} }
@ -223,7 +242,6 @@ const isSelectionAvailable = (itemProposal) => {
:disable-option="{ card: true, table: true }" :disable-option="{ card: true, table: true }"
:table="{ :table="{
'row-key': 'id', 'row-key': 'id',
selection: 'single',
}" }"
> >
<template #body-selection="props"> <template #body-selection="props">
@ -244,18 +262,52 @@ const isSelectionAvailable = (itemProposal) => {
</QCheckbox> </QCheckbox>
</template> </template>
<template #column-longName="{ row }"> <template #column-longName="{ row }">
<QTd style="min-width: 800px"> <QTd
style="
max-width: 100%;
display: flex;
max-width: 100%;
/* align-items: center; */
/* justify-content: flex-start; */
/* flex: 1 1 100px; */
flex-shrink: 50px;
flex-wrap: nowrap;
"
>
<QTooltip> <QTooltip>
{{ row.id }} {{ row.id }}
</QTooltip> </QTooltip>
<!-- <QBtn flat color="blue" dense>{{ }}</QBtn> --> <!-- <QBtn flat color="blue" dense>{{ }}</QBtn> -->
<span style="font-size: x-small">({{ row.id }})</span <div
><span class="link">{{ row.longName }}</span> id="middle"
<ItemDescriptorProxy :id="row.id" /> style="
/* position: absolute; */
float: left;
margin-right: 2px;
flex: 2 0 5px;
"
:style="{
background: gradientStyle(statusConditionalValue(row)),
}"
class="compatibility"
>
<QTooltip>
{{ compatibilityItem(statusConditionalValue(row)) }}
</QTooltip>
<!-- </div> -->
</div>
<div style="flex: 2 0 100%">
<div>
<span style="font-size: x-small">({{ row.id }})</span
><span class="link">{{ row.longName }}</span>
<!-- :style="{
color: gradientStyle(statusConditionalValue(row)),
}" -->
<ItemDescriptorProxy :id="row.id" />
<section id="portraitGrid"> <!-- <section id="portraitGrid"> -->
<!-- --> <!-- -->
<!-- <div id="left"> <!-- <div id="left">
<VnImg <VnImg
:id="row.id" :id="row.id"
spinner-color="primary" spinner-color="primary"
@ -264,24 +316,23 @@ const isSelectionAvailable = (itemProposal) => {
class="image remove-bg" class="image remove-bg"
/> />
</div> --> </div> -->
<div id="right" style="min-width: 200px">
<div <!-- <FetchedTags :item="row" class="q-mb-xs" columns="4" /> -->
id="middle"
:style="{
background: gradientStyle(
statusConditionalValue(row)
),
}"
class="compatibility"
>
<QTooltip>
{{ compatibilityItem(statusConditionalValue(row)) }}
</QTooltip>
<!-- </div> -->
</div>
<FetchedTags :item="row" class="q-mb-xs" columns="4" />
</div> </div>
</section> <div :key="key" class="inline-tag" v-for="(tag, key) in [5]">
<span
class="text"
:style="{
color: row[`match${tag}`]
? 'green'
: 'var(--vn-label-color)',
}"
>
{{ row[`value${tag}`] }}
</span>
</div>
</div>
<!-- </section> -->
</QTd> </QTd>
</template> </template>
<template #column-available="{ row }"> <template #column-available="{ row }">
@ -326,7 +377,6 @@ const isSelectionAvailable = (itemProposal) => {
</template> </template>
<style lang="scss"> <style lang="scss">
.compatibility { .compatibility {
height: 1vh;
width: 100%; width: 100%;
} }

View File

@ -3,7 +3,9 @@ import ItemProposal from './ItemProposal.vue';
import VnImg from 'src/components/ui/VnImg.vue'; import VnImg from 'src/components/ui/VnImg.vue';
import FetchedTags from 'components/ui/FetchedTags.vue'; import FetchedTags from 'components/ui/FetchedTags.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue'; import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import { ref } from 'vue';
const emit = defineEmits(['onDialogClosed', 'itemReplaced']); const emit = defineEmits(['onDialogClosed', 'itemReplaced']);
const popupProxyRef = ref(null);
const $props = defineProps({ const $props = defineProps({
itemLack: { itemLack: {
@ -24,7 +26,7 @@ const $props = defineProps({
}); });
</script> </script>
<template> <template>
<QPopupProxy> <QPopupProxy ref="popupProxyRef">
<QCard> <QCard>
<QCardSection class="row items-center q-pb-none"> <QCardSection class="row items-center q-pb-none">
<span class="text-h6 text-grey">{{ $t('Item proposal') }}</span> <span class="text-h6 text-grey">{{ $t('Item proposal') }}</span>
@ -43,7 +45,12 @@ const $props = defineProps({
<QCardSection class="q-pt-none"> --> <QCardSection class="q-pt-none"> -->
<ItemProposal <ItemProposal
v-bind="$props" v-bind="$props"
@item-replaced="(data) => emit('itemReplaced', data)" @item-replaced="
(data) => {
emit('itemReplaced', data);
popupProxyRef.value.hide();
}
"
></ItemProposal ></ItemProposal
></QCardSection> ></QCardSection>
</QCard> </QCard>

View File

@ -3,6 +3,7 @@ import { computed, onMounted, onUnmounted, ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import ChangeQuantityDialog from 'pages/Ticket/Negative/components/ChangeQuantityDialog.vue'; import ChangeQuantityDialog from 'pages/Ticket/Negative/components/ChangeQuantityDialog.vue';
import ChangeStateDialog from 'pages/Ticket/Negative/components/ChangeStateDialog.vue'; import ChangeStateDialog from 'pages/Ticket/Negative/components/ChangeStateDialog.vue';
import ChangeItemDialog from 'pages/Ticket/Negative/components/ChangeItemDialog.vue';
import FetchedTags from 'components/ui/FetchedTags.vue'; import FetchedTags from 'components/ui/FetchedTags.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue'; import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
@ -24,6 +25,7 @@ const editableStates = ref([]);
const stateStore = useStateStore(); const stateStore = useStateStore();
const proposalDialogRef = ref(); const proposalDialogRef = ref();
const tableRef = ref(); const tableRef = ref();
const changeItemDialogRef = ref();
const changeStateDialogRef = ref(); const changeStateDialogRef = ref();
const changeQuantityDialogRef = ref(); const changeQuantityDialogRef = ref();
const showProposalDialog = ref(false); const showProposalDialog = ref(false);
@ -137,6 +139,16 @@ function onTicketLackFetched(data) {
<VnSubToolbar> <VnSubToolbar>
<template #st-data> <template #st-data>
<QBtnGroup push style="column-gap: 1px"> <QBtnGroup push style="column-gap: 1px">
<TicketMassiveUpdate
:disable="selectedRows.length < 2"
:label="t('negative.buttonsUpdate.item')"
:tooltip="t('negative.detail.modal.changeItem.title')"
>
<ChangeItemDialog
ref="changeItemDialogRef"
:selected-rows="selectedRows"
></ChangeItemDialog>
</TicketMassiveUpdate>
<TicketMassiveUpdate <TicketMassiveUpdate
:disable="selectedRows.length < 2" :disable="selectedRows.length < 2"
:label="t('negative.buttonsUpdate.state')" :label="t('negative.buttonsUpdate.state')"

View File

@ -0,0 +1,90 @@
<script setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import axios from 'axios';
import { useDialogPluginComponent } from 'quasar';
import VnSelect from 'src/components/common/VnSelect.vue';
import FetchData from 'components/FetchData.vue';
const editableItems = ref([]);
const { t } = useI18n();
const showChangeItemDialog = ref(false);
const newItem = ref(null);
const { dialogRef } = useDialogPluginComponent();
const $props = defineProps({
selectedRows: {
type: Array,
default: () => [],
},
});
const updateItem = async () => {
try {
showChangeItemDialog.value = true;
const rowsToUpdate = $props.selectedRows.map(({ ticketFk }) =>
axios.post(`Tickets/state`, {
ticketFk,
code: newItem.value,
})
);
await Promise.all(rowsToUpdate);
} catch (err) {
return err;
} finally {
dialogRef.value.hide({ type: 'refresh', refresh: true });
}
};
</script>
<template>
<FetchData
url="State/editableStates"
@on-fetch="(data) => (editableItems = data)"
auto-load
/>
<QCard class="q-pa-sm">
<QCardSection class="row items-center justify-center column items-stretch">
<span>{{ t('negative.detail.modal.changeItem.title') }}</span>
<VnSelect
:label="t('negative.detail.modal.changeItem.placeholder')"
v-model="newItem"
:options="editableItems"
option-label="name"
option-value="code"
/>
</QCardSection>
<QCardActions align="right">
<QBtn :label="t('globals.cancel')" color="primary" flat v-close-popup />
<QBtn
:label="t('globals.confirm')"
color="primary"
:disable="!newItem"
@click="updateItem"
unelevated
autofocus
/> </QCardActions
></QCard>
</template>
<style lang="scss" scoped>
.list {
max-height: 100%;
padding: 15px;
width: 100%;
}
.grid-style-transition {
transition: transform 0.28s, background-color 0.28s;
}
#true {
background-color: $positive;
}
#false {
background-color: $negative;
}
div.q-dialog__inner > div {
max-width: fit-content !important;
}
</style>

View File

@ -211,7 +211,7 @@ negative:
totalNegative: 'Total negatives' totalNegative: 'Total negatives'
days: Days days: Days
buttonsUpdate: buttonsUpdate:
itemProposal: Item item: Item
state: State state: State
quantity: Quantity quantity: Quantity
modalOrigin: modalOrigin:
@ -245,6 +245,9 @@ negative:
changeQuantity: changeQuantity:
title: Update tickets quantity title: Update tickets quantity
placeholder: New quantity placeholder: New quantity
changeItem:
title: Update tickets item
placeholder: New item
split: split:
title: Are you sure you want to split selected tickets? title: Are you sure you want to split selected tickets?
subTitle: Confirm split action subTitle: Confirm split action