403 lines
12 KiB
Vue
403 lines
12 KiB
Vue
<script setup>
|
|
import { onMounted, ref, onUnmounted, computed } from 'vue';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { useStateStore } from 'stores/useStateStore';
|
|
|
|
import { beforeSave } from 'src/composables/updateMinPriceBeforeSave';
|
|
|
|
import FetchedTags from 'components/ui/FetchedTags.vue';
|
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
|
import EditFixedPriceForm from 'src/pages/Item/components/EditFixedPriceForm.vue';
|
|
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
|
import RightMenu from 'src/components/common/RightMenu.vue';
|
|
import VnTable from 'src/components/VnTable/VnTable.vue';
|
|
import VnColor from 'src/components/common/VnColor.vue';
|
|
|
|
import { toDate } from 'src/filters';
|
|
import { isLower, isBigger } from 'src/filters/date.js';
|
|
import ItemFixedPriceFilter from './ItemFixedPriceFilter.vue';
|
|
import ItemDescriptorProxy from './Card/ItemDescriptorProxy.vue';
|
|
import CloneFixedPriceForm from 'src/pages/Item/components/CloneFixedPriceForm.vue';
|
|
|
|
const stateStore = useStateStore();
|
|
const { t } = useI18n();
|
|
const tableRef = ref();
|
|
const editFixedPriceForm = ref(null);
|
|
const cloneFixedPriceForm = ref(null);
|
|
const cloneRow = ref({});
|
|
const selectedRows = ref([]);
|
|
const hasSelectedRows = computed(() => selectedRows.value.length > 0);
|
|
const dateColor = 'var(--vn-label-text-color)';
|
|
onMounted(async () => {
|
|
stateStore.rightDrawer = true;
|
|
});
|
|
onUnmounted(() => (stateStore.rightDrawer = false));
|
|
|
|
const columns = computed(() => [
|
|
{
|
|
name: 'itemFk',
|
|
label: t('item.fixedPrice.itemFk'),
|
|
labelAbbreviation: 'Id',
|
|
toolTip: t('item.fixedPrice.itemFk'),
|
|
component: 'select',
|
|
attrs: {
|
|
url: 'Items',
|
|
fields: ['id', 'name', 'subName'],
|
|
optionLabel: 'name',
|
|
optionValue: 'id',
|
|
uppercase: false,
|
|
},
|
|
columnFilter: {
|
|
inWhere: true,
|
|
},
|
|
width: '55px',
|
|
},
|
|
{
|
|
labelAbbreviation: '',
|
|
name: 'hex',
|
|
columnSearch: false,
|
|
isEditable: false,
|
|
width: '10px',
|
|
component: 'select',
|
|
attrs: {
|
|
url: 'Inks',
|
|
fields: ['id', 'name'],
|
|
},
|
|
},
|
|
{
|
|
align: 'left',
|
|
label: t('globals.name'),
|
|
name: 'name',
|
|
create: true,
|
|
component: 'input',
|
|
isEditable: false,
|
|
},
|
|
{
|
|
label: t('item.fixedPrice.groupingPrice'),
|
|
labelAbbreviation: 'Group.',
|
|
toolTip: t('item.fixedPrice.groupingPrice'),
|
|
name: 'rate2',
|
|
component: 'number',
|
|
create: true,
|
|
createOrder: 3,
|
|
width: '40px',
|
|
},
|
|
{
|
|
label: t('item.fixedPrice.packingPrice'),
|
|
labelAbbreviation: 'Pack.',
|
|
toolTip: t('item.fixedPrice.packingPrice'),
|
|
name: 'rate3',
|
|
component: 'number',
|
|
create: true,
|
|
createOrder: 4,
|
|
width: '40px',
|
|
},
|
|
{
|
|
name: 'hasMinPrice',
|
|
label: t('item.fixedPrice.hasMinPrice'),
|
|
labelAbbreviation: t('item.fixedPrice.MP'),
|
|
toolTip: t('item.fixedPrice.hasMinPrice'),
|
|
label: t('Has min price'),
|
|
component: 'checkbox',
|
|
attrs: {
|
|
toggleIndeterminate: false,
|
|
},
|
|
width: '50px',
|
|
},
|
|
{
|
|
label: t('item.fixedPrice.minPrice'),
|
|
labelAbbreviation: 'Min.P',
|
|
toolTip: t('item.fixedPrice.minPrice'),
|
|
name: 'minPrice',
|
|
component: 'number',
|
|
width: '45px',
|
|
style: (row) => {
|
|
if (!row?.hasMinPrice) return { color: 'var(--vn-label-color)' };
|
|
},
|
|
format: (row) => parseFloat(row['minPrice']).toFixed(2),
|
|
},
|
|
{
|
|
label: t('item.fixedPrice.started'),
|
|
name: 'started',
|
|
component: 'date',
|
|
columnFilter: {
|
|
component: 'date',
|
|
},
|
|
create: true,
|
|
createOrder: 5,
|
|
width: '55px',
|
|
},
|
|
{
|
|
label: t('item.fixedPrice.ended'),
|
|
name: 'ended',
|
|
component: 'date',
|
|
columnFilter: {
|
|
component: 'date',
|
|
},
|
|
create: true,
|
|
createOrder: 6,
|
|
width: '55px',
|
|
},
|
|
{
|
|
align: 'center',
|
|
label: t('globals.warehouse'),
|
|
name: 'warehouseFk',
|
|
component: 'select',
|
|
attrs: {
|
|
url: 'Warehouses',
|
|
fields: ['id', 'name'],
|
|
optionLabel: 'name',
|
|
optionValue: 'id',
|
|
},
|
|
create: true,
|
|
format: (row, dashIfEmpty) => dashIfEmpty(row.warehouseName),
|
|
width: '80px',
|
|
},
|
|
{
|
|
align: 'right',
|
|
name: 'tableActions',
|
|
actions: [
|
|
{
|
|
title: t('globals.clone'),
|
|
icon: 'vn:clone',
|
|
action: (row) => openCloneFixedPriceForm(row),
|
|
isPrimary: true,
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
|
|
const openEditFixedPriceForm = () => {
|
|
editFixedPriceForm.value.show();
|
|
};
|
|
|
|
const openCloneFixedPriceForm = (row) => {
|
|
cloneRow.value = (({ itemFk, rate2, rate3, started, ended, warehouseFk }) => ({
|
|
itemFk,
|
|
rate2,
|
|
rate3,
|
|
started,
|
|
ended,
|
|
warehouseFk,
|
|
}))(JSON.parse(JSON.stringify(row)));
|
|
|
|
cloneFixedPriceForm.value.show();
|
|
};
|
|
|
|
const dateStyle = (date) =>
|
|
date
|
|
? {
|
|
color: 'var(--vn-black-text-color)',
|
|
}
|
|
: { color: dateColor, 'background-color': 'transparent' };
|
|
</script>
|
|
|
|
<template>
|
|
<RightMenu>
|
|
<template #right-panel>
|
|
<ItemFixedPriceFilter data-key="ItemFixedPrices" />
|
|
</template>
|
|
</RightMenu>
|
|
<VnSubToolbar />
|
|
<Teleport to="#st-data" v-if="stateStore?.isSubToolbarShown()">
|
|
<QBtnGroup push style="column-gap: 10px">
|
|
<QBtn
|
|
:disable="!hasSelectedRows"
|
|
@click="openEditFixedPriceForm()"
|
|
color="primary"
|
|
icon="vn:wand"
|
|
flat
|
|
:label="t('globals.edit')"
|
|
data-cy="FixedPriceToolbarEditBtn"
|
|
>
|
|
<QTooltip>
|
|
{{ t('Edit fixed price(s)') }}
|
|
</QTooltip>
|
|
</QBtn>
|
|
</QBtnGroup>
|
|
</Teleport>
|
|
<VnTable
|
|
ref="tableRef"
|
|
data-key="ItemFixedPrices"
|
|
url="FixedPrices/filter"
|
|
:order="'name DESC'"
|
|
save-url="FixedPrices/crud"
|
|
:columns="columns"
|
|
:is-editable="true"
|
|
:right-search="false"
|
|
:table="{
|
|
'row-key': 'id',
|
|
selection: 'multiple',
|
|
}"
|
|
v-model:selected="selectedRows"
|
|
:create="{
|
|
urlCreate: 'FixedPrices',
|
|
title: t('Create fixed price'),
|
|
formInitialData: {},
|
|
onDataSaved: () => tableRef.reload(),
|
|
showSaveAndContinueBtn: true,
|
|
}"
|
|
:disable-option="{ card: true }"
|
|
auto-load
|
|
:beforeSaveFn="(data, getChanges) => beforeSave(data, getChanges, 'FixedPrices')"
|
|
>
|
|
<template #column-hex="{ row }">
|
|
<VnColor :colors="row?.hexJson" style="height: 100%; min-width: 2000px" />
|
|
</template>
|
|
<template #column-name="{ row }">
|
|
<span class="link">
|
|
{{ row.name }}
|
|
</span>
|
|
<span class="subName">{{ row.subName }}</span>
|
|
<ItemDescriptorProxy :id="row.itemFk" />
|
|
<FetchedTags :item="row" :columns="6" />
|
|
</template>
|
|
<template #column-started="{ row }">
|
|
<div class="editable-text q-pb-xxs">
|
|
<QBadge class="badge" :style="dateStyle(isLower(row?.ended))">
|
|
{{ toDate(row?.started) }}
|
|
</QBadge>
|
|
</div>
|
|
</template>
|
|
<template #column-ended="{ row }">
|
|
<div class="editable-text q-pb-xxs">
|
|
<QBadge class="badge" :style="dateStyle(isBigger(row?.ended))">
|
|
{{ toDate(row?.ended) }}
|
|
</QBadge>
|
|
</div>
|
|
</template>
|
|
<template #column-create-name="{ data }">
|
|
<VnSelect
|
|
url="Items/search"
|
|
v-model="data.itemFk"
|
|
:label="t('item.fixedPrice.itemName')"
|
|
:fields="['id', 'name']"
|
|
:filter-options="['id', 'name']"
|
|
option-label="name"
|
|
option-value="id"
|
|
:required="true"
|
|
sort-by="name ASC"
|
|
data-cy="FixedPriceCreateNameSelect"
|
|
>
|
|
<template #option="scope">
|
|
<QItem v-bind="scope.itemProps">
|
|
<QItemSection>
|
|
<QItemLabel>
|
|
{{ scope.opt.name }}
|
|
</QItemLabel>
|
|
<QItemLabel caption> #{{ scope.opt.id }} </QItemLabel>
|
|
</QItemSection>
|
|
</QItem>
|
|
</template>
|
|
</VnSelect>
|
|
</template>
|
|
<template #column-create-warehouseFk="{ data }">
|
|
<VnSelect
|
|
:label="t('globals.warehouse')"
|
|
url="Warehouses"
|
|
v-model="data.warehouseFk"
|
|
:fields="['id', 'name']"
|
|
option-label="name"
|
|
option-value="id"
|
|
hide-selected
|
|
:required="true"
|
|
sort-by="name ASC"
|
|
data-cy="FixedPriceCreateWarehouseSelect"
|
|
>
|
|
<template #option="scope">
|
|
<QItem v-bind="scope.itemProps">
|
|
<QItemSection>
|
|
<QItemLabel>
|
|
{{ scope.opt.name }}
|
|
</QItemLabel>
|
|
<QItemLabel caption> #{{ scope.opt.id }} </QItemLabel>
|
|
</QItemSection>
|
|
</QItem>
|
|
</template>
|
|
</VnSelect>
|
|
</template>
|
|
</VnTable>
|
|
|
|
<QDialog ref="editFixedPriceForm">
|
|
<EditFixedPriceForm
|
|
edit-url="FixedPrices/editFixedPrice"
|
|
:rows="selectedRows"
|
|
:fields-options="
|
|
columns.filter(
|
|
({ isEditable, component, name }) =>
|
|
isEditable !== false && component && name !== 'itemFk',
|
|
)
|
|
"
|
|
:beforeSave="beforeSave"
|
|
@on-data-saved="tableRef.CrudModelRef.saveChanges()"
|
|
/>
|
|
</QDialog>
|
|
<QDialog ref="cloneFixedPriceForm">
|
|
<CloneFixedPriceForm :row="cloneRow" @on-data-saved="tableRef.reload()" />
|
|
</QDialog>
|
|
</template>
|
|
<style lang="scss">
|
|
.q-table th,
|
|
.q-table td {
|
|
padding-inline: 5px !important;
|
|
}
|
|
.q-table tr td {
|
|
font-size: 10pt;
|
|
border-top: none;
|
|
border-collapse: collapse;
|
|
}
|
|
.q-table tbody td {
|
|
max-width: none;
|
|
.q-td.col {
|
|
& .vnInputDate {
|
|
min-width: 90px;
|
|
}
|
|
& div.row {
|
|
& .q-checkbox {
|
|
& .q-checkbox__inner {
|
|
position: relative !important;
|
|
&.q-checkbox__inner--truthy {
|
|
color: var(--q-primary);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.q-field__after,
|
|
.q-field__append {
|
|
padding: 0;
|
|
}
|
|
|
|
tbody tr.highlight .q-td {
|
|
animation: highlight-animation 4s ease-in-out;
|
|
}
|
|
@keyframes highlight-animation {
|
|
0% {
|
|
background-color: $primary-light;
|
|
}
|
|
100% {
|
|
background-color: transparent;
|
|
}
|
|
}
|
|
.subName {
|
|
margin-left: 5%;
|
|
font-size: 0.75rem;
|
|
text-transform: uppercase;
|
|
color: var(--vn-label-color);
|
|
}
|
|
</style>
|
|
|
|
<style lang="scss" scoped>
|
|
.badge {
|
|
background-color: $warning;
|
|
}
|
|
</style>
|
|
|
|
<i18n>
|
|
es:
|
|
Add fixed price: Añadir precio fijado
|
|
Edit fixed price(s): Editar precio(s) fijado(s)
|
|
Create fixed price: Crear precio fijado
|
|
</i18n>
|