#6825 - VnTable V1 #396
|
@ -1,11 +1,17 @@
|
|||
<script setup>
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import { useQuasar } from 'quasar';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useQuasar } from 'quasar';
|
||||
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
|
||||
import VnPaginate from 'components/ui/VnPaginate.vue';
|
||||
import VnFilterPanel from 'components/ui/VnFilterPanel.vue';
|
||||
import VnLv from 'components/ui/VnLv.vue';
|
||||
|
||||
import VnBreadcrumbs from 'components/common/VnBreadcrumbs.vue';
|
||||
import VnTableColumn from 'src/components/common/VnTableColumn.vue';
|
||||
import VnLv from 'src/components/ui/VnLv.vue';
|
||||
import VnTableColumn from 'components/common/VnTableColumn.vue';
|
||||
import VnTableFilter from 'components/common/VnTableFilter.vue';
|
||||
|
||||
const $props = defineProps({
|
||||
columns: {
|
||||
|
@ -35,8 +41,11 @@ const $props = defineProps({
|
|||
});
|
||||
const { t } = useI18n();
|
||||
const $q = useQuasar();
|
||||
const stateStore = useStateStore();
|
||||
|
||||
const mode = ref('list');
|
||||
const selected = ref([]);
|
||||
const filters = ref({});
|
||||
const tableModes = computed(() => {
|
||||
const modes = [
|
||||
{
|
||||
|
@ -60,25 +69,38 @@ const tableModes = computed(() => {
|
|||
|
||||
return modes;
|
||||
});
|
||||
// {
|
||||
// isId: Boolean
|
||||
// align: 'left',
|
||||
// field: 'hasFile',
|
||||
// label: t('globals.original'),
|
||||
// name: 'hasFile',
|
||||
// component: QCheckbox ?? span,
|
||||
// cardVisible: Boolean
|
||||
// props: (prop) => ({
|
||||
// disable: true,
|
||||
// 'model-value': Boolean(prop.value),
|
||||
// }),
|
||||
// },
|
||||
// vnTableOpitons y hacer bucle
|
||||
|
||||
onMounted(() => {
|
||||
mode.value = $props.defaultMode;
|
||||
stateStore.rightDrawer = true;
|
||||
});
|
||||
|
||||
function columnsCard(cols) {
|
||||
return Object.values(cols).filter(
|
||||
(col) => col.cardVisible && !col.isId && col.field != 'tableActions'
|
||||
);
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above>
|
||||
<QScrollArea class="fit text-grey-8">
|
||||
<VnFilterPanel
|
||||
:data-key="$attrs['data-key']"
|
||||
:search-button="true"
|
||||
:params="filters"
|
||||
>
|
||||
<template #body>
|
||||
<VnTableFilter
|
||||
:column="col"
|
||||
:data-key="$attrs['data-key']"
|
||||
v-for="col of columns"
|
||||
:key="col.id"
|
||||
v-model="filters[col.field]"
|
||||
/>
|
||||
</template>
|
||||
</VnFilterPanel>
|
||||
</QScrollArea>
|
||||
</QDrawer>
|
||||
<VnPaginate v-bind="$attrs" class="q-px-md">
|
||||
<template #body="{ rows }">
|
||||
<!-- :grid="($q.screen.lt.md && reponsive) || mode != 'table'" -->
|
||||
|
@ -118,42 +140,45 @@ onMounted(() => {
|
|||
dense
|
||||
:options="tableModes"
|
||||
/>
|
||||
<QBtn icon="filter_alt" title="asd" class="bg-dark q-ml-md" dense />
|
||||
<QBtn
|
||||
icon="filter_alt"
|
||||
title="asd"
|
||||
class="bg-dark q-ml-md"
|
||||
dense
|
||||
@click="stateStore.toggleRightDrawer()"
|
||||
/>
|
||||
</template>
|
||||
<!-- VnTableColumn¿?-->
|
||||
<template #header-cell="{ col }">
|
||||
<QTh auto-width>
|
||||
<div class="q-pa-sm" :class="`text-${col.align ?? 'left'}`">
|
||||
{{ col.label }}
|
||||
</div>
|
||||
<hr class="q-ma-none divisor-line" />
|
||||
<QInput
|
||||
v-if="columnSearch"
|
||||
dense
|
||||
:type="col.component == 'number' ? 'number' : 'text'"
|
||||
class="q-px-md q-pb-xs"
|
||||
<QTh auto-width style="min-width: 100px">
|
||||
<VnTableFilter
|
||||
:column="col"
|
||||
:show-title="true"
|
||||
:data-key="$attrs['data-key']"
|
||||
v-model="filters[col.field]"
|
||||
/>
|
||||
</QTh>
|
||||
</template>
|
||||
|
||||
<template #body-cell="{ row, col }">
|
||||
<template #body-cell="{ col, row }">
|
||||
<!-- Columns -->
|
||||
<QTd auto-width :class="`text-${col.align ?? 'left'}`">
|
||||
<VnTableColumn :column="col" :row />
|
||||
<VnTableColumn :column="col" :row="row" />
|
||||
</QTd>
|
||||
</template>
|
||||
<template #item="{ row, colsMap }">
|
||||
<TransitionGroup name="grid" tag="div" class="grid">
|
||||
<QCard bordered flat>
|
||||
<QCardSection horizontal>
|
||||
<span v-for="(col, index) of colsMap" :key="col.field">
|
||||
{{ index }}
|
||||
<!-- <TransitionGroup name="grid" tag="div" class="grid"> -->
|
||||
<QCard bordered flat class="row no-wrap justify-between">
|
||||
<QCardSection vertical class="no-margin no-padding w-80">
|
||||
<!-- Chips -->
|
||||
<QCardSection horizontal class="w-80">
|
||||
<span v-for="col of colsMap" :key="col.field">
|
||||
<QChip
|
||||
:class="
|
||||
col.color
|
||||
? col.color(row)
|
||||
: col.isId == 1
|
||||
? 'bg-primary-light'
|
||||
: 'bg-secondary'
|
||||
: 'bg-chip-secondary'
|
||||
"
|
||||
square
|
||||
v-if="col.isId"
|
||||
|
@ -164,41 +189,51 @@ onMounted(() => {
|
|||
</QChip>
|
||||
</span>
|
||||
</QCardSection>
|
||||
<QCardSection class="row justify-between q-pa-sm">
|
||||
<div>
|
||||
<div v-for="col of colsMap" :key="col.field">
|
||||
<div
|
||||
v-if="
|
||||
col.cardVisible &&
|
||||
!col.isId &&
|
||||
col.field != 'tableActions'
|
||||
"
|
||||
>
|
||||
<VnLv :label="`${col.label}:`">
|
||||
<template #value>
|
||||
<VnTableColumn :column="col" :row />
|
||||
</template>
|
||||
</VnLv>
|
||||
</div>
|
||||
<!-- Fields -->
|
||||
<QCardSection
|
||||
class="q-pa-sm w-80"
|
||||
:class="
|
||||
mode == 'list' || $q.screen.lt.md
|
||||
? 'grid-three'
|
||||
: 'grid-one'
|
||||
"
|
||||
>
|
||||
<div v-for="col of columnsCard(colsMap)" :key="col.field">
|
||||
<div
|
||||
v-if="
|
||||
col.cardVisible &&
|
||||
!col.isId &&
|
||||
col.field != 'tableActions'
|
||||
"
|
||||
>
|
||||
<VnLv :label="`${col.label}:`">
|
||||
<template #value>
|
||||
<VnTableColumn :column="col" :row />
|
||||
</template>
|
||||
</VnLv>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="colsMap.tableActions" class="column">
|
||||
<QBtn
|
||||
v-for="(btn, index) of colsMap.tableActions
|
||||
.actions"
|
||||
:key="index"
|
||||
:title="btn.title"
|
||||
:icon="btn.icon"
|
||||
:outline="!btn.isPrimary"
|
||||
size="sm"
|
||||
class="q-pa-sm q-mb-sm"
|
||||
:class="{ 'bg-primary-light': btn.isPrimary }"
|
||||
@click.stop="btn.action(row)"
|
||||
/>
|
||||
</div>
|
||||
</QCardSection>
|
||||
</QCard>
|
||||
</TransitionGroup>
|
||||
</QCardSection>
|
||||
<!-- Actions -->
|
||||
<QCardSection
|
||||
v-if="colsMap.tableActions"
|
||||
class="column flex-center w-10 no-margin q-pa-xs q-gutter-y-xs"
|
||||
>
|
||||
<QBtn
|
||||
v-for="(btn, index) of colsMap.tableActions.actions"
|
||||
:key="index"
|
||||
:title="btn.title"
|
||||
:icon="btn.icon"
|
||||
:outline="!btn.isPrimary"
|
||||
size="sm"
|
||||
class="q-pa-sm"
|
||||
:class="{ 'bg-primary-light': btn.isPrimary }"
|
||||
@click.stop="btn.action(row)"
|
||||
/>
|
||||
</QCardSection>
|
||||
</QCard>
|
||||
<!-- </TransitionGroup> -->
|
||||
</template>
|
||||
</QTable>
|
||||
</template>
|
||||
|
@ -213,7 +248,7 @@ onMounted(() => {
|
|||
color: var(--vn-section-color);
|
||||
}
|
||||
|
||||
.bg-secondary {
|
||||
.bg-chip-secondary {
|
||||
background-color: var(--vn-page-color);
|
||||
color: var(--vn-text-colo);
|
||||
}
|
||||
|
@ -308,4 +343,12 @@ onMounted(() => {
|
|||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.w-80 {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.w-20 {
|
||||
width: 20%;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
<template>
|
||||
<div
|
||||
v-if="showTitle && column"
|
||||
class="q-pt-sm q-px-sm ellipsis"
|
||||
:class="`text-${column.align ?? 'left'}`"
|
||||
>
|
||||
{{ column.label }}
|
||||
</div>
|
||||
<div
|
||||
v-if="columnFilter !== false && column.field != 'tableActions'"
|
||||
class="row no-wrap"
|
||||
>
|
||||
<hr class="q-ma-none divisor-line" v-if="showTitle" />
|
||||
<component
|
||||
v-if="columnFilter?.component"
|
||||
:is="isBasicComponent?.component ?? columnFilter.component"
|
||||
v-model="model"
|
||||
v-bind="columnFilter.attrs"
|
||||
v-on="isBasicComponent?.event ?? columnFilter.event"
|
||||
dense
|
||||
/>
|
||||
<span v-else class="full-width">
|
||||
<QInput
|
||||
v-model="model"
|
||||
dense
|
||||
class="q-px-sm q-pb-xs q-pt-none"
|
||||
:label="showTitle ? '' : column.label"
|
||||
@keyup.enter="addFilter"
|
||||
>
|
||||
<template #append> </template>
|
||||
</QInput>
|
||||
</span>
|
||||
</div>
|
||||
<div v-else-if="showTitle" style="height: 45px"><!-- fixme! --></div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { markRaw, computed, defineModel } from 'vue';
|
||||
import { QCheckbox } from 'quasar';
|
||||
import { useArrayData } from 'composables/useArrayData';
|
||||
|
||||
/* basic input */
|
||||
import VnSelect from 'components/common/VnSelect.vue';
|
||||
import VnInput from 'components/common/VnInput.vue';
|
||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||
|
||||
const $props = defineProps({
|
||||
column: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
showTitle: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
dataKey: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
addModel: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
const model = defineModel();
|
||||
const arrayData = useArrayData($props.dataKey);
|
||||
const columnFilter = computed(() => $props.column?.columnFilter);
|
||||
const isBasicComponent = computed(
|
||||
() => components[$props.column?.columnFilter?.component]
|
||||
);
|
||||
|
||||
const updateEvent = { 'update:modelValue': addFilter };
|
||||
const enterEvent = { 'keyup.enter': addFilter };
|
||||
const components = {
|
||||
input: {
|
||||
component: markRaw(VnInput),
|
||||
event: enterEvent,
|
||||
},
|
||||
number: {
|
||||
component: markRaw(VnInput),
|
||||
event: enterEvent,
|
||||
},
|
||||
date: {
|
||||
component: markRaw(VnInputDate),
|
||||
event: updateEvent,
|
||||
},
|
||||
checkbox: {
|
||||
component: markRaw(QCheckbox),
|
||||
event: updateEvent,
|
||||
},
|
||||
select: {
|
||||
component: markRaw(VnSelect),
|
||||
event: updateEvent,
|
||||
},
|
||||
};
|
||||
|
||||
async function addFilter() {
|
||||
const value = model.value == '' ? null : model.value;
|
||||
const prefix = columnFilter.value?.inWhere?.prefix;
|
||||
let field = columnFilter.value?.field ?? $props.column.field;
|
||||
field = prefix ? prefix + '.' + field : field;
|
||||
const toFilter = { [field]: value };
|
||||
const filter = columnFilter.value?.inWhere
|
||||
? { filter: { where: toFilter } }
|
||||
: { params: toFilter };
|
||||
|
||||
await arrayData.addFilter(filter);
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,13 @@
|
|||
<template>
|
||||
<QSelect dense icon="filter_alt" flat size="xs" :options="filterOptions"> </QSelect>
|
||||
</template>
|
||||
<script setup>
|
||||
const model = defineModel();
|
||||
|
||||
const filterOptions = [{ label: '%' }, { label: '<' }, { label: '>' }];
|
||||
|
||||
async function encapsulate(field) {
|
||||
// ejemplo
|
||||
// si es % que te ponga {like: `%${field}%`}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,33 @@
|
|||
// {
|
||||
// isId: Boolean
|
||||
// align: 'left',
|
||||
// field: 'hasFile',
|
||||
// label: t('globals.original'),
|
||||
// name: 'hasFile',
|
||||
// component: QCheckbox ?? span,
|
||||
// cardVisible: Boolean
|
||||
// isId: 1/2
|
||||
// color: function
|
||||
// props: (prop) => ({
|
||||
// disable: true,
|
||||
// 'model-value': Boolean(prop.value),
|
||||
// }),
|
||||
// tableActions: {
|
||||
// field: 'tableActions',
|
||||
// name: 'tableActions',
|
||||
// actions: [
|
||||
// {
|
||||
// title: t('Client ticket list'),
|
||||
// icon: 'vn:ticket',
|
||||
// action: redirectToCreateView,
|
||||
// isPrimary: true,
|
||||
// },
|
||||
// {
|
||||
// title: t('Client ticket list'),
|
||||
// icon: 'preview',
|
||||
// action: (row) => viewSummary(row.id, CustomerSummary),
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// },
|
||||
// tableActions y hacer bucle
|
|
@ -62,6 +62,8 @@ onMounted(() => {
|
|||
if (Object.keys(store.userParams).length > 0) {
|
||||
userParams.value = JSON.parse(JSON.stringify(store.userParams));
|
||||
}
|
||||
|
||||
console.log('userParams.value: ', userParams.value);
|
||||
emit('init', { params: userParams.value });
|
||||
});
|
||||
|
||||
|
@ -165,7 +167,7 @@ function formatValue(value) {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<QForm @submit="search" id="filterPanelForm">
|
||||
<div id="filterPanelForm">
|
||||
|
||||
<QList dense>
|
||||
<QItem class="q-mt-xs">
|
||||
<QItemSection top>
|
||||
|
@ -255,7 +257,7 @@ function formatValue(value) {
|
|||
</QItem>
|
||||
<QSeparator />
|
||||
</template>
|
||||
</QForm>
|
||||
</div>
|
||||
<QInnerLoading
|
||||
:label="t('globals.pleaseWait')"
|
||||
:showing="isLoading"
|
||||
|
|
|
@ -265,6 +265,7 @@ const columns = computed(() => [
|
|||
field: 'customerStatus',
|
||||
label: 'customerStatus',
|
||||
name: 'customerStatus',
|
||||
columnFilter: false,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -272,6 +273,9 @@ const columns = computed(() => [
|
|||
label: t('customer.extendedList.tableVisibleColumns.id'),
|
||||
name: 'id',
|
||||
isId: 1,
|
||||
columnFilter: {
|
||||
field: 'search',
|
||||
},
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -279,6 +283,11 @@ const columns = computed(() => [
|
|||
label: t('customer.extendedList.tableVisibleColumns.name'),
|
||||
name: 'name',
|
||||
isId: 2,
|
||||
columnFilter: {
|
||||
inWhere: {
|
||||
prefix: 'c',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
|
Loading…
Reference in New Issue
Si la operacion ternaria es para el valor de la traducción, porque no ponerla dentro de la funcion t?
Otra cosa es, hacen falta las traducciones? Porque en globals tenemos yes y no