feat: solve minor bugs and styles
This commit is contained in:
parent
22f77fc70c
commit
76df3413b9
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { toPercentage } from 'filters/index';
|
import { toCurrency, toPercentage } from 'filters/index';
|
||||||
|
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
@ -8,6 +8,10 @@ const props = defineProps({
|
||||||
type: Number,
|
type: Number,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
format: {
|
||||||
|
type: String,
|
||||||
|
default: 'percentage', // 'currency'
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const valueClass = computed(() =>
|
const valueClass = computed(() =>
|
||||||
|
@ -21,7 +25,10 @@ const formattedValue = computed(() => props.value);
|
||||||
<template>
|
<template>
|
||||||
<span :class="valueClass">
|
<span :class="valueClass">
|
||||||
<QIcon :name="iconName" size="sm" class="value-icon" />
|
<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>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ const ticketConfig = ref({});
|
||||||
const proposalTableRef = ref(null);
|
const proposalTableRef = ref(null);
|
||||||
|
|
||||||
const sale = computed(() => $props.sales[0]);
|
const sale = computed(() => $props.sales[0]);
|
||||||
const saleFk = computed(() => sale.value.saleFk);
|
const saleFk = computed(() => sale.value?.saleFk);
|
||||||
const filter = computed(() => ({
|
const filter = computed(() => ({
|
||||||
where: $props.filter,
|
where: $props.filter,
|
||||||
|
|
||||||
|
@ -56,8 +56,24 @@ const defaultColumnAttrs = {
|
||||||
};
|
};
|
||||||
const emit = defineEmits(['onDialogClosed', 'itemReplaced']);
|
const emit = defineEmits(['onDialogClosed', 'itemReplaced']);
|
||||||
|
|
||||||
const conditionalValuePrice = (price) =>
|
const priceStatusClass = (proposalPrice) => {
|
||||||
price > 1 + ticketConfig.value.lackAlertPrice / 100 ? 'match' : 'not-match';
|
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(() => [
|
const columns = computed(() => [
|
||||||
{
|
{
|
||||||
|
@ -97,7 +113,15 @@ const columns = computed(() => [
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
sortable: true,
|
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',
|
name: 'tag5',
|
||||||
field: 'value5',
|
field: 'value5',
|
||||||
columnClass: 'expand',
|
columnClass: 'expand',
|
||||||
|
@ -105,7 +129,7 @@ const columns = computed(() => [
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
label: t('item.list.stems'),
|
label: t('proposal.tag6'),
|
||||||
name: 'tag6',
|
name: 'tag6',
|
||||||
field: 'value6',
|
field: 'value6',
|
||||||
columnClass: 'expand',
|
columnClass: 'expand',
|
||||||
|
@ -113,12 +137,27 @@ const columns = computed(() => [
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
label: t('item.list.producer'),
|
label: t('proposal.tag7'),
|
||||||
name: 'tag7',
|
name: 'tag7',
|
||||||
field: 'value7',
|
field: 'value7',
|
||||||
columnClass: 'expand',
|
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,
|
...defaultColumnAttrs,
|
||||||
label: t('proposal.price2'),
|
label: t('proposal.price2'),
|
||||||
|
@ -169,14 +208,14 @@ function extractMatchValues(obj) {
|
||||||
.filter((key) => key.startsWith(MATCH))
|
.filter((key) => key.startsWith(MATCH))
|
||||||
.map((key) => parseInt(key.replace(MATCH, ''), 10));
|
.map((key) => parseInt(key.replace(MATCH, ''), 10));
|
||||||
}
|
}
|
||||||
const gradientStyle = (value) => {
|
const gradientStyleClass = (row) => {
|
||||||
let color = 'white';
|
let color = 'white';
|
||||||
const perc = parseFloat(value);
|
const value = parseFloat(row);
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case perc >= 0 && perc < 33:
|
case value >= 0 && value < 33:
|
||||||
color = 'primary';
|
color = 'primary';
|
||||||
break;
|
break;
|
||||||
case perc >= 33 && perc < 66:
|
case value >= 33 && value < 66:
|
||||||
color = 'warning';
|
color = 'warning';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -193,34 +232,49 @@ const statusConditionalValue = (row) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const isSelectionAvailable = (itemProposal) => {
|
const isSelectionAvailable = (itemProposal) => {
|
||||||
const { price2 } = itemProposal;
|
const { price2, available } = itemProposal;
|
||||||
const salePrice = sale.value.price;
|
const originalPrice = sale.value?.price;
|
||||||
const byPrice = (100 * price2) / salePrice > ticketConfig.value.lackAlertPrice;
|
const lackQuantity = $props.itemLack?.lack;
|
||||||
if (byPrice) {
|
|
||||||
return byPrice;
|
if (
|
||||||
|
!originalPrice ||
|
||||||
|
!lackQuantity ||
|
||||||
|
!ticketConfig.value ||
|
||||||
|
typeof ticketConfig.value.lackAlertPrice !== 'number'
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
const byQuantity =
|
|
||||||
(100 * itemProposal.available) / Math.abs($props.itemLack.lack) <
|
const priceIncreasePercentage = ((price2 - originalPrice) / originalPrice) * 100;
|
||||||
ticketConfig.value.lackAlertPrice;
|
const isPriceTooHigh = priceIncreasePercentage > ticketConfig.value.lackAlertPrice;
|
||||||
return byQuantity;
|
|
||||||
|
if (isPriceTooHigh) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const availablePercentage = (available / Math.abs(lackQuantity)) * 100;
|
||||||
|
const hasEnoughQuantity = availablePercentage >= ticketConfig.value.lackAlertPrice;
|
||||||
|
|
||||||
|
return hasEnoughQuantity;
|
||||||
};
|
};
|
||||||
|
|
||||||
async function change({ itemFk: substitutionFk }) {
|
async function change({ itemFk: substitutionFk }) {
|
||||||
try {
|
try {
|
||||||
|
let body;
|
||||||
const promises = $props.sales.map(({ saleFk, quantity }) => {
|
const promises = $props.sales.map(({ saleFk, quantity }) => {
|
||||||
const params = {
|
body = {
|
||||||
saleFk,
|
saleFk,
|
||||||
substitutionFk,
|
substitutionFk,
|
||||||
quantity,
|
quantity,
|
||||||
};
|
};
|
||||||
return axios.post('Sales/replaceItem', params);
|
return axios.post('Sales/replaceItem', body);
|
||||||
});
|
});
|
||||||
const results = await Promise.allSettled(promises);
|
const results = await Promise.allSettled(promises);
|
||||||
|
|
||||||
notifyResults(results, 'saleFk');
|
notifyResults(results, 'saleFk');
|
||||||
emit('itemReplaced', {
|
emit('itemReplaced', {
|
||||||
|
...body,
|
||||||
type: 'refresh',
|
type: 'refresh',
|
||||||
quantity: quantity.value,
|
|
||||||
itemProposal: proposalSelected.value[0],
|
itemProposal: proposalSelected.value[0],
|
||||||
});
|
});
|
||||||
proposalSelected.value = [];
|
proposalSelected.value = [];
|
||||||
|
@ -232,6 +286,13 @@ async function change({ itemFk: substitutionFk }) {
|
||||||
async function handleTicketConfig(data) {
|
async function handleTicketConfig(data) {
|
||||||
ticketConfig.value = data[0];
|
ticketConfig.value = data[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function filterRows(data) {
|
||||||
|
const filteredRows = data.sort(
|
||||||
|
(a, b) => isSelectionAvailable(b) - isSelectionAvailable(a),
|
||||||
|
);
|
||||||
|
proposalTableRef.value.CrudModelRef.formData = filteredRows;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
<FetchData
|
||||||
|
@ -251,6 +312,7 @@ async function handleTicketConfig(data) {
|
||||||
:user-filter="filter"
|
:user-filter="filter"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
class="full-width q-mt-md"
|
class="full-width q-mt-md"
|
||||||
|
@on-fetch="filterRows"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
:row-click="change"
|
:row-click="change"
|
||||||
:is-editable="false"
|
:is-editable="false"
|
||||||
|
@ -273,7 +335,9 @@ async function handleTicketConfig(data) {
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="middle full-width"
|
class="middle full-width"
|
||||||
:class="[`proposal-${gradientStyle(statusConditionalValue(row))}`]"
|
:class="[
|
||||||
|
`proposal-${gradientStyleClass(statusConditionalValue(row))}`,
|
||||||
|
]"
|
||||||
>
|
>
|
||||||
<QTooltip> {{ statusConditionalValue(row) }}% </QTooltip>
|
<QTooltip> {{ statusConditionalValue(row) }}% </QTooltip>
|
||||||
</div>
|
</div>
|
||||||
|
@ -294,6 +358,9 @@ async function handleTicketConfig(data) {
|
||||||
<template #column-tag7="{ row }">
|
<template #column-tag7="{ row }">
|
||||||
<span :class="{ match: !row.match7 }">{{ row.value7 }}</span>
|
<span :class="{ match: !row.match7 }">{{ row.value7 }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
<template #column-tag8="{ row }">
|
||||||
|
<span :class="{ match: !row.match8 }">{{ row.value8 }}</span>
|
||||||
|
</template>
|
||||||
<template #column-counter="{ row }">
|
<template #column-counter="{ row }">
|
||||||
<span
|
<span
|
||||||
:class="{
|
:class="{
|
||||||
|
@ -308,8 +375,17 @@ async function handleTicketConfig(data) {
|
||||||
</template>
|
</template>
|
||||||
<template #column-price2="{ row }">
|
<template #column-price2="{ row }">
|
||||||
<div class="flex column items-center content-center">
|
<div class="flex column items-center content-center">
|
||||||
<VnStockValueDisplay :value="(sales[0].price - row.price2) / 100" />
|
<!-- Use class binding for tooltip background -->
|
||||||
<span :class="[conditionalValuePrice(row.price2)]">{{
|
<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)
|
toCurrency(row.price2)
|
||||||
}}</span>
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -323,12 +399,37 @@ async function handleTicketConfig(data) {
|
||||||
margin-right: 2px;
|
margin-right: 2px;
|
||||||
flex: 2 0 5px;
|
flex: 2 0 5px;
|
||||||
}
|
}
|
||||||
.match {
|
|
||||||
|
/* Removed old .match / .not-match specific to price */
|
||||||
|
/* .match {
|
||||||
color: $negative;
|
color: $negative;
|
||||||
}
|
}
|
||||||
.not-match {
|
.not-match {
|
||||||
color: inherit;
|
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 {
|
.proposal-warning {
|
||||||
background-color: $warning;
|
background-color: $warning;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,33 +23,32 @@ const $props = defineProps({
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const { dialogRef } = useDialogPluginComponent();
|
|
||||||
|
const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } =
|
||||||
|
useDialogPluginComponent();
|
||||||
const emit = defineEmits([
|
const emit = defineEmits([
|
||||||
'onDialogClosed',
|
'onDialogClosed',
|
||||||
|
'onDialogOk',
|
||||||
'itemReplaced',
|
'itemReplaced',
|
||||||
...useDialogPluginComponent.emits,
|
...useDialogPluginComponent.emits,
|
||||||
]);
|
]);
|
||||||
defineExpose({ show: () => dialogRef.value.show(), hide: () => dialogRef.value.hide() });
|
defineExpose({ show: () => dialogRef.value.show(), hide: () => dialogRef.value.hide() });
|
||||||
|
const itemReplaced = (data) => {
|
||||||
|
onDialogOK(data);
|
||||||
|
dialogRef.value.hide();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<QDialog ref="dialogRef" transition-show="scale" transition-hide="scale">
|
<QDialog ref="dialogRef" transition-show="scale" transition-hide="scale">
|
||||||
<QCard class="dialog-width">
|
<QCard class="dialog-width">
|
||||||
<QCardSection class="row items-center q-pb-none">
|
<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 />
|
<QSpace />
|
||||||
<QBtn icon="close" flat round dense v-close-popup />
|
<QBtn icon="close" flat round dense v-close-popup />
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
<QCardSection>
|
<QCardSection>
|
||||||
<ItemProposal
|
<ItemProposal v-bind="$props" @item-replaced="itemReplaced"
|
||||||
v-bind="$props"
|
/></QCardSection>
|
||||||
@item-replaced="
|
|
||||||
(data) => {
|
|
||||||
emit('itemReplaced', data);
|
|
||||||
dialogRef.hide();
|
|
||||||
}
|
|
||||||
"
|
|
||||||
></ItemProposal
|
|
||||||
></QCardSection>
|
|
||||||
</QCard>
|
</QCard>
|
||||||
</QDialog>
|
</QDialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -231,6 +231,11 @@ proposal:
|
||||||
value6: value6
|
value6: value6
|
||||||
value7: value7
|
value7: value7
|
||||||
value8: value8
|
value8: value8
|
||||||
|
tag5: Tag5
|
||||||
|
tag6: Tag6
|
||||||
|
tag7: Tag7
|
||||||
|
tag8: Tag8
|
||||||
|
advanceable: Advanceable
|
||||||
available: Available
|
available: Available
|
||||||
minQuantity: minQuantity
|
minQuantity: minQuantity
|
||||||
price2: Price
|
price2: Price
|
||||||
|
|
|
@ -237,11 +237,16 @@ proposal:
|
||||||
value6: value6
|
value6: value6
|
||||||
value7: value7
|
value7: value7
|
||||||
value8: value8
|
value8: value8
|
||||||
|
tag5: Tag5
|
||||||
|
tag6: Tag6
|
||||||
|
tag7: Tag7
|
||||||
|
tag8: Tag8
|
||||||
available: Disponible
|
available: Disponible
|
||||||
minQuantity: Min. cantidad
|
minQuantity: Min. cantidad
|
||||||
price2: Precio
|
price2: Precio
|
||||||
located: Ubicado
|
located: Ubicado
|
||||||
counter: Contador
|
counter: Contador
|
||||||
|
advanceable: Adelantable
|
||||||
difference: Diferencial
|
difference: Diferencial
|
||||||
groupingPrice: Precio Grouping
|
groupingPrice: Precio Grouping
|
||||||
itemOldPrice: Precio itemOld
|
itemOldPrice: Precio itemOld
|
||||||
|
|
Loading…
Reference in New Issue