feat: solve minor bugs and styles

This commit is contained in:
Javier Segarra 2025-05-05 12:26:37 +02:00
parent 22f77fc70c
commit 76df3413b9
5 changed files with 158 additions and 41 deletions

View File

@ -1,5 +1,5 @@
<script setup>
import { toPercentage } from 'filters/index';
import { toCurrency, toPercentage } from 'filters/index';
import { computed } from 'vue';
@ -8,6 +8,10 @@ const props = defineProps({
type: Number,
required: true,
},
format: {
type: String,
default: 'percentage', // 'currency'
},
});
const valueClass = computed(() =>
@ -21,7 +25,10 @@ const formattedValue = computed(() => props.value);
<template>
<span :class="valueClass">
<QIcon :name="iconName" size="sm" class="value-icon" />
{{ toPercentage(formattedValue) }}
<span v-if="$props.format === 'percentage'">{{
toPercentage(formattedValue)
}}</span>
<span v-if="$props.format === 'currency'">{{ toCurrency(formattedValue) }}</span>
</span>
</template>

View File

@ -42,7 +42,7 @@ const ticketConfig = ref({});
const proposalTableRef = ref(null);
const sale = computed(() => $props.sales[0]);
const saleFk = computed(() => sale.value.saleFk);
const saleFk = computed(() => sale.value?.saleFk);
const filter = computed(() => ({
where: $props.filter,
@ -56,8 +56,24 @@ const defaultColumnAttrs = {
};
const emit = defineEmits(['onDialogClosed', 'itemReplaced']);
const conditionalValuePrice = (price) =>
price > 1 + ticketConfig.value.lackAlertPrice / 100 ? 'match' : 'not-match';
const priceStatusClass = (proposalPrice) => {
const originalPrice = sale.value?.price;
if (
!originalPrice ||
!ticketConfig.value ||
typeof ticketConfig.value.lackAlertPrice !== 'number'
) {
return 'price-ok';
}
const priceIncreasePercentage =
((proposalPrice - originalPrice) / originalPrice) * 100;
return priceIncreasePercentage > ticketConfig.value.lackAlertPrice
? 'price-alert'
: 'price-ok';
};
const columns = computed(() => [
{
@ -97,7 +113,15 @@ const columns = computed(() => [
{
align: 'left',
sortable: true,
label: t('item.list.color'),
label: t('item.list.producer'),
name: 'subName',
field: 'subName',
columnClass: 'expand',
},
{
align: 'left',
sortable: true,
label: t('proposal.tag5'),
name: 'tag5',
field: 'value5',
columnClass: 'expand',
@ -105,7 +129,7 @@ const columns = computed(() => [
{
align: 'left',
sortable: true,
label: t('item.list.stems'),
label: t('proposal.tag6'),
name: 'tag6',
field: 'value6',
columnClass: 'expand',
@ -113,12 +137,27 @@ const columns = computed(() => [
{
align: 'left',
sortable: true,
label: t('item.list.producer'),
label: t('proposal.tag7'),
name: 'tag7',
field: 'value7',
columnClass: 'expand',
},
{
align: 'left',
sortable: true,
label: t('proposal.tag8'),
name: 'tag8',
field: 'value8',
columnClass: 'expand',
},
{
align: 'left',
sortable: true,
label: t('proposal.advanceable'),
name: 'advanceable',
field: 'advanceable',
columnClass: 'expand',
},
{
...defaultColumnAttrs,
label: t('proposal.price2'),
@ -169,14 +208,14 @@ function extractMatchValues(obj) {
.filter((key) => key.startsWith(MATCH))
.map((key) => parseInt(key.replace(MATCH, ''), 10));
}
const gradientStyle = (value) => {
const gradientStyleClass = (row) => {
let color = 'white';
const perc = parseFloat(value);
const value = parseFloat(row);
switch (true) {
case perc >= 0 && perc < 33:
case value >= 0 && value < 33:
color = 'primary';
break;
case perc >= 33 && perc < 66:
case value >= 33 && value < 66:
color = 'warning';
break;
@ -193,34 +232,49 @@ const statusConditionalValue = (row) => {
};
const isSelectionAvailable = (itemProposal) => {
const { price2 } = itemProposal;
const salePrice = sale.value.price;
const byPrice = (100 * price2) / salePrice > ticketConfig.value.lackAlertPrice;
if (byPrice) {
return byPrice;
const { price2, available } = itemProposal;
const originalPrice = sale.value?.price;
const lackQuantity = $props.itemLack?.lack;
if (
!originalPrice ||
!lackQuantity ||
!ticketConfig.value ||
typeof ticketConfig.value.lackAlertPrice !== 'number'
) {
return false;
}
const byQuantity =
(100 * itemProposal.available) / Math.abs($props.itemLack.lack) <
ticketConfig.value.lackAlertPrice;
return byQuantity;
const priceIncreasePercentage = ((price2 - originalPrice) / originalPrice) * 100;
const isPriceTooHigh = priceIncreasePercentage > ticketConfig.value.lackAlertPrice;
if (isPriceTooHigh) {
return false;
}
const availablePercentage = (available / Math.abs(lackQuantity)) * 100;
const hasEnoughQuantity = availablePercentage >= ticketConfig.value.lackAlertPrice;
return hasEnoughQuantity;
};
async function change({ itemFk: substitutionFk }) {
try {
let body;
const promises = $props.sales.map(({ saleFk, quantity }) => {
const params = {
body = {
saleFk,
substitutionFk,
quantity,
};
return axios.post('Sales/replaceItem', params);
return axios.post('Sales/replaceItem', body);
});
const results = await Promise.allSettled(promises);
notifyResults(results, 'saleFk');
emit('itemReplaced', {
...body,
type: 'refresh',
quantity: quantity.value,
itemProposal: proposalSelected.value[0],
});
proposalSelected.value = [];
@ -232,6 +286,13 @@ async function change({ itemFk: substitutionFk }) {
async function handleTicketConfig(data) {
ticketConfig.value = data[0];
}
function filterRows(data) {
const filteredRows = data.sort(
(a, b) => isSelectionAvailable(b) - isSelectionAvailable(a),
);
proposalTableRef.value.CrudModelRef.formData = filteredRows;
}
</script>
<template>
<FetchData
@ -251,6 +312,7 @@ async function handleTicketConfig(data) {
:user-filter="filter"
:columns="columns"
class="full-width q-mt-md"
@on-fetch="filterRows"
row-key="id"
:row-click="change"
:is-editable="false"
@ -273,7 +335,9 @@ async function handleTicketConfig(data) {
>
<div
class="middle full-width"
:class="[`proposal-${gradientStyle(statusConditionalValue(row))}`]"
:class="[
`proposal-${gradientStyleClass(statusConditionalValue(row))}`,
]"
>
<QTooltip> {{ statusConditionalValue(row) }}% </QTooltip>
</div>
@ -294,6 +358,9 @@ async function handleTicketConfig(data) {
<template #column-tag7="{ row }">
<span :class="{ match: !row.match7 }">{{ row.value7 }}</span>
</template>
<template #column-tag8="{ row }">
<span :class="{ match: !row.match8 }">{{ row.value8 }}</span>
</template>
<template #column-counter="{ row }">
<span
:class="{
@ -308,8 +375,17 @@ async function handleTicketConfig(data) {
</template>
<template #column-price2="{ row }">
<div class="flex column items-center content-center">
<VnStockValueDisplay :value="(sales[0].price - row.price2) / 100" />
<span :class="[conditionalValuePrice(row.price2)]">{{
<!-- Use class binding for tooltip background -->
<QTooltip :offset="[0, 5]" anchor="top middle" self="bottom middle">
<div>{{ $t('proposal.price2') }}: {{ toCurrency(row.price2) }}</div>
<div>
{{ $t('proposal.itemOldPrice') }}:
{{ toCurrency(sales[0]?.price) }}
</div>
</QTooltip>
<VnStockValueDisplay :format="'currency'" :value="-row.price2 / 100" />
<!-- Use class binding for text color -->
<span :class="[priceStatusClass(row.price2)]">{{
toCurrency(row.price2)
}}</span>
</div>
@ -323,12 +399,37 @@ async function handleTicketConfig(data) {
margin-right: 2px;
flex: 2 0 5px;
}
.match {
/* Removed old .match / .not-match specific to price */
/* .match {
color: $negative;
}
.not-match {
color: inherit;
} */
/* Added classes for price status */
.price-alert {
color: $negative; /* Alert text color */
&.q-tooltip {
background-color: $negative; /* Alert tooltip background */
color: white; /* Ensure tooltip text is readable */
}
}
.price-ok {
color: inherit; /* Default text color */
&.q-tooltip {
/* Keep default tooltip background or set a specific 'ok' color */
background-color: $positive; /* Example: green background for OK price */
color: white; /* Ensure tooltip text is readable */
}
}
.match {
color: $negative;
}
.proposal-warning {
background-color: $warning;
}

View File

@ -23,33 +23,32 @@ const $props = defineProps({
default: () => [],
},
});
const { dialogRef } = useDialogPluginComponent();
const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } =
useDialogPluginComponent();
const emit = defineEmits([
'onDialogClosed',
'onDialogOk',
'itemReplaced',
...useDialogPluginComponent.emits,
]);
defineExpose({ show: () => dialogRef.value.show(), hide: () => dialogRef.value.hide() });
const itemReplaced = (data) => {
onDialogOK(data);
dialogRef.value.hide();
};
</script>
<template>
<QDialog ref="dialogRef" transition-show="scale" transition-hide="scale">
<QCard class="dialog-width">
<QCardSection class="row items-center q-pb-none">
<span class="text-h6 text-grey">{{ $t('itemProposal') }}</span>
<span class="text-h6 text-grey" v-text="$t('itemProposal')" />
<QSpace />
<QBtn icon="close" flat round dense v-close-popup />
</QCardSection>
<QCardSection>
<ItemProposal
v-bind="$props"
@item-replaced="
(data) => {
emit('itemReplaced', data);
dialogRef.hide();
}
"
></ItemProposal
></QCardSection>
<ItemProposal v-bind="$props" @item-replaced="itemReplaced"
/></QCardSection>
</QCard>
</QDialog>
</template>

View File

@ -231,6 +231,11 @@ proposal:
value6: value6
value7: value7
value8: value8
tag5: Tag5
tag6: Tag6
tag7: Tag7
tag8: Tag8
advanceable: Advanceable
available: Available
minQuantity: minQuantity
price2: Price

View File

@ -237,11 +237,16 @@ proposal:
value6: value6
value7: value7
value8: value8
tag5: Tag5
tag6: Tag6
tag7: Tag7
tag8: Tag8
available: Disponible
minQuantity: Min. cantidad
price2: Precio
located: Ubicado
counter: Contador
advanceable: Adelantable
difference: Diferencial
groupingPrice: Precio Grouping
itemOldPrice: Precio itemOld