#6825 - VnTable V1 #396
|
@ -2,17 +2,12 @@
|
|||
<span v-for="toComponent of componentArray" :key="toComponent.field">
|
||||
<component
|
||||
v-if="toComponent?.component"
|
||||
:is="
|
||||
(components && components[toComponent.component]) ?? toComponent.component
|
||||
"
|
||||
v-bind="
|
||||
typeof toComponent.attrs == 'function'
|
||||
? toComponent.attrs(value)
|
||||
: toComponent.attrs
|
||||
"
|
||||
@click="toComponent.event && toComponent.event(value)"
|
||||
:is="mix(toComponent).component"
|
||||
v-bind="mix(toComponent).attrs"
|
||||
v-on="mix(toComponent).event"
|
||||
v-model="model"
|
||||
/>
|
||||
<!-- @click="toComponent.event && toComponent.event(value)" -->
|
||||
</span>
|
||||
</template>
|
||||
<script setup>
|
||||
|
@ -40,4 +35,24 @@ const componentArray = computed(() => {
|
|||
if (typeof $props.prop === 'object') return [$props.prop];
|
||||
return $props.prop;
|
||||
});
|
||||
|
||||
function mix(toComponent) {
|
||||
const { component, attrs, event } = toComponent;
|
||||
const customComponent = $props.components[component];
|
||||
return {
|
||||
component: customComponent?.component ?? component,
|
||||
attrs: {
|
||||
...toValueAttrs(attrs),
|
||||
...toValueAttrs(customComponent?.attrs),
|
||||
...toComponent,
|
||||
...toValueAttrs(customComponent?.forceAttrs),
|
||||
},
|
||||
event: event ?? customComponent?.event,
|
||||
};
|
||||
}
|
||||
|
||||
function toValueAttrs(attrs) {
|
||||
if (!attrs) return;
|
||||
return typeof attrs == 'function' ? attrs($props.value) : attrs;
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -2,7 +2,12 @@
|
|||
import { computed, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'update:options', 'keyup.enter']);
|
||||
const emit = defineEmits([
|
||||
'update:modelValue',
|
||||
'update:options',
|
||||
'keyup.enter',
|
||||
'remove',
|
||||
]);
|
||||
|
||||
const $props = defineProps({
|
||||
modelValue: {
|
||||
|
@ -43,6 +48,7 @@ const onEnterPress = () => {
|
|||
|
||||
const handleValue = (val = null) => {
|
||||
value.value = val;
|
||||
emit('remove');
|
||||
};
|
||||
|
||||
const focus = () => {
|
||||
|
|
|
@ -22,6 +22,10 @@ const $props = defineProps({
|
|||
type: String,
|
||||
default: 'id',
|
||||
},
|
||||
optionFilter: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
default: '',
|
||||
|
@ -59,7 +63,7 @@ const $props = defineProps({
|
|||
const { t } = useI18n();
|
||||
const requiredFieldRule = (val) => val ?? t('globals.fieldRequired');
|
||||
|
||||
const { optionLabel, optionValue, options, modelValue } = toRefs($props);
|
||||
const { optionLabel, optionValue, optionFilter, options, modelValue } = toRefs($props);
|
||||
const myOptions = ref([]);
|
||||
const myOptionsOriginal = ref([]);
|
||||
const vnSelectRef = ref();
|
||||
|
@ -109,7 +113,7 @@ async function fetchFilter(val) {
|
|||
const { fields, sortBy, limit } = $props;
|
||||
let key = optionLabel.value;
|
||||
|
||||
if (new RegExp(/\d/g).test(val)) key = optionValue.value;
|
||||
if (new RegExp(/\d/g).test(val)) key = optionFilter.value ?? optionValue.value;
|
||||
|
||||
const where = { ...{ [key]: { like: `%${val}%` } }, ...$props.where };
|
||||
const fetchOptions = { where, order: sortBy, limit };
|
||||
|
|
|
@ -4,6 +4,7 @@ import { useI18n } from 'vue-i18n';
|
|||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import FormModelPopup from 'components/FormModelPopup.vue';
|
||||
import VnPaginate from 'components/ui/VnPaginate.vue';
|
||||
import VnFilterPanel from 'components/ui/VnFilterPanel.vue';
|
||||
import VnLv from 'components/ui/VnLv.vue';
|
||||
|
@ -189,7 +190,7 @@ const rowClickFunction = computed(() => {
|
|||
:column="col"
|
||||
:show-title="true"
|
||||
:data-key="$attrs['data-key']"
|
||||
v-model="params[col.field]"
|
||||
v-model="params[col.columnFilter?.field ?? col.field]"
|
||||
/>
|
||||
</QTh>
|
||||
</template>
|
||||
|
@ -197,7 +198,12 @@ const rowClickFunction = computed(() => {
|
|||
<template #body-cell="{ col, row }">
|
||||
<!-- Columns -->
|
||||
<QTd auto-width :class="`text-${col.align ?? 'left'}`">
|
||||
<VnTableColumn :column="col" :row="row" />
|
||||
<VnTableColumn
|
||||
:column="col"
|
||||
:row="row"
|
||||
:is-editable="false"
|
||||
v-model="row[col.field]"
|
||||
/>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #item="{ row, colsMap }">
|
||||
|
@ -308,12 +314,24 @@ const rowClickFunction = computed(() => {
|
|||
</QTooltip> -->
|
||||
</QPageSticky>
|
||||
<QDialog v-model="showForm" transition-show="scale" transition-hide="scale">
|
||||
<VnTableCreate
|
||||
:columns="cardTemplate.create"
|
||||
<FormModelPopup
|
||||
v-bind="{ ...$attrs, ...create }"
|
||||
:model="$attrs['data-key'] + 'Create'"
|
||||
:create="create"
|
||||
/>
|
||||
<!-- v-bind="$attrs.create" -->
|
||||
>
|
||||
<template #form-inputs="{ data }">
|
||||
<div class="grid-create">
|
||||
<VnTableColumn
|
||||
v-for="column of cardTemplate.create"
|
||||
:key="column.field"
|
||||
:column="column"
|
||||
:row="{}"
|
||||
default="input"
|
||||
v-model="data[column.field]"
|
||||
/>
|
||||
<slot name="more-create-dialog" :data="data" />
|
||||
</div>
|
||||
</template>
|
||||
</FormModelPopup>
|
||||
</QDialog>
|
||||
</template>
|
||||
<style lang="scss">
|
||||
|
@ -381,6 +399,14 @@ const rowClickFunction = computed(() => {
|
|||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.grid-create {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, max-content));
|
||||
max-width: 100%;
|
||||
grid-gap: 20px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.flex-one {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
:prop="col.before"
|
||||
:components="components"
|
||||
:value="value"
|
||||
v-model="model"
|
||||
/>
|
||||
{{ col?.component }}
|
||||
<VnComponent
|
||||
v-if="col.component"
|
||||
:prop="col"
|
||||
|
@ -13,13 +13,13 @@
|
|||
:value="value"
|
||||
v-model="model"
|
||||
/>
|
||||
<!-- ?? [defaultComponent] -->
|
||||
<span v-else>{{ dashIfEmpty(row[col.field]) }}</span>
|
||||
<VnComponent
|
||||
v-if="col.after"
|
||||
:prop="col.after"
|
||||
:components="components"
|
||||
:value="value"
|
||||
v-model="model"
|
||||
/>
|
||||
</template>
|
||||
<script setup>
|
||||
|
@ -45,29 +45,85 @@ const $props = defineProps({
|
|||
},
|
||||
default: {
|
||||
type: [Object, String],
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
componentProp: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
isEditable: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
components: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const components = {
|
||||
input: markRaw(VnInput),
|
||||
number: markRaw(VnInput),
|
||||
date: markRaw(VnInputDate),
|
||||
checkbox: markRaw(QCheckbox),
|
||||
select: markRaw(VnSelect),
|
||||
icon: markRaw(QIcon),
|
||||
const defaultComponents = {
|
||||
input: {
|
||||
component: markRaw(VnInput),
|
||||
attrs: {
|
||||
disable: !$props.isEditable,
|
||||
},
|
||||
},
|
||||
number: {
|
||||
component: markRaw(VnInput),
|
||||
attrs: {
|
||||
disable: !$props.isEditable,
|
||||
},
|
||||
},
|
||||
date: {
|
||||
component: markRaw(VnInputDate),
|
||||
attrs: {
|
||||
disable: !$props.isEditable,
|
||||
},
|
||||
},
|
||||
checkbox: {
|
||||
component: markRaw(QCheckbox),
|
||||
attrs: (prop) => {
|
||||
return {
|
||||
disable: !$props.isEditable,
|
||||
// 'true-value': 1,
|
||||
// 'false-value': 0,
|
||||
// 'model-value': Boolean(prop),
|
||||
};
|
||||
},
|
||||
forceAttrs: {
|
||||
label: null,
|
||||
},
|
||||
},
|
||||
select: {
|
||||
component: markRaw(VnSelect),
|
||||
attrs: {
|
||||
disable: !$props.isEditable,
|
||||
},
|
||||
},
|
||||
icon: {
|
||||
component: markRaw(QIcon),
|
||||
},
|
||||
};
|
||||
|
||||
const value = computed(() =>
|
||||
$props.column.format ? $props.column.format($props.row) : $props.row
|
||||
);
|
||||
const value = computed(() => {
|
||||
return $props.column.format ? $props.column.format($props.row) : $props.row;
|
||||
});
|
||||
|
||||
const col = computed(() => {
|
||||
const newColumn = { ...$props.column };
|
||||
console.log('newColumn: ', newColumn);
|
||||
console.log('newColumn.componen: ', newColumn.component);
|
||||
let newColumn = { ...$props.column };
|
||||
const specific = newColumn[$props.componentProp];
|
||||
if (specific) {
|
||||
newColumn = {
|
||||
...newColumn,
|
||||
...specific,
|
||||
...specific.attrs,
|
||||
...specific.forceAttrs,
|
||||
};
|
||||
}
|
||||
if ($props.default && !newColumn.component) newColumn.component = $props.default;
|
||||
|
||||
return newColumn;
|
||||
});
|
||||
|
||||
const components = computed(() => $props.components ?? defaultComponents);
|
||||
</script>
|
||||
|
|
|
@ -19,12 +19,7 @@ const $props = defineProps({
|
|||
<VnTableColumn
|
||||
v-for="column of $props.columns"
|
||||
:key="column.field"
|
||||
:column="{
|
||||
...(column ?? column.create),
|
||||
...{
|
||||
attrs: column,
|
||||
},
|
||||
}"
|
||||
:column="column"
|
||||
:row="{}"
|
||||
default="input"
|
||||
v-model="data[column.field]"
|
||||
|
|
|
@ -11,24 +11,15 @@
|
|||
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="{ ...isBasicComponent?.attrs, ...columnFilter.attrs }"
|
||||
v-on="isBasicComponent?.event ?? columnFilter.event"
|
||||
dense
|
||||
/>
|
||||
<span v-else class="full-width">
|
||||
<QInput
|
||||
<span class="full-width">
|
||||
<VnTableColumn
|
||||
:column="$props.column"
|
||||
:row="{}"
|
||||
default="input"
|
||||
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>
|
||||
:components="components"
|
||||
:component-prop="`columnFilter`"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div v-else-if="showTitle" style="height: 45px"><!-- fixme! --></div>
|
||||
|
@ -42,6 +33,7 @@ import { useArrayData } from 'composables/useArrayData';
|
|||
import VnSelect from 'components/common/VnSelect.vue';
|
||||
import VnInput from 'components/common/VnInput.vue';
|
||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||
import VnTableColumn from 'components/common/VnTableColumn.vue';
|
||||
|
||||
const $props = defineProps({
|
||||
column: {
|
||||
|
@ -60,16 +52,23 @@ const $props = defineProps({
|
|||
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(model.value) };
|
||||
const enterEvent = {
|
||||
'keyup.enter': () => addFilter(model.value),
|
||||
remove: () => addFilter(null),
|
||||
};
|
||||
const components = {
|
||||
input: {
|
||||
component: markRaw(VnInput),
|
||||
event: enterEvent,
|
||||
attrs: {
|
||||
class: 'q-px-sm q-pb-xs q-pt-none',
|
||||
dense: true,
|
||||
},
|
||||
forceAttrs: {
|
||||
label: $props.showTitle ? '' : $props.column.label,
|
||||
},
|
||||
},
|
||||
number: {
|
||||
component: markRaw(VnInput),
|
||||
|
@ -82,12 +81,18 @@ const components = {
|
|||
checkbox: {
|
||||
component: markRaw(QCheckbox),
|
||||
event: updateEvent,
|
||||
forceAttrs: {
|
||||
label: $props.showTitle ? '' : $props.column.label,
|
||||
},
|
||||
},
|
||||
select: {
|
||||
component: markRaw(VnSelect),
|
||||
event: updateEvent,
|
||||
attrs: {
|
||||
class: 'full-width q-px-sm',
|
||||
class: 'q-px-md q-pb-xs q-pt-none',
|
||||
dense: true,
|
||||
},
|
||||
forceAttrs: {
|
||||
label: $props.showTitle ? '' : $props.column.label,
|
||||
},
|
||||
},
|
||||
|
@ -109,7 +114,6 @@ const components = {
|
|||
|
||||
async function addFilter(value) {
|
||||
if (value && typeof value === 'object') value = model.value;
|
||||
console.log('VALUE: ', value);
|
||||
value = value == '' ? null : value;
|
||||
let field = columnFilter.value?.field ?? $props.column.field;
|
||||
const toFilter = { [field]: value };
|
||||
|
|
|
@ -58,6 +58,7 @@ onMounted(() => {
|
|||
if (params.value) userParams.value = JSON.parse(JSON.stringify(params.value));
|
||||
if (Object.keys(store.userParams).length > 0) {
|
||||
userParams.value = JSON.parse(JSON.stringify(store.userParams));
|
||||
params.value = { ...params.value, ...userParams.value };
|
||||
}
|
||||
emit('init', { params: userParams.value });
|
||||
});
|
||||
|
@ -147,7 +148,6 @@ async function clearFilters() {
|
|||
}
|
||||
|
||||
const tagsList = computed(() => {
|
||||
console.log('userParams.value: ', userParams.value);
|
||||
return Object.entries(userParams.value)
|
||||
.filter(([key, value]) => value && !(props.hiddenTags || []).includes(key))
|
||||
.map(([key, value]) => ({
|
||||
|
@ -166,8 +166,6 @@ const customTags = computed(() =>
|
|||
async function remove(key) {
|
||||
userParams.value[key] = null;
|
||||
params.value[key] = undefined;
|
||||
console.log('key: ', key);
|
||||
console.log('params: ', params.value);
|
||||
await arrayData.applyFilter({ params: userParams.value });
|
||||
emit('remove', key);
|
||||
|
||||
}
|
||||
|
|
|
@ -270,7 +270,8 @@ customer:
|
|||
extendedList:
|
||||
tableVisibleColumns:
|
||||
id: Identifier
|
||||
name: Name
|
||||
name: Comercial name
|
||||
socialName: Business name
|
||||
fi: Tax number
|
||||
salesPersonFk: Salesperson
|
||||
credit: Credit
|
||||
|
|
|
@ -268,7 +268,8 @@ customer:
|
|||
extendedList:
|
||||
tableVisibleColumns:
|
||||
id: Identificador
|
||||
name: Nombre
|
||||
name: Nombre Comercial
|
||||
socialName: Razón social
|
||||
fi: NIF / CIF
|
||||
salesPersonFk: Comercial
|
||||
credit: Crédito
|
||||
|
|
|
@ -3,6 +3,7 @@ import { ref, computed, onMounted } from 'vue';
|
|||
import { useI18n } from 'vue-i18n';
|
||||
import { useRouter } from 'vue-router';
|
||||
import VnTable from 'components/common/VnTable.vue';
|
||||
import VnLocation from 'src/components/common/VnLocation.vue';
|
||||
import CustomerSummary from '../Card/CustomerSummary.vue';
|
||||
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
||||
|
||||
|
@ -30,6 +31,7 @@ const selectedCustomerId = ref(0);
|
|||
const selectedSalesPersonId = ref(0);
|
||||
const allColumnNames = ref([]);
|
||||
const visibleColumns = ref([]);
|
||||
const postcodesOptions = ref([]);
|
||||
|
||||
const tableColumnComponents = {
|
||||
customerStatus: {
|
||||
|
@ -278,8 +280,8 @@ const columns = computed(() => [
|
|||
condition: () => true,
|
||||
},
|
||||
columnFilter: {
|
||||
field: 'search',
|
||||
component: 'select',
|
||||
field: 'search',
|
||||
attrs: {
|
||||
url: 'Clients',
|
||||
fields: ['id', 'name'],
|
||||
|
@ -294,33 +296,32 @@ const columns = computed(() => [
|
|||
isTitle: true,
|
||||
create: true,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: 'socialName',
|
||||
label: t('customer.extendedList.tableVisibleColumns.socialName'),
|
||||
isTitle: true,
|
||||
create: true,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: 'fi',
|
||||
label: t('customer.extendedList.tableVisibleColumns.fi'),
|
||||
name: 'fi',
|
||||
create: true,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: 'salesPersonFk',
|
||||
label: t('customer.extendedList.tableVisibleColumns.salesPersonFk'),
|
||||
name: 'salesPersonFk',
|
||||
columnFilter: {
|
||||
component: 'select',
|
||||
attrs: {
|
||||
url: 'Workers/activeWithInheritedRole',
|
||||
fields: ['id', 'name'],
|
||||
where: { role: 'salesPerson' },
|
||||
},
|
||||
},
|
||||
create: {
|
||||
component: 'select',
|
||||
attrs: {
|
||||
url: 'Workers/activeWithInheritedRole',
|
||||
fields: ['id', 'name'],
|
||||
where: { role: 'salesPerson' },
|
||||
},
|
||||
component: 'select',
|
||||
attrs: {
|
||||
url: 'Workers/activeWithInheritedRole',
|
||||
fields: ['id', 'name'],
|
||||
where: { role: 'salesPerson' },
|
||||
},
|
||||
create: true,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -359,6 +360,7 @@ const columns = computed(() => [
|
|||
field: 'street',
|
||||
label: t('customer.extendedList.tableVisibleColumns.street'),
|
||||
name: 'street',
|
||||
create: true,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -400,9 +402,16 @@ const columns = computed(() => [
|
|||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: 'businessType',
|
||||
field: 'businessTypeFk',
|
||||
label: t('customer.extendedList.tableVisibleColumns.businessTypeFk'),
|
||||
name: 'businessTypeFk',
|
||||
create: true,
|
||||
component: 'select',
|
||||
attrs: {
|
||||
url: 'BusinessTypes',
|
||||
optionLabel: 'description',
|
||||
optionValue: 'code',
|
||||
},
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -450,6 +459,8 @@ const columns = computed(() => [
|
|||
field: 'isEqualizated',
|
||||
label: t('customer.extendedList.tableVisibleColumns.isEqualizated'),
|
||||
name: 'isEqualizated',
|
||||
component: 'checkbox',
|
||||
created: true,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -473,6 +484,7 @@ const columns = computed(() => [
|
|||
field: 'hasToInvoiceByAddress',
|
||||
label: t('customer.extendedList.tableVisibleColumns.hasToInvoiceByAddress'),
|
||||
name: 'hasToInvoiceByAddress',
|
||||
component: 'checkbox',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -530,6 +542,14 @@ const navigateToTravelId = (id) => router.push({ path: `/customer/${id}` });
|
|||
const selectCustomerId = (id) => (selectedCustomerId.value = id);
|
||||
|
||||
const selectSalesPersonId = (id) => (selectedSalesPersonId.value = id);
|
||||
|
||||
function handleLocation(data, location) {
|
||||
const { town, code, provinceFk, countryFk } = location ?? {};
|
||||
data.postcode = code;
|
||||
data.city = town;
|
||||
data.provinceFk = provinceFk;
|
||||
data.countryFk = countryFk;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -569,10 +589,29 @@ const selectSalesPersonId = (id) => (selectedSalesPersonId.value = id);
|
|||
}"
|
||||
order="id DESC"
|
||||
:columns="columns"
|
||||
default-mode="card"
|
||||
redirect="customer"
|
||||
default-mode="table"
|
||||
auto-load
|
||||
>
|
||||
<template #more-create-dialog="{ data }">
|
||||
<QInput :label="t('Email')" clearable type="email" v-model="data.email">
|
||||
<template #append>
|
||||
<QIcon name="info" class="cursor-info">
|
||||
<QTooltip max-width="400px">{{
|
||||
t('customer.basicData.youCanSaveMultipleEmails')
|
||||
}}</QTooltip>
|
||||
</QIcon>
|
||||
</template>
|
||||
</QInput>
|
||||
<QInput v-model="data.userName" :label="t('Web user')" />
|
||||
<VnLocation
|
||||
:roles-allowed-to-create="['deliveryAssistant']"
|
||||
:options="postcodesOptions"
|
||||
v-model="data.location"
|
||||
@update:model-value="(location) => handleLocation(data, location)"
|
||||
>
|
||||
</VnLocation>
|
||||
</template>
|
||||
<!-- redirect="customer" -->
|
||||
<!--
|
||||
default-mode="table"
|
||||
<template #body-cell="{ col, value }">
|
||||
|
|
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