#6321 - Negative ticket #158
|
@ -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>
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
|||||||
|
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
jgallego
commented
30 ? 30 ?
jsegarra
commented
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%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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')"
|
||||||
|
|
|
@ -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>
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue
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
ok, vale, cambio de style por class