forked from verdnatura/salix-front
feat: refs #8224 wip
This commit is contained in:
parent
9086b7d48d
commit
df8cd3dd55
|
@ -15,6 +15,7 @@ import VnTableChip from 'components/VnTable/VnChip.vue';
|
|||
import VnVisibleColumn from 'src/components/VnTable/VnVisibleColumn.vue';
|
||||
import VnLv from 'components/ui/VnLv.vue';
|
||||
import VnTableOrder from 'src/components/VnTable/VnOrder.vue';
|
||||
import ContextMenu from 'src/components/common/ContextMenu.vue';
|
||||
|
||||
const $props = defineProps({
|
||||
columns: {
|
||||
|
@ -113,6 +114,10 @@ const $props = defineProps({
|
|||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
contextMenuItems: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
const { t } = useI18n();
|
||||
const stateStore = useStateStore();
|
||||
|
@ -544,6 +549,14 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
|
|||
component-prop="columnField"
|
||||
/>
|
||||
</slot>
|
||||
<ContextMenu
|
||||
v-if="contextMenuItems && contextMenuItems.length > 0"
|
||||
:data-key="$attrs['data-key']"
|
||||
:table-row="row"
|
||||
:table-col="col"
|
||||
:expr-builder="$attrs['expr-builder']"
|
||||
:context-menu-items="$props.contextMenuItems"
|
||||
/>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-tableActions="{ col, row }">
|
||||
|
@ -774,6 +787,7 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
|
|||
</FormModelPopup>
|
||||
</QDialog>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
en:
|
||||
status: Status
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { useArrayData } from 'composables/useArrayData';
|
||||
import { buildFilter } from 'filters/filterPanel';
|
||||
|
||||
const $props = defineProps({
|
||||
contextMenuItems: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
tableRow: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
dataKey: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
tableCol: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
exprBuilder: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const arrayData = useArrayData($props.dataKey, {
|
||||
exprBuilder: $props.exprBuilder,
|
||||
url: 'Tickets/filter',
|
||||
});
|
||||
|
||||
const store = arrayData.store;
|
||||
const contextMenuProps = computed(() => $props.tableCol.contextMenuProps);
|
||||
const isMenuEnabled = computed(() => contextMenuProps.value.menuEnabled);
|
||||
const isFilterAllowed = computed(() => contextMenuProps.value.filterEnabled);
|
||||
const isActionAllowed = computed(() => contextMenuProps.value.actionEnabled);
|
||||
const fieldName = computed(() => $props.tableCol.name);
|
||||
const fieldValue = computed(() => $props.tableRow[fieldName.value]);
|
||||
const copyValueField = computed(
|
||||
() => contextMenuProps.value.copyValueField || fieldName.value
|
||||
);
|
||||
|
||||
const menuItems = computed(() => {
|
||||
// If item does not have type, it will be displayed
|
||||
return $props.contextMenuItems.filter((item) => {
|
||||
return (
|
||||
(item.type === 'filter' && isFilterAllowed.value) ||
|
||||
(item.type === 'action' && isActionAllowed.value) ||
|
||||
!item.type
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Filter by current field selection
|
||||
*/
|
||||
const filterBySelection = () => {
|
||||
const where = $props.exprBuilder
|
||||
? $props.exprBuilder(fieldName.value, fieldValue.value)
|
||||
: { [fieldName.value]: fieldValue.value };
|
||||
arrayData.addFilterWhere(where);
|
||||
};
|
||||
|
||||
/**
|
||||
* Exclude by current field selection
|
||||
*/
|
||||
const excludeSelection = () => {
|
||||
console.log('Exclude selection');
|
||||
// TODO: Revisar porque no se aplica and en el filtro
|
||||
let where = { [fieldName.value]: { neq: fieldValue.value } };
|
||||
console.log('first where: ', where);
|
||||
if ($props.exprBuilder) {
|
||||
where = { [fieldName.value]: fieldValue.value };
|
||||
where = buildFilter(where, (param, value) => {
|
||||
console.log('build filter where: ', where);
|
||||
console.log('parammmmm: ', param);
|
||||
console.log('valueeeee: ', value);
|
||||
const expr = $props.exprBuilder(param, value);
|
||||
console.log('expr: ', expr);
|
||||
const props = Object.keys(expr);
|
||||
let newExpr = {};
|
||||
for (let prop of props) {
|
||||
if (expr[prop].like) {
|
||||
const operator = expr[prop].like;
|
||||
newExpr[prop] = { nlike: operator };
|
||||
} else if (expr[prop].between) {
|
||||
const operator = expr[prop].between;
|
||||
newExpr = {
|
||||
or: [
|
||||
{ [prop]: { lt: operator[0] } },
|
||||
{ [prop]: { gt: operator[1] } },
|
||||
],
|
||||
};
|
||||
} else newExpr[prop] = { neq: fieldValue.value };
|
||||
}
|
||||
console.log('newExpr: ', newExpr);
|
||||
return newExpr;
|
||||
});
|
||||
}
|
||||
|
||||
const filter = { where };
|
||||
arrayData.addFilter({ filter });
|
||||
};
|
||||
|
||||
const removeFilter = () => {
|
||||
const userFilter = store.userFilter;
|
||||
const userParams = store.userParams;
|
||||
const where = userFilter?.where;
|
||||
|
||||
let filterKey = fieldName.value;
|
||||
if ($props.exprBuilder) {
|
||||
const param = $props.exprBuilder(fieldName.value, null);
|
||||
if (param) [filterKey] = Object.keys(param);
|
||||
}
|
||||
|
||||
if (!where) return;
|
||||
|
||||
const whereKeys = Object.keys(where);
|
||||
for (let key of whereKeys) {
|
||||
removeProp(where, filterKey, key);
|
||||
|
||||
if (!Object.keys(where)) delete userFilter.where;
|
||||
}
|
||||
|
||||
function removeProp(obj, targetProp, prop) {
|
||||
if (prop == targetProp) delete obj[prop];
|
||||
|
||||
if (prop === 'and' || prop === 'or') {
|
||||
const arrayCopy = obj[prop].slice();
|
||||
for (let param of arrayCopy) {
|
||||
const [key] = Object.keys(param);
|
||||
const index = obj[prop].findIndex((param) => {
|
||||
return Object.keys(param)[0] == key;
|
||||
});
|
||||
if (key == targetProp) obj[prop].splice(index, 1);
|
||||
|
||||
if (param[key] instanceof Array) removeProp(param, filterKey, key);
|
||||
|
||||
if (Object.keys(param).length == 0) obj[prop].splice(index, 1);
|
||||
}
|
||||
|
||||
if (obj[prop].length == 0) delete obj[prop];
|
||||
}
|
||||
}
|
||||
|
||||
arrayData.applyFilter({ filter: userFilter, params: userParams });
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes all applied filters
|
||||
*/
|
||||
const removeAllFilters = () => {
|
||||
const filter = { where: null };
|
||||
arrayData.applyFilter({ filter });
|
||||
};
|
||||
|
||||
/**
|
||||
* Copies the current field
|
||||
* value to the clipboard
|
||||
*/
|
||||
const copyValue = () => {
|
||||
console.log('table row: ', $props.tableRow);
|
||||
console.log('table col: ', $props.tableCol);
|
||||
navigator.clipboard.writeText($props.tableRow[copyValueField.value]);
|
||||
};
|
||||
|
||||
const menuActions = {
|
||||
filterBySelection: () => filterBySelection(),
|
||||
excludeSelection: () => excludeSelection(),
|
||||
removeFilter: () => removeFilter(),
|
||||
removeAllFilters: () => removeAllFilters(),
|
||||
copyValue: () => copyValue(),
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<QMenu v-if="isMenuEnabled" touch-position context-menu v-bind="$attrs">
|
||||
<QList dense style="min-width: 100px">
|
||||
<QItem
|
||||
v-for="(item, index) in menuItems"
|
||||
:key="index"
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="menuActions[item.action]"
|
||||
>
|
||||
<QItemSection>{{ item.label }}</QItemSection>
|
||||
</QItem>
|
||||
</QList>
|
||||
</QMenu>
|
||||
</template>
|
|
@ -833,6 +833,12 @@ item:
|
|||
specie: Specie
|
||||
components:
|
||||
topbar: {}
|
||||
contextMenu:
|
||||
filterBySelection: Filter by selection
|
||||
excludeSelection: Exclude selection
|
||||
removeFilter: Remove filter
|
||||
removeAllFilters: Remove all filters
|
||||
copyValue: Copy value
|
||||
itemsFilterPanel:
|
||||
typeFk: Type
|
||||
value: Value
|
||||
|
|
|
@ -827,6 +827,12 @@ item:
|
|||
concept: Concepto
|
||||
components:
|
||||
topbar: {}
|
||||
contextMenu:
|
||||
filterBySelection: Filtro por selección
|
||||
excludeSelection: Excluir selección
|
||||
removeFilter: Quitar filtro por selección
|
||||
removeAllFilters: Eliminar todos los filtros
|
||||
copyValue: Copiar valor
|
||||
itemsFilterPanel:
|
||||
typeFk: Tipo
|
||||
value: Valor
|
||||
|
|
|
@ -47,7 +47,23 @@ const getGroupedStates = (data) => {
|
|||
/>
|
||||
<FetchData url="AgencyModes" @on-fetch="(data) => (agencies = data)" auto-load />
|
||||
<FetchData url="Warehouses" @on-fetch="(data) => (warehouses = data)" auto-load />
|
||||
<VnFilterPanel :data-key="props.dataKey" :search-button="true">
|
||||
<VnFilterPanel
|
||||
:data-key="props.dataKey"
|
||||
:search-button="true"
|
||||
:hidden-tags="[
|
||||
'ts.stateFk',
|
||||
'c.salesPersonFk',
|
||||
'a.provinceFk',
|
||||
'z.hour',
|
||||
't.shipped',
|
||||
't.id',
|
||||
't.refFk',
|
||||
't.zoneFk',
|
||||
't.nickname',
|
||||
't.agencyModeFk',
|
||||
't.warehouseFk',
|
||||
]"
|
||||
>
|
||||
<template #tags="{ tag, formatFn }">
|
||||
<div class="q-gutter-x-xs">
|
||||
<strong>{{ t(`params.${tag.label}`) }}: </strong>
|
||||
|
|
|
@ -5,7 +5,7 @@ import { useRoute, useRouter } from 'vue-router';
|
|||
import { useStateStore } from 'stores/useStateStore';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useQuasar } from 'quasar';
|
||||
import { toDate, toCurrency, dashIfEmpty } from 'src/filters/index';
|
||||
import { toDate, toCurrency, dashIfEmpty, dateRange } from 'src/filters/index';
|
||||
import useNotify from 'src/composables/useNotify';
|
||||
import TicketSummary from './Card/TicketSummary.vue';
|
||||
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
||||
|
@ -46,12 +46,14 @@ const userParams = {
|
|||
from: null,
|
||||
to: null,
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initializeFromQuery();
|
||||
stateStore.rightDrawer = true;
|
||||
if (!route.query.createForm) return;
|
||||
onClientSelected(JSON.parse(route.query.createForm));
|
||||
});
|
||||
|
||||
const initializeFromQuery = () => {
|
||||
const query = route.query.table ? JSON.parse(route.query.table) : {};
|
||||
from.value = query.from || from.toISOString();
|
||||
|
@ -67,6 +69,60 @@ const companiesOptions = ref([]);
|
|||
const accountingOptions = ref([]);
|
||||
const amountToReturn = ref();
|
||||
|
||||
const exprBuilder = (param, value) => {
|
||||
switch (param) {
|
||||
case 'stateFk':
|
||||
return { 'ts.stateFk': value };
|
||||
case 'salesPersonFk':
|
||||
return { 'c.salesPersonFk': value };
|
||||
case 'provinceFk':
|
||||
return { 'a.provinceFk': value };
|
||||
case 'hour':
|
||||
return { 'z.hour': value };
|
||||
case 'shipped':
|
||||
return {
|
||||
't.shipped': {
|
||||
between: dateRange(value),
|
||||
},
|
||||
};
|
||||
case 'id':
|
||||
case 'refFk':
|
||||
case 'zoneFk':
|
||||
case 'nickname':
|
||||
case 'agencyModeFk':
|
||||
case 'warehouseFk':
|
||||
return { [`t.${param}`]: value };
|
||||
}
|
||||
};
|
||||
|
||||
const contextMenuItems = [
|
||||
{
|
||||
label: t('components.contextMenu.filterBySelection'),
|
||||
action: 'filterBySelection',
|
||||
type: 'filter',
|
||||
},
|
||||
{
|
||||
label: t('components.contextMenu.excludeSelection'),
|
||||
action: 'excludeSelection',
|
||||
type: 'filter',
|
||||
},
|
||||
{
|
||||
label: t('components.contextMenu.removeFilter'),
|
||||
action: 'removeFilter',
|
||||
type: 'filter',
|
||||
},
|
||||
{
|
||||
label: t('components.contextMenu.removeAllFilters'),
|
||||
action: 'removeAllFilters',
|
||||
type: null,
|
||||
},
|
||||
{
|
||||
label: t('components.contextMenu.copyValue'),
|
||||
action: 'copyValue',
|
||||
type: 'action',
|
||||
},
|
||||
];
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -74,6 +130,11 @@ const columns = computed(() => [
|
|||
hidden: true,
|
||||
format: () => '',
|
||||
columnClass: 'expand',
|
||||
contextMenuProps: {
|
||||
menuEnabled: true,
|
||||
filterEnabled: false,
|
||||
actionEnabled: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -83,6 +144,11 @@ const columns = computed(() => [
|
|||
condition: () => true,
|
||||
},
|
||||
isId: true,
|
||||
contextMenuProps: {
|
||||
menuEnabled: true,
|
||||
filterEnabled: true,
|
||||
actionEnabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -100,11 +166,17 @@ const columns = computed(() => [
|
|||
component: null,
|
||||
},
|
||||
columnClass: 'expand',
|
||||
contextMenuProps: {
|
||||
menuEnabled: true,
|
||||
filterEnabled: true,
|
||||
actionEnabled: true,
|
||||
copyValueField: 'salesPerson',
|
||||
},
|
||||
format: (row, dashIfEmpty) => dashIfEmpty(row.salesPerson),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'shippedDate',
|
||||
name: 'shipped',
|
||||
cardVisible: true,
|
||||
label: t('ticketList.shipped'),
|
||||
columnFilter: {
|
||||
|
@ -112,18 +184,34 @@ const columns = computed(() => [
|
|||
alias: 't',
|
||||
inWhere: true,
|
||||
},
|
||||
contextMenuProps: {
|
||||
menuEnabled: true,
|
||||
filterEnabled: true,
|
||||
actionEnabled: true,
|
||||
},
|
||||
format: ({ shippedDate }) => toDate(shippedDate),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'shipped',
|
||||
name: 'shippedHour',
|
||||
label: t('ticketList.hour'),
|
||||
contextMenuProps: {
|
||||
menuEnabled: true,
|
||||
filterEnabled: false,
|
||||
actionEnabled: false,
|
||||
},
|
||||
format: (row) => toTimeFormat(row.shipped),
|
||||
},
|
||||
{
|
||||
//TODO: Revisar porque no anda exclude filter
|
||||
align: 'left',
|
||||
name: 'zoneLanding',
|
||||
label: t('ticketList.closure'),
|
||||
contextMenuProps: {
|
||||
menuEnabled: true,
|
||||
filterEnabled: true,
|
||||
actionEnabled: true,
|
||||
},
|
||||
format: (row, dashIfEmpty) => dashIfEmpty(toTimeFormat(row.zoneLanding)),
|
||||
},
|
||||
{
|
||||
|
@ -131,18 +219,34 @@ const columns = computed(() => [
|
|||
name: 'nickname',
|
||||
label: t('ticketList.nickname'),
|
||||
columnClass: 'expand',
|
||||
contextMenuProps: {
|
||||
menuEnabled: true,
|
||||
filterEnabled: true,
|
||||
actionEnabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'addressNickname',
|
||||
label: t('ticketList.addressNickname'),
|
||||
columnClass: 'expand',
|
||||
contextMenuProps: {
|
||||
menuEnabled: true,
|
||||
filterEnabled: false,
|
||||
actionEnabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'province',
|
||||
name: 'provinceFk',
|
||||
label: t('ticketList.province'),
|
||||
columnClass: 'expand',
|
||||
contextMenuProps: {
|
||||
menuEnabled: true,
|
||||
filterEnabled: true,
|
||||
actionEnabled: true,
|
||||
},
|
||||
format: (row) => row.province,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -157,6 +261,11 @@ const columns = computed(() => [
|
|||
},
|
||||
},
|
||||
columnClass: 'expand',
|
||||
contextMenuProps: {
|
||||
menuEnabled: true,
|
||||
filterEnabled: true,
|
||||
actionEnabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -172,13 +281,24 @@ const columns = computed(() => [
|
|||
inWhere: true,
|
||||
},
|
||||
columnClass: 'expand',
|
||||
contextMenuProps: {
|
||||
menuEnabled: true,
|
||||
filterEnabled: true,
|
||||
actionEnabled: true,
|
||||
},
|
||||
format: (row, dashIfEmpty) => dashIfEmpty(row.zoneName),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'warehouse',
|
||||
name: 'warehouseFk',
|
||||
label: t('ticketList.warehouse'),
|
||||
columnClass: 'expand',
|
||||
contextMenuProps: {
|
||||
menuEnabled: true,
|
||||
filterEnabled: true,
|
||||
actionEnabled: true,
|
||||
},
|
||||
format: (row) => row.warehouse,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -189,12 +309,22 @@ const columns = computed(() => [
|
|||
component: 'number',
|
||||
inWhere: true,
|
||||
},
|
||||
contextMenuProps: {
|
||||
menuEnabled: true,
|
||||
filterEnabled: false,
|
||||
actionEnabled: true,
|
||||
},
|
||||
format: (row) => toCurrency(row.totalWithVat),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'packing',
|
||||
label: t('ticketSale.packaging'),
|
||||
contextMenuProps: {
|
||||
menuEnabled: true,
|
||||
filterEnabled: false,
|
||||
actionEnabled: false,
|
||||
},
|
||||
format: (row, dashIfEmpty) => dashIfEmpty(row.packing),
|
||||
},
|
||||
{
|
||||
|
@ -221,6 +351,11 @@ const columns = computed(() => [
|
|||
},
|
||||
},
|
||||
],
|
||||
contextMenuProps: {
|
||||
menuEnabled: false,
|
||||
filterEnabled: false,
|
||||
actionEnabled: false,
|
||||
},
|
||||
},
|
||||
]);
|
||||
function redirectToLines(id) {
|
||||
|
@ -463,6 +598,7 @@ function setReference(data) {
|
|||
<TicketFilter data-key="TicketList" />
|
||||
</template>
|
||||
</RightMenu>
|
||||
|
||||
<VnTable
|
||||
ref="tableRef"
|
||||
data-key="TicketList"
|
||||
|
@ -484,7 +620,12 @@ function setReference(data) {
|
|||
'row-key': 'id',
|
||||
selection: 'multiple',
|
||||
}"
|
||||
<<<<<<< Updated upstream
|
||||
data-cy="ticketListTable"
|
||||
=======
|
||||
:context-menu-items="contextMenuItems"
|
||||
:expr-builder="exprBuilder"
|
||||
>>>>>>> Stashed changes
|
||||
>
|
||||
<template #column-statusIcons="{ row }">
|
||||
<TicketProblems :row="row" />
|
||||
|
@ -495,7 +636,7 @@ function setReference(data) {
|
|||
<CustomerDescriptorProxy :id="row.salesPersonFk" />
|
||||
</span>
|
||||
</template>
|
||||
<template #column-shippedDate="{ row }">
|
||||
<template #column-shipped="{ row }">
|
||||
<span v-if="getDateColor(row.shipped)">
|
||||
<QChip :class="getDateColor(row.shipped)" dense square>
|
||||
{{ toDate(row.shippedDate) }}
|
||||
|
|
Loading…
Reference in New Issue