refactor: refs #6897 enhance localization entries, clean up unused code, and improve component structure
This commit is contained in:
parent
84c92b8a98
commit
b258c4eaac
|
@ -64,6 +64,10 @@ const $props = defineProps({
|
||||||
type: Function,
|
type: Function,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
|
beforeSaveFn: {
|
||||||
|
type: Function,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
goTo: {
|
goTo: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
|
@ -149,7 +153,7 @@ function filter(value, update, filterOptions) {
|
||||||
(ref) => {
|
(ref) => {
|
||||||
ref.setOptionIndex(-1);
|
ref.setOptionIndex(-1);
|
||||||
ref.moveOptionSelection(1, true);
|
ref.moveOptionSelection(1, true);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,7 +180,11 @@ async function saveChanges(data) {
|
||||||
hasChanges.value = false;
|
hasChanges.value = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const changes = data || getChanges();
|
let changes = data || getChanges();
|
||||||
|
if ($props.beforeSaveFn) {
|
||||||
|
changes = await $props.beforeSaveFn(changes, getChanges);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await axios.post($props.saveUrl || $props.url + '/crud', changes);
|
await axios.post($props.saveUrl || $props.url + '/crud', changes);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -215,7 +223,7 @@ async function remove(data) {
|
||||||
|
|
||||||
if (preRemove.length) {
|
if (preRemove.length) {
|
||||||
newData = newData.filter(
|
newData = newData.filter(
|
||||||
(form) => !preRemove.some((index) => index == form.$index)
|
(form) => !preRemove.some((index) => index == form.$index),
|
||||||
);
|
);
|
||||||
const changes = getChanges();
|
const changes = getChanges();
|
||||||
if (!changes.creates?.length && !changes.updates?.length)
|
if (!changes.creates?.length && !changes.updates?.length)
|
||||||
|
@ -374,6 +382,8 @@ watch(formUrl, async () => {
|
||||||
@click="onSubmit"
|
@click="onSubmit"
|
||||||
:disable="!hasChanges"
|
:disable="!hasChanges"
|
||||||
:title="t('globals.save')"
|
:title="t('globals.save')"
|
||||||
|
v-shortcut="'s'"
|
||||||
|
shortcut="s"
|
||||||
data-cy="crudModelDefaultSaveBtn"
|
data-cy="crudModelDefaultSaveBtn"
|
||||||
/>
|
/>
|
||||||
<slot name="moreAfterActions" />
|
<slot name="moreAfterActions" />
|
||||||
|
|
|
@ -97,7 +97,7 @@ const $props = defineProps({
|
||||||
});
|
});
|
||||||
const emit = defineEmits(['onFetch', 'onDataSaved']);
|
const emit = defineEmits(['onFetch', 'onDataSaved']);
|
||||||
const modelValue = computed(
|
const modelValue = computed(
|
||||||
() => $props.model ?? `formModel_${route?.meta?.title ?? route.name}`
|
() => $props.model ?? `formModel_${route?.meta?.title ?? route.name}`,
|
||||||
).value;
|
).value;
|
||||||
const componentIsRendered = ref(false);
|
const componentIsRendered = ref(false);
|
||||||
const arrayData = useArrayData(modelValue);
|
const arrayData = useArrayData(modelValue);
|
||||||
|
@ -148,7 +148,7 @@ onMounted(async () => {
|
||||||
JSON.stringify(newVal) !== JSON.stringify(originalData.value);
|
JSON.stringify(newVal) !== JSON.stringify(originalData.value);
|
||||||
isResetting.value = false;
|
isResetting.value = false;
|
||||||
},
|
},
|
||||||
{ deep: true }
|
{ deep: true },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -156,7 +156,7 @@ onMounted(async () => {
|
||||||
if (!$props.url)
|
if (!$props.url)
|
||||||
watch(
|
watch(
|
||||||
() => arrayData.store.data,
|
() => arrayData.store.data,
|
||||||
(val) => updateAndEmit('onFetch', val)
|
(val) => updateAndEmit('onFetch', val),
|
||||||
);
|
);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
@ -165,7 +165,7 @@ watch(
|
||||||
originalData.value = null;
|
originalData.value = null;
|
||||||
reset();
|
reset();
|
||||||
await fetch();
|
await fetch();
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
onBeforeRouteLeave((to, from, next) => {
|
onBeforeRouteLeave((to, from, next) => {
|
||||||
|
@ -254,7 +254,7 @@ function filter(value, update, filterOptions) {
|
||||||
(ref) => {
|
(ref) => {
|
||||||
ref.setOptionIndex(-1);
|
ref.setOptionIndex(-1);
|
||||||
ref.moveOptionSelection(1, true);
|
ref.moveOptionSelection(1, true);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed, onMounted } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import FormModel from 'components/FormModel.vue';
|
import FormModel from 'components/FormModel.vue';
|
||||||
|
@ -15,23 +15,30 @@ defineProps({
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
showSaveAndContinueBtn: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const formModelRef = ref(null);
|
const formModelRef = ref(null);
|
||||||
const closeButton = ref(null);
|
const closeButton = ref(null);
|
||||||
|
const isSaveAndContinue = ref(false);
|
||||||
const onDataSaved = (formData, requestResponse) => {
|
const onDataSaved = (formData, requestResponse) => {
|
||||||
if (closeButton.value) closeButton.value.click();
|
if (closeButton.value && isSaveAndContinue) closeButton.value.click();
|
||||||
emit('onDataSaved', formData, requestResponse);
|
emit('onDataSaved', formData, requestResponse);
|
||||||
};
|
};
|
||||||
|
|
||||||
const isLoading = computed(() => formModelRef.value?.isLoading);
|
const isLoading = computed(() => formModelRef.value?.isLoading);
|
||||||
|
const reset = computed(() => formModelRef.value?.reset);
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
isLoading,
|
isLoading,
|
||||||
onDataSaved,
|
onDataSaved,
|
||||||
|
isSaveAndContinue,
|
||||||
|
reset,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -51,6 +58,19 @@ defineExpose({
|
||||||
<p>{{ subtitle }}</p>
|
<p>{{ subtitle }}</p>
|
||||||
<slot name="form-inputs" :data="data" :validate="validate" />
|
<slot name="form-inputs" :data="data" :validate="validate" />
|
||||||
<div class="q-mt-lg row justify-end">
|
<div class="q-mt-lg row justify-end">
|
||||||
|
<QBtn
|
||||||
|
v-if="showSaveAndContinueBtn"
|
||||||
|
:label="t('globals.isSaveAndContinue')"
|
||||||
|
:title="t('globals.isSaveAndContinue')"
|
||||||
|
type="submit"
|
||||||
|
color="primary"
|
||||||
|
class="q-ml-sm"
|
||||||
|
:disabled="isLoading"
|
||||||
|
:loading="isLoading"
|
||||||
|
data-cy="FormModelPopup_isSaveAndContinue"
|
||||||
|
z-max
|
||||||
|
@click="() => (isSaveAndContinue = true)"
|
||||||
|
/>
|
||||||
<QBtn
|
<QBtn
|
||||||
:label="t('globals.cancel')"
|
:label="t('globals.cancel')"
|
||||||
:title="t('globals.cancel')"
|
:title="t('globals.cancel')"
|
||||||
|
@ -59,10 +79,15 @@ defineExpose({
|
||||||
flat
|
flat
|
||||||
:disabled="isLoading"
|
:disabled="isLoading"
|
||||||
:loading="isLoading"
|
:loading="isLoading"
|
||||||
@click="emit('onDataCanceled')"
|
|
||||||
v-close-popup
|
|
||||||
data-cy="FormModelPopup_cancel"
|
data-cy="FormModelPopup_cancel"
|
||||||
|
v-close-popup
|
||||||
z-max
|
z-max
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
isSaveAndContinue = false;
|
||||||
|
emit('onDataCanceled');
|
||||||
|
}
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
<QBtn
|
<QBtn
|
||||||
:label="t('globals.save')"
|
:label="t('globals.save')"
|
||||||
|
@ -74,6 +99,7 @@ defineExpose({
|
||||||
:loading="isLoading"
|
:loading="isLoading"
|
||||||
data-cy="FormModelPopup_save"
|
data-cy="FormModelPopup_save"
|
||||||
z-max
|
z-max
|
||||||
|
@click="() => (isSaveAndContinue = false)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -12,6 +12,7 @@ import VnInputDate from 'components/common/VnInputDate.vue';
|
||||||
import VnInputTime from 'components/common/VnInputTime.vue';
|
import VnInputTime from 'components/common/VnInputTime.vue';
|
||||||
import VnComponent from 'components/common/VnComponent.vue';
|
import VnComponent from 'components/common/VnComponent.vue';
|
||||||
import VnUserLink from 'components/ui/VnUserLink.vue';
|
import VnUserLink from 'components/ui/VnUserLink.vue';
|
||||||
|
import VnSelectEnum from '../common/VnSelectEnum.vue';
|
||||||
|
|
||||||
const model = defineModel(undefined, { required: true });
|
const model = defineModel(undefined, { required: true });
|
||||||
const emit = defineEmits(['blur']);
|
const emit = defineEmits(['blur']);
|
||||||
|
@ -59,6 +60,7 @@ const defaultSelect = {
|
||||||
row: $props.row,
|
row: $props.row,
|
||||||
disable: !$props.isEditable,
|
disable: !$props.isEditable,
|
||||||
class: 'fit',
|
class: 'fit',
|
||||||
|
'emit-value': false,
|
||||||
},
|
},
|
||||||
forceAttrs: {
|
forceAttrs: {
|
||||||
label: $props.showLabel && $props.column.label,
|
label: $props.showLabel && $props.column.label,
|
||||||
|
@ -139,6 +141,10 @@ const defaultComponents = {
|
||||||
component: markRaw(VnSelect),
|
component: markRaw(VnSelect),
|
||||||
...defaultSelect,
|
...defaultSelect,
|
||||||
},
|
},
|
||||||
|
selectEnum: {
|
||||||
|
component: markRaw(VnSelectEnum),
|
||||||
|
...defaultSelect,
|
||||||
|
},
|
||||||
icon: {
|
icon: {
|
||||||
component: markRaw(QIcon),
|
component: markRaw(QIcon),
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { markRaw, computed } from 'vue';
|
import { markRaw, computed } from 'vue';
|
||||||
import { QCheckbox } from 'quasar';
|
import { QCheckbox, QToggle } from 'quasar';
|
||||||
import { useArrayData } from 'composables/useArrayData';
|
import { useArrayData } from 'composables/useArrayData';
|
||||||
|
|
||||||
/* basic input */
|
/* basic input */
|
||||||
|
@ -34,7 +34,7 @@ defineExpose({ addFilter, props: $props });
|
||||||
const model = defineModel(undefined, { required: true });
|
const model = defineModel(undefined, { required: true });
|
||||||
const arrayData = useArrayData(
|
const arrayData = useArrayData(
|
||||||
$props.dataKey,
|
$props.dataKey,
|
||||||
$props.searchUrl ? { searchUrl: $props.searchUrl } : null
|
$props.searchUrl ? { searchUrl: $props.searchUrl } : null,
|
||||||
);
|
);
|
||||||
const columnFilter = computed(() => $props.column?.columnFilter);
|
const columnFilter = computed(() => $props.column?.columnFilter);
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ const defaultAttrs = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const forceAttrs = {
|
const forceAttrs = {
|
||||||
label: $props.showTitle ? '' : columnFilter.value?.label ?? $props.column.label,
|
label: $props.showTitle ? '' : (columnFilter.value?.label ?? $props.column.label),
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectComponent = {
|
const selectComponent = {
|
||||||
|
@ -117,10 +117,19 @@ const components = {
|
||||||
},
|
},
|
||||||
select: selectComponent,
|
select: selectComponent,
|
||||||
rawSelect: selectComponent,
|
rawSelect: selectComponent,
|
||||||
|
toggle: {
|
||||||
|
component: markRaw(QToggle),
|
||||||
|
event: updateEvent,
|
||||||
|
attrs: {
|
||||||
|
class: $props.showTitle ? 'q-py-sm' : 'q-px-md q-py-xs fit',
|
||||||
|
'toggle-indeterminate': true,
|
||||||
|
size: 'sm',
|
||||||
|
},
|
||||||
|
forceAttrs,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
async function addFilter(value, name) {
|
async function addFilter(value, name) {
|
||||||
console.log('test');
|
|
||||||
value ??= undefined;
|
value ??= undefined;
|
||||||
if (value && typeof value === 'object') value = model.value;
|
if (value && typeof value === 'object') value = model.value;
|
||||||
value = value === '' ? undefined : value;
|
value = value === '' ? undefined : value;
|
||||||
|
@ -133,19 +142,8 @@ async function addFilter(value, name) {
|
||||||
await arrayData.addFilter({ params: { [field]: value } });
|
await arrayData.addFilter({ params: { [field]: value } });
|
||||||
}
|
}
|
||||||
|
|
||||||
function alignRow() {
|
|
||||||
switch ($props.column.align) {
|
|
||||||
case 'left':
|
|
||||||
return 'justify-start items-start';
|
|
||||||
case 'right':
|
|
||||||
return 'justify-end items-end';
|
|
||||||
default:
|
|
||||||
return 'flex-center';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const showFilter = computed(
|
const showFilter = computed(
|
||||||
() => $props.column?.columnFilter !== false && $props.column.name != 'tableActions'
|
() => $props.column?.columnFilter !== false && $props.column.name != 'tableActions',
|
||||||
);
|
);
|
||||||
|
|
||||||
const onTabPressed = async () => {
|
const onTabPressed = async () => {
|
||||||
|
@ -153,12 +151,7 @@ const onTabPressed = async () => {
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div v-if="showFilter" class="full-width flex-center" style="overflow: hidden">
|
||||||
v-if="showFilter"
|
|
||||||
class="full-width"
|
|
||||||
:class="alignRow()"
|
|
||||||
style="max-height: 45px; overflow: hidden"
|
|
||||||
>
|
|
||||||
<VnTableColumn
|
<VnTableColumn
|
||||||
:column="$props.column"
|
:column="$props.column"
|
||||||
default="input"
|
default="input"
|
||||||
|
@ -170,10 +163,6 @@ const onTabPressed = async () => {
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
/* label.test {
|
|
||||||
padding-bottom: 0px !important;
|
|
||||||
background-color: red;
|
|
||||||
} */
|
|
||||||
label.test > .q-field__inner > .q-field__control {
|
label.test > .q-field__inner > .q-field__control {
|
||||||
padding: inherit;
|
padding: inherit;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import {
|
||||||
ref,
|
ref,
|
||||||
onBeforeMount,
|
onBeforeMount,
|
||||||
onMounted,
|
onMounted,
|
||||||
|
onUnmounted,
|
||||||
computed,
|
computed,
|
||||||
watch,
|
watch,
|
||||||
h,
|
h,
|
||||||
|
@ -29,6 +30,7 @@ import VnVisibleColumn from 'src/components/VnTable/VnVisibleColumn.vue';
|
||||||
import VnLv from 'components/ui/VnLv.vue';
|
import VnLv from 'components/ui/VnLv.vue';
|
||||||
import VnTableOrder from 'src/components/VnTable/VnOrder.vue';
|
import VnTableOrder from 'src/components/VnTable/VnOrder.vue';
|
||||||
import VnTableFilter from './VnTableFilter.vue';
|
import VnTableFilter from './VnTableFilter.vue';
|
||||||
|
import { getColAlign } from 'src/composables/getColAlign';
|
||||||
|
|
||||||
const arrayData = useArrayData(useAttrs()['data-key']);
|
const arrayData = useArrayData(useAttrs()['data-key']);
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
|
@ -56,10 +58,6 @@ const $props = defineProps({
|
||||||
type: [Function, Boolean],
|
type: [Function, Boolean],
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
rowCtrlClick: {
|
|
||||||
type: [Function, Boolean],
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
redirect: {
|
redirect: {
|
||||||
type: String,
|
type: String,
|
||||||
default: null,
|
default: null,
|
||||||
|
@ -150,6 +148,7 @@ const showForm = ref(false);
|
||||||
const splittedColumns = ref({ columns: [] });
|
const splittedColumns = ref({ columns: [] });
|
||||||
const columnsVisibilitySkipped = ref();
|
const columnsVisibilitySkipped = ref();
|
||||||
const createForm = ref();
|
const createForm = ref();
|
||||||
|
const createRef = ref(null);
|
||||||
const tableRef = ref();
|
const tableRef = ref();
|
||||||
const params = ref(useFilterParams($attrs['data-key']).params);
|
const params = ref(useFilterParams($attrs['data-key']).params);
|
||||||
const orders = ref(useFilterParams($attrs['data-key']).orders);
|
const orders = ref(useFilterParams($attrs['data-key']).orders);
|
||||||
|
@ -159,6 +158,7 @@ const editingRow = ref(null);
|
||||||
const editingField = ref(null);
|
const editingField = ref(null);
|
||||||
const isTableMode = computed(() => mode.value == TABLE_MODE);
|
const isTableMode = computed(() => mode.value == TABLE_MODE);
|
||||||
const showRightIcon = computed(() => $props.rightSearch || $props.rightSearchIcon);
|
const showRightIcon = computed(() => $props.rightSearch || $props.rightSearchIcon);
|
||||||
|
const originalCreateData = $props?.create?.formInitialData;
|
||||||
const tableModes = [
|
const tableModes = [
|
||||||
{
|
{
|
||||||
icon: 'view_column',
|
icon: 'view_column',
|
||||||
|
@ -178,7 +178,8 @@ onBeforeMount(() => {
|
||||||
const urlParams = route.query[$props.searchUrl];
|
const urlParams = route.query[$props.searchUrl];
|
||||||
hasParams.value = urlParams && Object.keys(urlParams).length !== 0;
|
hasParams.value = urlParams && Object.keys(urlParams).length !== 0;
|
||||||
});
|
});
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
|
if ($props.isEditable) document.addEventListener('click', clickHandler);
|
||||||
mode.value =
|
mode.value =
|
||||||
quasar.platform.is.mobile && !$props.disableOption?.card
|
quasar.platform.is.mobile && !$props.disableOption?.card
|
||||||
? CARD_MODE
|
? CARD_MODE
|
||||||
|
@ -199,6 +200,9 @@ onMounted(() => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
onUnmounted(async () => {
|
||||||
|
if ($props.isEditable) document.removeEventListener('click', clickHandler);
|
||||||
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => $props.columns,
|
() => $props.columns,
|
||||||
|
@ -250,16 +254,6 @@ const rowClickFunction = computed(() => {
|
||||||
return () => {};
|
return () => {};
|
||||||
});
|
});
|
||||||
|
|
||||||
const rowCtrlClickFunction = computed(() => {
|
|
||||||
if ($props.rowCtrlClick != undefined) return $props.rowCtrlClick;
|
|
||||||
if ($props.redirect)
|
|
||||||
return (evt, { id }) => {
|
|
||||||
stopEventPropagation(evt);
|
|
||||||
window.open(`/#/${$props.redirect}/${id}`, '_blank');
|
|
||||||
};
|
|
||||||
return () => {};
|
|
||||||
});
|
|
||||||
|
|
||||||
function redirectFn(id) {
|
function redirectFn(id) {
|
||||||
router.push({ path: `/${$props.redirect}/${id}` });
|
router.push({ path: `/${$props.redirect}/${id}` });
|
||||||
}
|
}
|
||||||
|
@ -281,10 +275,6 @@ function columnName(col) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getColAlign(col) {
|
|
||||||
return 'text-' + (col.align ?? 'left');
|
|
||||||
}
|
|
||||||
|
|
||||||
const emit = defineEmits(['onFetch', 'update:selected', 'saveChanges']);
|
const emit = defineEmits(['onFetch', 'update:selected', 'saveChanges']);
|
||||||
defineExpose({
|
defineExpose({
|
||||||
create: createForm,
|
create: createForm,
|
||||||
|
@ -336,126 +326,114 @@ function hasEditableFormat(column) {
|
||||||
if (isEditableColumn(column)) return 'editable-text';
|
if (isEditableColumn(column)) return 'editable-text';
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleClick = async (event) => {
|
const clickHandler = async (event) => {
|
||||||
const clickedElement = event.target.closest('td');
|
const clickedElement = event.target.closest('td');
|
||||||
|
|
||||||
if (!clickedElement) return;
|
const isDateElement = event.target.closest('.q-date');
|
||||||
|
const isTimeElement = event.target.closest('.q-time');
|
||||||
|
|
||||||
const rowIndex = clickedElement.getAttribute('data-row-index');
|
if (isDateElement || isTimeElement) return;
|
||||||
console.log('HandleRowIndex: ', rowIndex);
|
|
||||||
const colField = clickedElement.getAttribute('data-col-field');
|
|
||||||
console.log('HandleColField: ', colField);
|
|
||||||
|
|
||||||
if (rowIndex !== null && colField) {
|
if (clickedElement === null) {
|
||||||
console.log('handleClick STARTEDEDITING');
|
destroyInput(editingRow.value, editingField.value);
|
||||||
const column = $props.columns.find((col) => col.name === colField);
|
return;
|
||||||
console.log('isEditableColumn(column): ', isEditableColumn(column));
|
|
||||||
if (!isEditableColumn(column)) return;
|
|
||||||
await startEditing(Number(rowIndex), colField, clickedElement);
|
|
||||||
if (column.component !== 'checkbox') console.log();
|
|
||||||
}
|
}
|
||||||
|
const rowIndex = clickedElement.getAttribute('data-row-index');
|
||||||
|
const colField = clickedElement.getAttribute('data-col-field');
|
||||||
|
const column = $props.columns.find((col) => col.name === colField);
|
||||||
|
|
||||||
|
if (editingRow.value != null && editingField.value != null) {
|
||||||
|
if (editingRow.value == rowIndex && editingField.value == colField) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
destroyInput(editingRow.value, editingField.value);
|
||||||
|
if (isEditableColumn(column))
|
||||||
|
await renderInput(Number(rowIndex), colField, clickedElement);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isEditableColumn(column))
|
||||||
|
await renderInput(Number(rowIndex), colField, clickedElement);
|
||||||
};
|
};
|
||||||
|
|
||||||
async function startEditing(rowId, field, clickedElement) {
|
async function handleTabKey(event, rowIndex, colField) {
|
||||||
console.log('startEditing: ', field);
|
if (editingRow.value == rowIndex && editingField.value == colField)
|
||||||
if (rowId === editingRow.value && field === editingField.value) return;
|
destroyInput(editingRow.value, editingField.value);
|
||||||
editingRow.value = rowId;
|
|
||||||
|
const direction = event.shiftKey ? -1 : 1;
|
||||||
|
const { nextRowIndex, nextColumnName } = await handleTabNavigation(
|
||||||
|
rowIndex,
|
||||||
|
colField,
|
||||||
|
direction,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (nextRowIndex < 0 || nextRowIndex >= arrayData.store.data.length) return;
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
await renderInput(nextRowIndex, nextColumnName, null);
|
||||||
|
}
|
||||||
|
const selectRegex = /select/;
|
||||||
|
async function renderInput(rowId, field, clickedElement) {
|
||||||
editingField.value = field;
|
editingField.value = field;
|
||||||
|
editingRow.value = rowId;
|
||||||
|
|
||||||
const column = $props.columns.find((col) => col.name === field);
|
const column = $props.columns.find((col) => col.name === field);
|
||||||
console.log('LaVerdaderacolumn: ', column);
|
|
||||||
const row = CrudModelRef.value.formData[rowId];
|
const row = CrudModelRef.value.formData[rowId];
|
||||||
const oldValue = CrudModelRef.value.formData[rowId][column?.name];
|
const oldValue = CrudModelRef.value.formData[rowId][column?.name];
|
||||||
console.log('changes: ', CrudModelRef.value.getChanges());
|
|
||||||
|
|
||||||
if (!clickedElement)
|
if (!clickedElement)
|
||||||
clickedElement = document.querySelector(
|
clickedElement = document.querySelector(
|
||||||
`[data-row-index="${rowId}"][data-col-field="${field}"]`
|
`[data-row-index="${rowId}"][data-col-field="${field}"]`,
|
||||||
);
|
);
|
||||||
|
|
||||||
Array.from(clickedElement.childNodes).forEach((child) => {
|
Array.from(clickedElement.childNodes).forEach((child) => {
|
||||||
child.style.visibility = 'hidden';
|
child.style.visibility = 'hidden';
|
||||||
child.style.position = 'absolute';
|
child.style.position = 'relative';
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('row[column.name]: ', row[column.name]);
|
const isSelect = selectRegex.test(column?.component);
|
||||||
|
if (isSelect) column.attrs = { ...column.attrs, 'emit-value': false };
|
||||||
|
|
||||||
const node = h(VnColumn, {
|
const node = h(VnColumn, {
|
||||||
row: row,
|
row: row,
|
||||||
|
class: 'temp-input',
|
||||||
column: column,
|
column: column,
|
||||||
modelValue: row[column.name],
|
modelValue: row[column.name],
|
||||||
componentProp: 'columnField',
|
componentProp: 'columnField',
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
focusOnMount: true,
|
focusOnMount: true,
|
||||||
eventHandlers: {
|
eventHandlers: {
|
||||||
'update:modelValue': (value) => {
|
'update:modelValue': async (value) => {
|
||||||
console.log('update:modelValue: ', value);
|
if (isSelect) {
|
||||||
row[column.name] = value;
|
row[column.name] = value[column.name.attrs?.optionValue ?? 'id'];
|
||||||
|
row[column?.name + 'textValue'] =
|
||||||
column?.cellEvent?.['update:modelValue']?.(value, oldValue, row);
|
value[column.name.attrs?.optionLabel ?? 'name'];
|
||||||
},
|
await column?.cellEvent?.['update:modelValue']?.(
|
||||||
onMouseDown: (event) => {
|
value,
|
||||||
console.log('mouseDown: ', field);
|
oldValue,
|
||||||
if (column.component === 'checkbox') event.stopPropagation();
|
row,
|
||||||
},
|
);
|
||||||
blur: () => {
|
} else row[column.name] = value;
|
||||||
/* const focusElement = document.activeElement;
|
await column?.cellEvent?.['update:modelValue']?.(value, oldValue, row);
|
||||||
const rowIndex = focusElement.getAttribute('data-row-index');
|
|
||||||
const colField = focusElement.getAttribute('data-col-field');
|
|
||||||
console.log('rowIndex: ', rowIndex);
|
|
||||||
console.log('colField: ', colField);
|
|
||||||
console.log('editingField.value: ', editingField.value);
|
|
||||||
console.log('editingRow.value: ', editingRow.value);
|
|
||||||
|
|
||||||
handleBlur(rowId, field, clickedElement);
|
|
||||||
column?.cellEvent?.blur?.(row); */
|
|
||||||
},
|
},
|
||||||
keyup: async (event) => {
|
keyup: async (event) => {
|
||||||
console.log('keyup: ', field);
|
|
||||||
if (event.key === 'Enter') handleBlur(rowId, field, clickedElement);
|
if (event.key === 'Enter') handleBlur(rowId, field, clickedElement);
|
||||||
},
|
},
|
||||||
keydown: async (event) => {
|
keydown: async (event) => {
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case 'Tab':
|
case 'Tab':
|
||||||
console.log('TabTest: ', field);
|
|
||||||
await handleTabKey(event, rowId, field);
|
await handleTabKey(event, rowId, field);
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
if (column.component === 'checkbox')
|
|
||||||
handleBlur(rowId, field, clickedElement);
|
|
||||||
break;
|
break;
|
||||||
case 'Escape':
|
case 'Escape':
|
||||||
console.log('Escape: ', field);
|
destroyInput(rowId, field, clickedElement);
|
||||||
stopEditing(rowId, field, clickedElement);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
click: (event) => {
|
click: (event) => {
|
||||||
/* event.stopPropagation();
|
column?.cellEvent?.['click']?.(event, row);
|
||||||
console.log('click: ', field);
|
|
||||||
|
|
||||||
if (column.component === 'checkbox') {
|
|
||||||
const allowNull = column?.toggleIndeterminate ?? true;
|
|
||||||
const currentValue = row[column.name];
|
|
||||||
|
|
||||||
let newValue;
|
|
||||||
|
|
||||||
if (allowNull) {
|
|
||||||
if (currentValue === null) {
|
|
||||||
newValue = true;
|
|
||||||
} else if (currentValue) {
|
|
||||||
newValue = false;
|
|
||||||
} else {
|
|
||||||
newValue = null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newValue = !currentValue;
|
|
||||||
}
|
|
||||||
row[column.name] = newValue;
|
|
||||||
|
|
||||||
column?.cellEvent?.['update:modelValue']?.(newValue, row);
|
|
||||||
}
|
|
||||||
column?.cellEvent?.['click']?.(event, row); */
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -463,11 +441,15 @@ async function startEditing(rowId, field, clickedElement) {
|
||||||
node.appContext = app._context;
|
node.appContext = app._context;
|
||||||
render(node, clickedElement);
|
render(node, clickedElement);
|
||||||
|
|
||||||
if (column.component === 'checkbox') node.el?.querySelector('span > div').focus();
|
if (['checkbox', 'toggle', undefined].includes(column?.component))
|
||||||
|
node.el?.querySelector('span > div').focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopEditing(rowIndex, field, clickedElement) {
|
function destroyInput(rowIndex, field, clickedElement) {
|
||||||
console.log('stopEditing: ', field);
|
if (!clickedElement)
|
||||||
|
clickedElement = document.querySelector(
|
||||||
|
`[data-row-index="${rowIndex}"][data-col-field="${field}"]`,
|
||||||
|
);
|
||||||
if (clickedElement) {
|
if (clickedElement) {
|
||||||
render(null, clickedElement);
|
render(null, clickedElement);
|
||||||
Array.from(clickedElement.childNodes).forEach((child) => {
|
Array.from(clickedElement.childNodes).forEach((child) => {
|
||||||
|
@ -481,8 +463,7 @@ function stopEditing(rowIndex, field, clickedElement) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBlur(rowIndex, field, clickedElement) {
|
function handleBlur(rowIndex, field, clickedElement) {
|
||||||
console.log('handleBlur: ', field);
|
destroyInput(rowIndex, field, clickedElement);
|
||||||
stopEditing(rowIndex, field, clickedElement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleTabNavigation(rowIndex, colName, direction) {
|
async function handleTabNavigation(rowIndex, colName, direction) {
|
||||||
|
@ -501,7 +482,6 @@ async function handleTabNavigation(rowIndex, colName, direction) {
|
||||||
} while (iterations < totalColumns);
|
} while (iterations < totalColumns);
|
||||||
|
|
||||||
if (iterations >= totalColumns) {
|
if (iterations >= totalColumns) {
|
||||||
console.warn('No editable columns found.');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,61 +490,37 @@ async function handleTabNavigation(rowIndex, colName, direction) {
|
||||||
} else if (direction === -1 && newColumnIndex >= currentColumnIndex) {
|
} else if (direction === -1 && newColumnIndex >= currentColumnIndex) {
|
||||||
rowIndex--;
|
rowIndex--;
|
||||||
}
|
}
|
||||||
console.log('next: ', columns[newColumnIndex].name, 'rowIndex: ', rowIndex);
|
|
||||||
return { nextRowIndex: rowIndex, nextColumnName: columns[newColumnIndex].name };
|
return { nextRowIndex: rowIndex, nextColumnName: columns[newColumnIndex].name };
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleTabKey(event, rowIndex, colName) {
|
|
||||||
const direction = event.shiftKey ? -1 : 1;
|
|
||||||
const { nextRowIndex, nextColumnName } = await handleTabNavigation(
|
|
||||||
rowIndex,
|
|
||||||
colName,
|
|
||||||
direction
|
|
||||||
);
|
|
||||||
|
|
||||||
if (nextRowIndex < 0 || nextRowIndex >= arrayData.store.data.length) return;
|
|
||||||
|
|
||||||
event.preventDefault();
|
|
||||||
await startEditing(nextRowIndex, nextColumnName, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCheckboxIcon(value) {
|
function getCheckboxIcon(value) {
|
||||||
switch (typeof value) {
|
switch (typeof value) {
|
||||||
case 'boolean':
|
case 'boolean':
|
||||||
return value ? 'check' : 'close';
|
return value ? 'check' : 'close';
|
||||||
case 'string':
|
|
||||||
return value.toLowerCase() === 'partial'
|
|
||||||
? 'indeterminate_check_box'
|
|
||||||
: 'unknown_med';
|
|
||||||
case 'number':
|
case 'number':
|
||||||
return value === 0 ? 'close' : 'check';
|
return value === 0 ? 'close' : 'check';
|
||||||
case 'object':
|
|
||||||
return value === null ? 'help_outline' : 'unknown_med';
|
|
||||||
case 'undefined':
|
case 'undefined':
|
||||||
return 'help_outline';
|
return 'indeterminate_check_box';
|
||||||
default:
|
default:
|
||||||
return 'indeterminate_check_box';
|
return 'indeterminate_check_box';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function getToggleIcon(value) {
|
||||||
|
if (value === null) return 'help_outline';
|
||||||
|
return value ? 'toggle_on' : 'toggle_off';
|
||||||
|
}
|
||||||
|
|
||||||
/* function getCheckboxIcon(value) {
|
function formatColumnValue(col, row, dashIfEmpty) {
|
||||||
switch (typeof value) {
|
if (col?.format) {
|
||||||
case 'boolean':
|
if (selectRegex.test(col?.component) && row[col?.name + 'textValue']) {
|
||||||
return value ? 'check_box' : 'check_box_outline_blank';
|
return dashIfEmpty(row[col?.name + 'textValue']);
|
||||||
case 'string':
|
} else {
|
||||||
return value.toLowerCase() === 'partial'
|
return col.format(row, dashIfEmpty);
|
||||||
? 'indeterminate_check_box'
|
|
||||||
: 'unknown_med';
|
|
||||||
case 'number':
|
|
||||||
return value === 0 ? 'check_box_outline_blank' : 'check_box';
|
|
||||||
case 'object':
|
|
||||||
return value === null ? 'help_outline' : 'unknown_med';
|
|
||||||
case 'undefined':
|
|
||||||
return 'help_outline';
|
|
||||||
default:
|
|
||||||
return 'indeterminate_check_box';
|
|
||||||
}
|
}
|
||||||
} */
|
} else {
|
||||||
|
return dashIfEmpty(row[col?.name]);
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<QDrawer
|
<QDrawer
|
||||||
|
@ -628,7 +584,6 @@ function getCheckboxIcon(value) {
|
||||||
@row-click="(_, row) => rowClickFunction && rowClickFunction(row)"
|
@row-click="(_, row) => rowClickFunction && rowClickFunction(row)"
|
||||||
@update:selected="emit('update:selected', $event)"
|
@update:selected="emit('update:selected', $event)"
|
||||||
@selection="(details) => handleSelection(details, rows)"
|
@selection="(details) => handleSelection(details, rows)"
|
||||||
v-on="isEditable ? { click: handleClick } : {}"
|
|
||||||
>
|
>
|
||||||
<template #top-left v-if="!$props.withoutHeader">
|
<template #top-left v-if="!$props.withoutHeader">
|
||||||
<slot name="top-left"> </slot>
|
<slot name="top-left"> </slot>
|
||||||
|
@ -647,6 +602,14 @@ function getCheckboxIcon(value) {
|
||||||
dense
|
dense
|
||||||
:options="tableModes.filter((mode) => !mode.disable)"
|
:options="tableModes.filter((mode) => !mode.disable)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<QBtn
|
||||||
|
v-if="showRightIcon"
|
||||||
|
icon="filter_alt"
|
||||||
|
class="bg-vn-section-color q-ml-sm"
|
||||||
|
dense
|
||||||
|
@click="stateStore.toggleRightDrawer()"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #header-cell="{ col }">
|
<template #header-cell="{ col }">
|
||||||
<QTh
|
<QTh
|
||||||
|
@ -665,7 +628,7 @@ function getCheckboxIcon(value) {
|
||||||
<VnTableOrder
|
<VnTableOrder
|
||||||
v-model="orders[col.orderBy ?? col.name]"
|
v-model="orders[col.orderBy ?? col.name]"
|
||||||
:name="col.orderBy ?? col.name"
|
:name="col.orderBy ?? col.name"
|
||||||
:label="col?.label"
|
:label="col?.labelAbbreviation ?? col?.label"
|
||||||
:data-key="$attrs['data-key']"
|
:data-key="$attrs['data-key']"
|
||||||
:search-url="searchUrl"
|
:search-url="searchUrl"
|
||||||
/>
|
/>
|
||||||
|
@ -707,15 +670,14 @@ function getCheckboxIcon(value) {
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
}"
|
}"
|
||||||
:class="[
|
:class="[
|
||||||
getColAlign(col),
|
|
||||||
col.columnClass,
|
col.columnClass,
|
||||||
'body-cell no-margin no-padding',
|
'body-cell no-margin no-padding text-center',
|
||||||
]"
|
]"
|
||||||
:data-row-index="rowIndex"
|
:data-row-index="rowIndex"
|
||||||
:data-col-field="col?.name"
|
:data-col-field="col?.name"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="no-padding no-margin"
|
class="no-padding no-margin peter"
|
||||||
style="
|
style="
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
@ -729,7 +691,18 @@ function getCheckboxIcon(value) {
|
||||||
:row-index="rowIndex"
|
:row-index="rowIndex"
|
||||||
>
|
>
|
||||||
<QIcon
|
<QIcon
|
||||||
v-if="col?.component === 'checkbox'"
|
v-if="col?.component === 'toggle'"
|
||||||
|
:name="
|
||||||
|
col?.getIcon
|
||||||
|
? col.getIcon(row[col?.name])
|
||||||
|
: getToggleIcon(row[col?.name])
|
||||||
|
"
|
||||||
|
style="color: var(--vn-text-color)"
|
||||||
|
:class="hasEditableFormat(col)"
|
||||||
|
size="17px"
|
||||||
|
/>
|
||||||
|
<QIcon
|
||||||
|
v-else-if="col?.component === 'checkbox'"
|
||||||
:name="getCheckboxIcon(row[col?.name])"
|
:name="getCheckboxIcon(row[col?.name])"
|
||||||
style="color: var(--vn-text-color)"
|
style="color: var(--vn-text-color)"
|
||||||
:class="hasEditableFormat(col)"
|
:class="hasEditableFormat(col)"
|
||||||
|
@ -741,11 +714,7 @@ function getCheckboxIcon(value) {
|
||||||
:style="col?.style ? col.style(row) : null"
|
:style="col?.style ? col.style(row) : null"
|
||||||
style="bottom: 0"
|
style="bottom: 0"
|
||||||
>
|
>
|
||||||
{{
|
{{ formatColumnValue(col, row, dashIfEmpty) }}
|
||||||
col?.format
|
|
||||||
? col.format(row, dashIfEmpty)
|
|
||||||
: dashIfEmpty(row[col?.name])
|
|
||||||
}}
|
|
||||||
</span>
|
</span>
|
||||||
</slot>
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
|
@ -898,7 +867,6 @@ function getCheckboxIcon(value) {
|
||||||
v-for="col of cols.filter((cols) => cols.visible ?? true)"
|
v-for="col of cols.filter((cols) => cols.visible ?? true)"
|
||||||
:key="col?.id"
|
:key="col?.id"
|
||||||
class="text-center"
|
class="text-center"
|
||||||
:class="getColAlign(col)"
|
|
||||||
>
|
>
|
||||||
<slot :name="`column-footer-${col.name}`" />
|
<slot :name="`column-footer-${col.name}`" />
|
||||||
</QTh>
|
</QTh>
|
||||||
|
@ -944,14 +912,32 @@ function getCheckboxIcon(value) {
|
||||||
{{ createForm?.title }}
|
{{ createForm?.title }}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
</QPageSticky>
|
</QPageSticky>
|
||||||
<QDialog v-model="showForm" transition-show="scale" transition-hide="scale">
|
<QDialog
|
||||||
|
v-model="showForm"
|
||||||
|
transition-show="scale"
|
||||||
|
transition-hide="scale"
|
||||||
|
:full-width="create?.isFullWidth ?? false"
|
||||||
|
@before-hide="
|
||||||
|
() => {
|
||||||
|
if (createRef.isSaveAndContinue) {
|
||||||
|
showForm = true;
|
||||||
|
createForm.formInitialData = { ...create.formInitialData };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
<FormModelPopup
|
<FormModelPopup
|
||||||
|
ref="createRef"
|
||||||
v-bind="createForm"
|
v-bind="createForm"
|
||||||
:model="$attrs['data-key'] + 'Create'"
|
:model="$attrs['data-key'] + 'Create'"
|
||||||
@on-data-saved="(_, res) => createForm.onDataSaved(res)"
|
@on-data-saved="(_, res) => createForm.onDataSaved(res)"
|
||||||
>
|
>
|
||||||
<template #form-inputs="{ data }">
|
<template #form-inputs="{ data }">
|
||||||
<div class="grid-create">
|
<div :class="create?.containerClass">
|
||||||
|
<div>
|
||||||
|
<slot name="previous-create-dialog" :data="data" />
|
||||||
|
</div>
|
||||||
|
<div class="grid-create" :style="create?.columnGridStyle">
|
||||||
<slot
|
<slot
|
||||||
v-for="column of splittedColumns.create"
|
v-for="column of splittedColumns.create"
|
||||||
:key="column.name"
|
:key="column.name"
|
||||||
|
@ -969,8 +955,11 @@ function getCheckboxIcon(value) {
|
||||||
component-prop="columnCreate"
|
component-prop="columnCreate"
|
||||||
/>
|
/>
|
||||||
</slot>
|
</slot>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<slot name="more-create-dialog" :data="data" />
|
<slot name="more-create-dialog" :data="data" />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</FormModelPopup>
|
</FormModelPopup>
|
||||||
</QDialog>
|
</QDialog>
|
||||||
|
@ -1021,6 +1010,7 @@ es:
|
||||||
.body-cell {
|
.body-cell {
|
||||||
padding-left: 2px !important;
|
padding-left: 2px !important;
|
||||||
padding-right: 2px !important;
|
padding-right: 2px !important;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
.bg-chip-secondary {
|
.bg-chip-secondary {
|
||||||
background-color: var(--vn-page-color);
|
background-color: var(--vn-page-color);
|
||||||
|
@ -1047,11 +1037,14 @@ es:
|
||||||
.grid-create {
|
.grid-create {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(150px, max-content));
|
grid-template-columns: repeat(auto-fit, minmax(150px, max-content));
|
||||||
max-width: 100%;
|
|
||||||
grid-gap: 20px;
|
grid-gap: 20px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
.form-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px; /* Espacio entre los divs */
|
||||||
|
}
|
||||||
.flex-one {
|
.flex-one {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: row wrap;
|
flex-flow: row wrap;
|
||||||
|
@ -1162,4 +1155,11 @@ es:
|
||||||
.q-table__middle.q-virtual-scroll.q-virtual-scroll--vertical.scroll {
|
.q-table__middle.q-virtual-scroll.q-virtual-scroll--vertical.scroll {
|
||||||
background-color: var(--vn-section-color);
|
background-color: var(--vn-section-color);
|
||||||
}
|
}
|
||||||
|
.temp-input {
|
||||||
|
top: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -29,10 +29,11 @@ function columnName(col) {
|
||||||
<VnFilterPanel v-bind="$attrs" :search-button="true" :disable-submit-event="true">
|
<VnFilterPanel v-bind="$attrs" :search-button="true" :disable-submit-event="true">
|
||||||
<template #body="{ params, orders }">
|
<template #body="{ params, orders }">
|
||||||
<div
|
<div
|
||||||
class="row no-wrap flex-center"
|
class="container"
|
||||||
v-for="col of columns.filter((c) => c.columnFilter ?? true)"
|
v-for="col of columns.filter((c) => c.columnFilter ?? true)"
|
||||||
:key="col.id"
|
:key="col.id"
|
||||||
>
|
>
|
||||||
|
<div class="filter">
|
||||||
<VnFilter
|
<VnFilter
|
||||||
ref="tableFilterRef"
|
ref="tableFilterRef"
|
||||||
:column="col"
|
:column="col"
|
||||||
|
@ -40,6 +41,8 @@ function columnName(col) {
|
||||||
v-model="params[columnName(col)]"
|
v-model="params[columnName(col)]"
|
||||||
:search-url="searchUrl"
|
:search-url="searchUrl"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="order">
|
||||||
<VnTableOrder
|
<VnTableOrder
|
||||||
v-if="col?.columnFilter !== false && col?.name !== 'tableActions'"
|
v-if="col?.columnFilter !== false && col?.name !== 'tableActions'"
|
||||||
v-model="orders[col.orderBy ?? col.name]"
|
v-model="orders[col.orderBy ?? col.name]"
|
||||||
|
@ -49,6 +52,7 @@ function columnName(col) {
|
||||||
:vertical="true"
|
:vertical="true"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<slot
|
<slot
|
||||||
name="moreFilterPanel"
|
name="moreFilterPanel"
|
||||||
:params="params"
|
:params="params"
|
||||||
|
@ -67,3 +71,21 @@ function columnName(col) {
|
||||||
</template>
|
</template>
|
||||||
</VnFilterPanel>
|
</VnFilterPanel>
|
||||||
</template>
|
</template>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 45px;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter {
|
||||||
|
width: 70%;
|
||||||
|
height: 40px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.order {
|
||||||
|
width: 10%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -58,7 +58,6 @@ function toValueAttrs(attrs) {
|
||||||
v-on="mix(toComponent).event ?? {}"
|
v-on="mix(toComponent).event ?? {}"
|
||||||
v-model="model"
|
v-model="model"
|
||||||
@blur="emit('blur')"
|
@blur="emit('blur')"
|
||||||
@mouse-down="() => console.log('mouse-down')"
|
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -140,7 +140,7 @@ const handleUppercase = () => {
|
||||||
hide-bottom-space
|
hide-bottom-space
|
||||||
:data-cy="$attrs.dataCy ?? $attrs.label + '_input'"
|
:data-cy="$attrs.dataCy ?? $attrs.label + '_input'"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend v-if="$slots.prepend">
|
||||||
<slot name="prepend" />
|
<slot name="prepend" />
|
||||||
</template>
|
</template>
|
||||||
<template #append>
|
<template #append>
|
||||||
|
@ -169,7 +169,7 @@ const handleUppercase = () => {
|
||||||
<QIcon
|
<QIcon
|
||||||
name="match_case"
|
name="match_case"
|
||||||
size="xs"
|
size="xs"
|
||||||
v-if="!$attrs.disabled && !($attrs.readonly) && $props.uppercase"
|
v-if="!$attrs.disabled && !$attrs.readonly && $props.uppercase"
|
||||||
@click="handleUppercase"
|
@click="handleUppercase"
|
||||||
class="uppercase-icon"
|
class="uppercase-icon"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -171,7 +171,8 @@ onMounted(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const arrayDataKey =
|
const arrayDataKey =
|
||||||
$props.dataKey ?? ($props.url?.length > 0 ? $props.url : $attrs.name ?? $attrs.label);
|
$props.dataKey ??
|
||||||
|
($props.url?.length > 0 ? $props.url : ($attrs.name ?? $attrs.label));
|
||||||
|
|
||||||
const arrayData = useArrayData(arrayDataKey, {
|
const arrayData = useArrayData(arrayDataKey, {
|
||||||
url: $props.url,
|
url: $props.url,
|
||||||
|
@ -220,7 +221,7 @@ async function fetchFilter(val) {
|
||||||
optionFilterValue.value ??
|
optionFilterValue.value ??
|
||||||
(new RegExp(/\d/g).test(val)
|
(new RegExp(/\d/g).test(val)
|
||||||
? optionValue.value
|
? optionValue.value
|
||||||
: optionFilter.value ?? optionLabel.value);
|
: (optionFilter.value ?? optionLabel.value));
|
||||||
|
|
||||||
let defaultWhere = {};
|
let defaultWhere = {};
|
||||||
if ($props.filterOptions.length) {
|
if ($props.filterOptions.length) {
|
||||||
|
@ -239,7 +240,7 @@ async function fetchFilter(val) {
|
||||||
|
|
||||||
const { data } = await arrayData.applyFilter(
|
const { data } = await arrayData.applyFilter(
|
||||||
{ filter: filterOptions },
|
{ filter: filterOptions },
|
||||||
{ updateRouter: false }
|
{ updateRouter: false },
|
||||||
);
|
);
|
||||||
setOptions(data);
|
setOptions(data);
|
||||||
return data;
|
return data;
|
||||||
|
@ -272,7 +273,7 @@ async function filterHandler(val, update) {
|
||||||
ref.setOptionIndex(-1);
|
ref.setOptionIndex(-1);
|
||||||
ref.moveOptionSelection(1, true);
|
ref.moveOptionSelection(1, true);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +309,7 @@ function handleKeyDown(event) {
|
||||||
if (inputValue) {
|
if (inputValue) {
|
||||||
const matchingOption = myOptions.value.find(
|
const matchingOption = myOptions.value.find(
|
||||||
(option) =>
|
(option) =>
|
||||||
option[optionLabel.value].toLowerCase() === inputValue.toLowerCase()
|
option[optionLabel.value].toLowerCase() === inputValue.toLowerCase(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (matchingOption) {
|
if (matchingOption) {
|
||||||
|
@ -320,11 +321,11 @@ function handleKeyDown(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const focusableElements = document.querySelectorAll(
|
const focusableElements = document.querySelectorAll(
|
||||||
'a:not([disabled]), button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), details:not([disabled]), [tabindex]:not([tabindex="-1"]):not([disabled])'
|
'a:not([disabled]), button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), details:not([disabled]), [tabindex]:not([tabindex="-1"]):not([disabled])',
|
||||||
);
|
);
|
||||||
const currentIndex = Array.prototype.indexOf.call(
|
const currentIndex = Array.prototype.indexOf.call(
|
||||||
focusableElements,
|
focusableElements,
|
||||||
event.target
|
event.target,
|
||||||
);
|
);
|
||||||
if (currentIndex >= 0 && currentIndex < focusableElements.length - 1) {
|
if (currentIndex >= 0 && currentIndex < focusableElements.length - 1) {
|
||||||
focusableElements[currentIndex + 1].focus();
|
focusableElements[currentIndex + 1].focus();
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
<script setup>
|
||||||
|
import VnSelectDialog from './VnSelectDialog.vue';
|
||||||
|
import FilterTravelForm from 'src/components/FilterTravelForm.vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { toDate } from 'src/filters';
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const $props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
onFilterTravelSelected: {
|
||||||
|
type: Function,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<VnSelectDialog
|
||||||
|
:label="t('entry.basicData.travel')"
|
||||||
|
v-bind="$attrs"
|
||||||
|
url="Travels/filter"
|
||||||
|
:fields="['id', 'warehouseInName']"
|
||||||
|
option-value="id"
|
||||||
|
option-label="warehouseInName"
|
||||||
|
map-options
|
||||||
|
hide-selected
|
||||||
|
:required="true"
|
||||||
|
action-icon="filter_alt"
|
||||||
|
>
|
||||||
|
<template #form>
|
||||||
|
<FilterTravelForm @travel-selected="onFilterTravelSelected(data, $event)" />
|
||||||
|
</template>
|
||||||
|
<template #option="scope">
|
||||||
|
<QItem v-bind="scope.itemProps">
|
||||||
|
<QItemSection>
|
||||||
|
<QItemLabel>
|
||||||
|
{{ scope.opt?.agencyModeName }} -
|
||||||
|
{{ scope.opt?.warehouseInName }}
|
||||||
|
({{ toDate(scope.opt?.shipped) }}) →
|
||||||
|
{{ scope.opt?.warehouseOutName }}
|
||||||
|
({{ toDate(scope.opt?.landed) }})
|
||||||
|
</QItemLabel>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template>
|
||||||
|
</VnSelectDialog>
|
||||||
|
</template>
|
|
@ -114,7 +114,7 @@ async function clearFilters() {
|
||||||
arrayData.resetPagination();
|
arrayData.resetPagination();
|
||||||
// Filtrar los params no removibles
|
// Filtrar los params no removibles
|
||||||
const removableFilters = Object.keys(userParams.value).filter((param) =>
|
const removableFilters = Object.keys(userParams.value).filter((param) =>
|
||||||
$props.unremovableParams.includes(param)
|
$props.unremovableParams.includes(param),
|
||||||
);
|
);
|
||||||
const newParams = {};
|
const newParams = {};
|
||||||
// Conservar solo los params que no son removibles
|
// Conservar solo los params que no son removibles
|
||||||
|
@ -162,13 +162,13 @@ const formatTags = (tags) => {
|
||||||
|
|
||||||
const tags = computed(() => {
|
const tags = computed(() => {
|
||||||
const filteredTags = tagsList.value.filter(
|
const filteredTags = tagsList.value.filter(
|
||||||
(tag) => !($props.customTags || []).includes(tag.label)
|
(tag) => !($props.customTags || []).includes(tag.label),
|
||||||
);
|
);
|
||||||
return formatTags(filteredTags);
|
return formatTags(filteredTags);
|
||||||
});
|
});
|
||||||
|
|
||||||
const customTags = computed(() =>
|
const customTags = computed(() =>
|
||||||
tagsList.value.filter((tag) => ($props.customTags || []).includes(tag.label))
|
tagsList.value.filter((tag) => ($props.customTags || []).includes(tag.label)),
|
||||||
);
|
);
|
||||||
|
|
||||||
async function remove(key) {
|
async function remove(key) {
|
||||||
|
@ -191,7 +191,9 @@ const getLocale = (label) => {
|
||||||
if (te(globalLocale)) return t(globalLocale);
|
if (te(globalLocale)) return t(globalLocale);
|
||||||
else if (te(t(`params.${param}`)));
|
else if (te(t(`params.${param}`)));
|
||||||
else {
|
else {
|
||||||
const camelCaseModuleName = route.meta.moduleName.charAt(0).toLowerCase() + route.meta.moduleName.slice(1);
|
const camelCaseModuleName =
|
||||||
|
route.meta.moduleName.charAt(0).toLowerCase() +
|
||||||
|
route.meta.moduleName.slice(1);
|
||||||
return t(`${camelCaseModuleName}.params.${param}`);
|
return t(`${camelCaseModuleName}.params.${param}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -290,6 +292,9 @@ const getLocale = (label) => {
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
.q-field__label.no-pointer-events.absolute.ellipsis {
|
||||||
|
margin-left: 6px !important;
|
||||||
|
}
|
||||||
.list {
|
.list {
|
||||||
width: 256px;
|
width: 256px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
import { useQuasar } from 'quasar';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import axios from 'axios';
|
||||||
|
import VnConfirm from 'components/ui/VnConfirm.vue';
|
||||||
|
|
||||||
|
export async function checkEntryLock(entryFk, userFk) {
|
||||||
|
const { t } = useI18n();
|
||||||
|
const quasar = useQuasar();
|
||||||
|
const { push } = useRouter();
|
||||||
|
const { data } = await axios.get(`Entries/${entryFk}`, {
|
||||||
|
params: {
|
||||||
|
filter: JSON.stringify({
|
||||||
|
fields: ['id', 'locked', 'lockerUserFk'],
|
||||||
|
include: { relation: 'user', scope: { fields: ['id', 'nickname'] } },
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const entryConfig = await axios.get('EntryConfigs/findOne');
|
||||||
|
|
||||||
|
if (data?.lockerUserFk && data?.locked) {
|
||||||
|
const now = new Date().getTime();
|
||||||
|
const lockedTime = new Date(data.locked).getTime();
|
||||||
|
const timeDiff = (now - lockedTime) / 1000;
|
||||||
|
const isMaxTimeLockExceeded = entryConfig.data.maxLockTime > timeDiff;
|
||||||
|
if (data?.lockerUserFk !== userFk && isMaxTimeLockExceeded) {
|
||||||
|
quasar
|
||||||
|
.dialog({
|
||||||
|
component: VnConfirm,
|
||||||
|
componentProps: {
|
||||||
|
title: t('entry.lock.title'),
|
||||||
|
message: t('entry.lock.message', {
|
||||||
|
userName: data?.user?.nickname,
|
||||||
|
time: timeDiff / 60,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.onOk(
|
||||||
|
async () =>
|
||||||
|
await axios.patch(`Entries/${entryFk}`, {
|
||||||
|
locked: Date.vnNow(),
|
||||||
|
lockerUserFk: userFk,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.onCancel(() => push({ path: `summary` }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
export function getColAlign(col) {
|
||||||
|
let align;
|
||||||
|
|
||||||
|
switch (col.component) {
|
||||||
|
case 'number':
|
||||||
|
align = 'right';
|
||||||
|
break;
|
||||||
|
case 'date':
|
||||||
|
case 'checkbox':
|
||||||
|
align = 'center';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
align = col?.align;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/^is[A-Z]/.test(col.name) || /^has[A-Z]/.test(col.name)) align = 'center';
|
||||||
|
|
||||||
|
return 'text-' + (align ?? 'center');
|
||||||
|
}
|
|
@ -315,9 +315,6 @@ input::-webkit-inner-spin-button {
|
||||||
max-width: fit-content;
|
max-width: fit-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
.row > .column:has(.q-checkbox) {
|
|
||||||
max-width: fit-content;
|
|
||||||
}
|
|
||||||
.q-field__inner {
|
.q-field__inner {
|
||||||
.q-field__control {
|
.q-field__control {
|
||||||
min-height: auto !important;
|
min-height: auto !important;
|
||||||
|
|
|
@ -33,6 +33,7 @@ globals:
|
||||||
reset: Reset
|
reset: Reset
|
||||||
close: Close
|
close: Close
|
||||||
cancel: Cancel
|
cancel: Cancel
|
||||||
|
isSaveAndContinue: Save and continue
|
||||||
clone: Clone
|
clone: Clone
|
||||||
confirm: Confirm
|
confirm: Confirm
|
||||||
assign: Assign
|
assign: Assign
|
||||||
|
@ -476,6 +477,27 @@ entry:
|
||||||
isRaid: Raid
|
isRaid: Raid
|
||||||
invoiceNumber: Invoice
|
invoiceNumber: Invoice
|
||||||
reference: Ref/Alb/Guide
|
reference: Ref/Alb/Guide
|
||||||
|
params:
|
||||||
|
isExcludedFromAvailable: Excluir del inventario
|
||||||
|
isOrdered: Pedida
|
||||||
|
isConfirmed: Lista para etiquetar
|
||||||
|
isReceived: Recibida
|
||||||
|
isRaid: Redada
|
||||||
|
landed: Fecha
|
||||||
|
supplierFk: Proveedor
|
||||||
|
invoiceNumber: Nº Factura
|
||||||
|
reference: Ref/Alb/Guía
|
||||||
|
agencyModeId: Agencia
|
||||||
|
isBooked: Asentado
|
||||||
|
companyFk: Empresa
|
||||||
|
travelFk: Envio
|
||||||
|
evaNotes: Notas
|
||||||
|
warehouseOutFk: Origen
|
||||||
|
warehouseInFk: Destino
|
||||||
|
entryTypeDescription: Tipo entrada
|
||||||
|
invoiceAmount: Importe
|
||||||
|
dated: Fecha
|
||||||
|
|
||||||
ticket:
|
ticket:
|
||||||
params:
|
params:
|
||||||
ticketFk: Ticket ID
|
ticketFk: Ticket ID
|
||||||
|
|
|
@ -33,6 +33,7 @@ globals:
|
||||||
reset: Restaurar
|
reset: Restaurar
|
||||||
close: Cerrar
|
close: Cerrar
|
||||||
cancel: Cancelar
|
cancel: Cancelar
|
||||||
|
isSaveAndContinue: Guardar y continuar
|
||||||
clone: Clonar
|
clone: Clonar
|
||||||
confirm: Confirmar
|
confirm: Confirmar
|
||||||
assign: Asignar
|
assign: Asignar
|
||||||
|
|
|
@ -1,30 +1,31 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRole } from 'src/composables/useRole';
|
import { useRole } from 'src/composables/useRole';
|
||||||
|
import { useState } from 'src/composables/useState';
|
||||||
|
import { checkEntryLock } from 'src/composables/checkEntryLock';
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import FormModel from 'components/FormModel.vue';
|
import FormModel from 'components/FormModel.vue';
|
||||||
import VnRow from 'components/ui/VnRow.vue';
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
import VnInput from 'src/components/common/VnInput.vue';
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
||||||
import VnSelectDialog from 'src/components/common/VnSelectDialog.vue';
|
import VnSelectTravelExtended from 'src/components/common/VnSelectTravelExtended.vue';
|
||||||
import FilterTravelForm from 'src/components/FilterTravelForm.vue';
|
|
||||||
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
|
||||||
import { toDate } from 'src/filters';
|
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { hasAny } = useRole();
|
const { hasAny } = useRole();
|
||||||
const isAdministrative = () => hasAny(['administrative']);
|
const isAdministrative = () => hasAny(['administrative']);
|
||||||
|
const state = useState();
|
||||||
|
const user = state.getUser().fn();
|
||||||
|
|
||||||
const companiesOptions = ref([]);
|
const companiesOptions = ref([]);
|
||||||
const currenciesOptions = ref([]);
|
const currenciesOptions = ref([]);
|
||||||
|
|
||||||
const onFilterTravelSelected = (formData, id) => {
|
onMounted(() => {
|
||||||
formData.travelFk = id;
|
checkEntryLock(route.params.id, user.id);
|
||||||
};
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -52,37 +53,11 @@ const onFilterTravelSelected = (formData, id) => {
|
||||||
>
|
>
|
||||||
<template #form="{ data }">
|
<template #form="{ data }">
|
||||||
<VnRow>
|
<VnRow>
|
||||||
<VnSelectDialog
|
<VnSelectTravelExtended
|
||||||
:label="t('entry.basicData.travel')"
|
:data="data"
|
||||||
v-model="data.travelFk"
|
v-model="data.travelFk"
|
||||||
url="Travels/filter"
|
:onFilterTravelSelected="(data, result) => (data.travelFk = result)"
|
||||||
:fields="['id', 'warehouseInName']"
|
|
||||||
option-value="id"
|
|
||||||
option-label="warehouseInName"
|
|
||||||
map-options
|
|
||||||
hide-selected
|
|
||||||
:required="true"
|
|
||||||
action-icon="filter_alt"
|
|
||||||
>
|
|
||||||
<template #form>
|
|
||||||
<FilterTravelForm
|
|
||||||
@travel-selected="onFilterTravelSelected(data, $event)"
|
|
||||||
/>
|
/>
|
||||||
</template>
|
|
||||||
<template #option="scope">
|
|
||||||
<QItem v-bind="scope.itemProps">
|
|
||||||
<QItemSection>
|
|
||||||
<QItemLabel>
|
|
||||||
{{ scope.opt?.agencyModeName }} -
|
|
||||||
{{ scope.opt?.warehouseInName }}
|
|
||||||
({{ toDate(scope.opt?.shipped) }}) →
|
|
||||||
{{ scope.opt?.warehouseOutName }}
|
|
||||||
({{ toDate(scope.opt?.landed) }})
|
|
||||||
</QItemLabel>
|
|
||||||
</QItemSection>
|
|
||||||
</QItem>
|
|
||||||
</template>
|
|
||||||
</VnSelectDialog>
|
|
||||||
<VnSelect
|
<VnSelect
|
||||||
:label="t('globals.supplier')"
|
:label="t('globals.supplier')"
|
||||||
v-model="data.supplierFk"
|
v-model="data.supplierFk"
|
||||||
|
|
|
@ -2,14 +2,21 @@
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { h, onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
|
import { useState } from 'src/composables/useState';
|
||||||
|
|
||||||
import FetchData from 'src/components/FetchData.vue';
|
import FetchData from 'src/components/FetchData.vue';
|
||||||
import VnTable from 'src/components/VnTable/VnTable.vue';
|
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||||
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
|
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
|
||||||
import FetchedTags from 'src/components/ui/FetchedTags.vue';
|
import FetchedTags from 'src/components/ui/FetchedTags.vue';
|
||||||
import VnColor from 'src/components/common/VnColor.vue';
|
import VnColor from 'src/components/common/VnColor.vue';
|
||||||
import { QCheckbox } from 'quasar';
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
|
import ItemDescriptor from 'src/pages/Item/Card/ItemDescriptor.vue';
|
||||||
|
import axios from 'axios';
|
||||||
|
import VnSelectEnum from 'src/components/common/VnSelectEnum.vue';
|
||||||
|
import { checkEntryLock } from 'src/composables/checkEntryLock';
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
id: {
|
id: {
|
||||||
type: Number,
|
type: Number,
|
||||||
|
@ -21,28 +28,67 @@ const $props = defineProps({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { t } = useI18n();
|
const state = useState();
|
||||||
|
const user = state.getUser().fn();
|
||||||
const stateStore = useStateStore();
|
const stateStore = useStateStore();
|
||||||
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const selectedRows = ref([]);
|
const selectedRows = ref([]);
|
||||||
const entityId = ref($props.id ?? route.params.id);
|
const entityId = ref($props.id ?? route.params.id);
|
||||||
console.log('entityId: ', entityId.value);
|
const entryBuysRef = ref();
|
||||||
|
const footerFetchDataRef = ref();
|
||||||
const footer = ref({});
|
const footer = ref({});
|
||||||
const columns = [
|
const columns = [
|
||||||
|
{
|
||||||
|
align: 'center',
|
||||||
|
labelAbbreviation: 'NV',
|
||||||
|
label: t('Ignore'),
|
||||||
|
toolTip: t('Ignored for available'),
|
||||||
|
name: 'isIgnored',
|
||||||
|
component: 'checkbox',
|
||||||
|
toggleIndeterminate: false,
|
||||||
|
create: true,
|
||||||
|
width: '25px',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('Buyer'),
|
||||||
|
name: 'workerFk',
|
||||||
|
component: 'select',
|
||||||
|
attrs: {
|
||||||
|
url: 'Workers/search',
|
||||||
|
fields: ['id', 'nickname'],
|
||||||
|
optionLabel: 'nickname',
|
||||||
|
optionValue: 'id',
|
||||||
|
},
|
||||||
|
visible: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('Family'),
|
||||||
|
name: 'itemTypeFk',
|
||||||
|
component: 'select',
|
||||||
|
attrs: {
|
||||||
|
url: 'itemTypes',
|
||||||
|
fields: ['id', 'name'],
|
||||||
|
optionLabel: 'name',
|
||||||
|
optionValue: 'id',
|
||||||
|
},
|
||||||
|
visible: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'id',
|
name: 'id',
|
||||||
isId: true,
|
isId: true,
|
||||||
visible: false,
|
visible: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
columnFilter: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
name: 'entryFk',
|
||||||
label: 'Nv',
|
isId: true,
|
||||||
name: 'isIgnored',
|
visible: false,
|
||||||
component: 'checkbox',
|
isEditable: false,
|
||||||
toggleIndeterminate: false,
|
disable: true,
|
||||||
width: '35px',
|
create: true,
|
||||||
|
columnFilter: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
@ -50,26 +96,47 @@ const columns = [
|
||||||
name: 'itemFk',
|
name: 'itemFk',
|
||||||
component: 'input',
|
component: 'input',
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
create: true,
|
width: '40px',
|
||||||
width: '45px',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '',
|
labelAbbreviation: '',
|
||||||
|
label: 'Color',
|
||||||
name: 'hex',
|
name: 'hex',
|
||||||
columnSearch: false,
|
columnSearch: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
width: '5px',
|
width: '5px',
|
||||||
|
component: 'select',
|
||||||
|
attrs: {
|
||||||
|
url: 'Inks',
|
||||||
|
fields: ['id', 'name'],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
label: t('Article'),
|
label: t('Article'),
|
||||||
name: 'name',
|
name: 'name',
|
||||||
width: '100px',
|
component: 'select',
|
||||||
|
attrs: {
|
||||||
|
url: 'Items',
|
||||||
|
fields: ['id', 'name'],
|
||||||
|
optionLabel: 'name',
|
||||||
|
optionValue: 'id',
|
||||||
|
},
|
||||||
|
width: '85px',
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
label: t('Siz.'),
|
label: t('Article'),
|
||||||
|
name: 'itemFk',
|
||||||
|
visible: false,
|
||||||
|
create: true,
|
||||||
|
columnFilter: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'center',
|
||||||
|
labelAbbreviation: t('Siz.'),
|
||||||
|
label: t('Size'),
|
||||||
toolTip: t('Size'),
|
toolTip: t('Size'),
|
||||||
name: 'size',
|
name: 'size',
|
||||||
width: '35px',
|
width: '35px',
|
||||||
|
@ -80,15 +147,17 @@ const columns = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
label: t('Sti.'),
|
labelAbbreviation: t('Sti.'),
|
||||||
|
label: t('Printed Stickers/Stickers'),
|
||||||
toolTip: t('Printed Stickers/Stickers'),
|
toolTip: t('Printed Stickers/Stickers'),
|
||||||
name: 'stickers',
|
name: 'stickers',
|
||||||
component: 'number',
|
component: 'number',
|
||||||
|
create: true,
|
||||||
attrs: {
|
attrs: {
|
||||||
positive: false,
|
positive: false,
|
||||||
},
|
},
|
||||||
cellEvent: {
|
cellEvent: {
|
||||||
'update:modelValue': (value, oldValue, row) => {
|
'update:modelValue': async (value, oldValue, row) => {
|
||||||
row['quantity'] = value * row['packing'];
|
row['quantity'] = value * row['packing'];
|
||||||
row['amount'] = row['quantity'] * row['buyingValue'];
|
row['amount'] = row['quantity'] * row['buyingValue'];
|
||||||
},
|
},
|
||||||
|
@ -105,7 +174,8 @@ const columns = [
|
||||||
fields: ['id', 'volume'],
|
fields: ['id', 'volume'],
|
||||||
optionLabel: 'id',
|
optionLabel: 'id',
|
||||||
},
|
},
|
||||||
width: '60px',
|
create: true,
|
||||||
|
width: '40px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
@ -117,12 +187,14 @@ const columns = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
label: 'Pack',
|
labelAbbreviation: 'Pack',
|
||||||
|
label: 'Packing',
|
||||||
|
toolTip: 'Packing',
|
||||||
name: 'packing',
|
name: 'packing',
|
||||||
component: 'number',
|
component: 'number',
|
||||||
|
create: true,
|
||||||
cellEvent: {
|
cellEvent: {
|
||||||
'update:modelValue': (value, oldValue, row) => {
|
'update:modelValue': async (value, oldValue, row) => {
|
||||||
console.log('oldValue: ', oldValue);
|
|
||||||
const oldPacking = oldValue === 1 || oldValue === null ? 1 : oldValue;
|
const oldPacking = oldValue === 1 || oldValue === null ? 1 : oldValue;
|
||||||
row['weight'] = (row['weight'] * value) / oldPacking;
|
row['weight'] = (row['weight'] * value) / oldPacking;
|
||||||
row['quantity'] = row['stickers'] * value;
|
row['quantity'] = row['stickers'] * value;
|
||||||
|
@ -134,42 +206,44 @@ const columns = [
|
||||||
if (row.groupingMode === 'grouping')
|
if (row.groupingMode === 'grouping')
|
||||||
return { color: 'var(--vn-label-color)' };
|
return { color: 'var(--vn-label-color)' };
|
||||||
},
|
},
|
||||||
/* append: {
|
|
||||||
name: 'groupingMode',
|
|
||||||
h: (row) =>
|
|
||||||
h(QCheckbox, {
|
|
||||||
'data-name': 'groupingMode',
|
|
||||||
modelValue: row['groupingMode'] === 'packing',
|
|
||||||
size: 'sm',
|
|
||||||
'onUpdate:modelValue': (value) => {
|
|
||||||
console.log('entra');
|
|
||||||
if (value) row['groupingMode'] = 'packing';
|
|
||||||
else row['groupingMode'] = 'grouping';
|
|
||||||
},
|
|
||||||
onClick: (event) => {
|
|
||||||
console.log('eventOnClick: ', event);
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}, */
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
label: 'Group',
|
labelAbbreviation: 'GM',
|
||||||
|
label: t('Grouping selector'),
|
||||||
|
toolTip: t('Grouping selector'),
|
||||||
name: 'groupingMode',
|
name: 'groupingMode',
|
||||||
component: 'toggle',
|
component: 'toggle',
|
||||||
attrs: {
|
attrs: {
|
||||||
|
'toggle-indeterminate': true,
|
||||||
trueValue: 'grouping',
|
trueValue: 'grouping',
|
||||||
falseValue: 'packing',
|
falseValue: 'packing',
|
||||||
indeterminateValue: null,
|
indeterminateValue: null,
|
||||||
},
|
},
|
||||||
width: '35px',
|
size: 'xs',
|
||||||
|
width: '30px',
|
||||||
|
create: true,
|
||||||
|
rightFilter: false,
|
||||||
|
getIcon: (value) => {
|
||||||
|
switch (value) {
|
||||||
|
case 'grouping':
|
||||||
|
return 'toggle_on';
|
||||||
|
case 'packing':
|
||||||
|
return 'toggle_off';
|
||||||
|
default:
|
||||||
|
return 'minimize';
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
label: 'Group',
|
labelAbbreviation: 'Group',
|
||||||
|
label: 'Grouping',
|
||||||
|
toolTip: 'Grouping',
|
||||||
name: 'grouping',
|
name: 'grouping',
|
||||||
component: 'number',
|
component: 'number',
|
||||||
width: '35px',
|
width: '35px',
|
||||||
|
create: true,
|
||||||
style: (row) => {
|
style: (row) => {
|
||||||
if (row.groupingMode === 'packing') return { color: 'var(--vn-label-color)' };
|
if (row.groupingMode === 'packing') return { color: 'var(--vn-label-color)' };
|
||||||
},
|
},
|
||||||
|
@ -183,34 +257,37 @@ const columns = [
|
||||||
positive: false,
|
positive: false,
|
||||||
},
|
},
|
||||||
cellEvent: {
|
cellEvent: {
|
||||||
'update:modelValue': (value, oldValue, row) => {
|
'update:modelValue': async (value, oldValue, row) => {
|
||||||
row['amount'] = value * row['buyingValue'];
|
row['amount'] = value * row['buyingValue'];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
width: '50px',
|
width: '45px',
|
||||||
|
create: true,
|
||||||
style: getQuantityStyle,
|
style: getQuantityStyle,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
label: t('Cost'),
|
labelAbbreviation: t('Cost'),
|
||||||
|
label: t('Buying value'),
|
||||||
toolTip: t('Buying value'),
|
toolTip: t('Buying value'),
|
||||||
name: 'buyingValue',
|
name: 'buyingValue',
|
||||||
|
create: true,
|
||||||
component: 'number',
|
component: 'number',
|
||||||
attrs: {
|
attrs: {
|
||||||
positive: false,
|
positive: false,
|
||||||
},
|
},
|
||||||
cellEvent: {
|
cellEvent: {
|
||||||
'update:modelValue': (value, oldValue, row) => {
|
'update:modelValue': async (value, oldValue, row) => {
|
||||||
row['amount'] = row['quantity'] * value;
|
row['amount'] = row['quantity'] * value;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
width: '50px',
|
width: '45px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
label: t('Amount'),
|
label: t('Amount'),
|
||||||
name: 'amount',
|
name: 'amount',
|
||||||
width: '50px',
|
width: '45px',
|
||||||
component: 'number',
|
component: 'number',
|
||||||
attrs: {
|
attrs: {
|
||||||
positive: false,
|
positive: false,
|
||||||
|
@ -220,11 +297,13 @@ const columns = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
label: t('Pack.'),
|
labelAbbreviation: t('Pack.'),
|
||||||
|
label: t('Package'),
|
||||||
toolTip: t('Package'),
|
toolTip: t('Package'),
|
||||||
name: 'price2',
|
name: 'price2',
|
||||||
component: 'number',
|
component: 'number',
|
||||||
width: '35px',
|
width: '35px',
|
||||||
|
create: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
@ -232,48 +311,45 @@ const columns = [
|
||||||
name: 'price3',
|
name: 'price3',
|
||||||
component: 'number',
|
component: 'number',
|
||||||
cellEvent: {
|
cellEvent: {
|
||||||
'update:modelValue': (value, row) => {
|
'update:modelValue': async (value, oldValue, row) => {
|
||||||
/*
|
row['price2'] = row['price2'] * (value / oldValue);
|
||||||
Call db.execV("UPDATE vn.item SET " & _
|
|
||||||
"typeFk = # " & _
|
|
||||||
",producerFk = # " & _
|
|
||||||
",minPrice = # " & _
|
|
||||||
",box = # " & _
|
|
||||||
",hasMinPrice = # " & _
|
|
||||||
",comment = # " & _
|
|
||||||
"WHERE id = # " _
|
|
||||||
, Me.tipo_id _
|
|
||||||
, Me.producer_id _
|
|
||||||
, Me.PVP _
|
|
||||||
, Me.caja _
|
|
||||||
, Me.Min _
|
|
||||||
, Nz(Me.reference, 0) _
|
|
||||||
, Me.Id_Article _
|
|
||||||
)
|
|
||||||
Me.Tarifa2 = Me.Tarifa2 * (Me.Tarifa3 / Me.Tarifa3.OldValue)
|
|
||||||
Call actualizar_compra
|
|
||||||
Me.sincro = True
|
|
||||||
*/
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
width: '35px',
|
width: '35px',
|
||||||
|
create: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
label: 'Min.',
|
labelAbbreviation: 'Min.',
|
||||||
|
label: t('Minimum price'),
|
||||||
toolTip: t('Minimum price'),
|
toolTip: t('Minimum price'),
|
||||||
name: 'minPrice',
|
name: 'minPrice',
|
||||||
component: 'number',
|
component: 'number',
|
||||||
isEditable: false,
|
cellEvent: {
|
||||||
|
'update:modelValue': async (value, oldValue, row) => {
|
||||||
|
await axios.patch(`Items/${row['itemFk']}`, {
|
||||||
|
minPrice: value,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
width: '35px',
|
width: '35px',
|
||||||
style: (row) => {
|
style: (row) => {
|
||||||
if (row?.hasMinPrice)
|
if (!row?.hasMinPrice) return { color: 'var(--vn-label-color)' };
|
||||||
return { backgroundColor: 'var(--q-positive)', color: 'black' };
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
label: t('P.Sen'),
|
labelAbbreviation: 'CM',
|
||||||
|
label: t('Check min price'),
|
||||||
|
toolTip: t('Check min price'),
|
||||||
|
name: 'hasMinPrice',
|
||||||
|
component: 'checkbox',
|
||||||
|
width: '25px',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'center',
|
||||||
|
labelAbbreviation: t('P.Sen'),
|
||||||
|
label: t('Packing sent'),
|
||||||
toolTip: t('Packing sent'),
|
toolTip: t('Packing sent'),
|
||||||
name: 'packingOut',
|
name: 'packingOut',
|
||||||
component: 'number',
|
component: 'number',
|
||||||
|
@ -282,16 +358,18 @@ const columns = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
label: t('Com.'),
|
labelAbbreviation: t('Com.'),
|
||||||
|
label: t('Comment'),
|
||||||
toolTip: t('Comment'),
|
toolTip: t('Comment'),
|
||||||
name: 'comment',
|
name: 'comment',
|
||||||
component: 'input',
|
component: 'input',
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
width: '55px',
|
width: '50px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
label: 'Prod.',
|
labelAbbreviation: 'Prod.',
|
||||||
|
label: t('Producer'),
|
||||||
toolTip: t('Producer'),
|
toolTip: t('Producer'),
|
||||||
name: 'subName',
|
name: 'subName',
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
@ -309,7 +387,8 @@ const columns = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
label: 'Comp.',
|
labelAbbreviation: 'Comp.',
|
||||||
|
label: t('Company'),
|
||||||
toolTip: t('Company'),
|
toolTip: t('Company'),
|
||||||
name: 'company_name',
|
name: 'company_name',
|
||||||
component: 'input',
|
component: 'input',
|
||||||
|
@ -327,97 +406,162 @@ function getAmountStyle(row) {
|
||||||
return { color: 'var(--vn-label-color)' };
|
return { color: 'var(--vn-label-color)' };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function beforeSave(data, getChanges) {
|
||||||
|
try {
|
||||||
|
const changes = data.updates;
|
||||||
|
if (!changes) return data;
|
||||||
|
const patchPromises = [];
|
||||||
|
|
||||||
|
for (const change of changes) {
|
||||||
|
let patchData = {};
|
||||||
|
|
||||||
|
if ('hasMinPrice' in change.data) {
|
||||||
|
patchData.hasMinPrice = change.data?.hasMinPrice;
|
||||||
|
delete change.data.hasMinPrice;
|
||||||
|
}
|
||||||
|
if ('minPrice' in change.data) {
|
||||||
|
patchData.minPrice = change.data?.minPrice;
|
||||||
|
delete change.data.minPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(patchData).length > 0) {
|
||||||
|
const promise = axios
|
||||||
|
.get('Buys/findOne', {
|
||||||
|
params: {
|
||||||
|
filter: {
|
||||||
|
fields: ['itemFk'],
|
||||||
|
where: { id: change.where.id },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((buy) => {
|
||||||
|
return axios.patch(`Items/${buy.data.itemFk}`, patchData);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error processing change: ', change, error);
|
||||||
|
});
|
||||||
|
|
||||||
|
patchPromises.push(promise);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(patchPromises);
|
||||||
|
|
||||||
|
data.updates = changes.filter((change) => Object.keys(change.data).length > 0);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in beforeSave:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function invertQuantitySign(rows, sign) {
|
||||||
|
for (const row of rows) {
|
||||||
|
row.quantity = row.quantity * sign;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function setIsChecked(rows, value) {
|
||||||
|
for (const row of rows) {
|
||||||
|
row.isChecked = value;
|
||||||
|
}
|
||||||
|
footerFetchDataRef.value.fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setBuyUltimate(itemFk, data) {
|
||||||
|
if (!itemFk) return;
|
||||||
|
const buyUltimate = await axios.get(`Entries/getBuyUltimate`, {
|
||||||
|
params: {
|
||||||
|
itemFk,
|
||||||
|
warehouseFk: user.warehouseFk,
|
||||||
|
date: Date.vnNew(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const buyUltimateData = buyUltimate.data[0];
|
||||||
|
|
||||||
|
const allowedKeys = columns
|
||||||
|
.filter((col) => col.create === true)
|
||||||
|
.map((col) => col.name);
|
||||||
|
|
||||||
|
allowedKeys.forEach((key) => {
|
||||||
|
if (buyUltimateData.hasOwnProperty(key) && key !== 'entryFk') {
|
||||||
|
data[key] = buyUltimateData[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
console.log('viewMode: ', $props.editableMode);
|
|
||||||
stateStore.rightDrawer = false;
|
stateStore.rightDrawer = false;
|
||||||
|
if ($props.editableMode) checkEntryLock(entityId.value, user.id);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<QToggle
|
|
||||||
toggle-indeterminate
|
|
||||||
toggle-order="ft"
|
|
||||||
v-model="cyan"
|
|
||||||
label="'ft' order + toggle-indeterminate"
|
|
||||||
color="cyan"
|
|
||||||
/>
|
|
||||||
<Teleport to="#st-data" v-if="stateStore?.isSubToolbarShown() && editableMode">
|
<Teleport to="#st-data" v-if="stateStore?.isSubToolbarShown() && editableMode">
|
||||||
<QBtnGroup push style="column-gap: 1px">
|
<QBtnGroup push style="column-gap: 1px">
|
||||||
<QBtn icon="calculate" color="primary" flat @click="console.log('calculate')">
|
|
||||||
<QTooltip>{{ t('tableActions.openBucketCalculator') }}</QTooltip>
|
|
||||||
</QBtn>
|
|
||||||
<QBtnDropdown
|
<QBtnDropdown
|
||||||
icon="box_edit"
|
|
||||||
color="primary"
|
|
||||||
flat
|
|
||||||
tool-tip="test"
|
|
||||||
@click="console.log('request_quote')"
|
|
||||||
:title="t('tableActions.setSaleMode')"
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<QList>
|
|
||||||
<QItem clickable v-close-popup @click="setSaleMode('packing')">
|
|
||||||
<QItemSection>
|
|
||||||
<QItemLabel>Packing</QItemLabel>
|
|
||||||
</QItemSection>
|
|
||||||
</QItem>
|
|
||||||
<QItem clickable v-close-popup @click="setSaleMode('packing')">
|
|
||||||
<QItemSection>
|
|
||||||
<QItemLabel>Grouping</QItemLabel>
|
|
||||||
</QItemSection>
|
|
||||||
</QItem>
|
|
||||||
<QItem label="Grouping" />
|
|
||||||
</QList>
|
|
||||||
</div>
|
|
||||||
</QBtnDropdown>
|
|
||||||
<QBtn
|
|
||||||
icon="invert_colors"
|
|
||||||
color="primary"
|
|
||||||
flat
|
|
||||||
@click="console.log('price_check')"
|
|
||||||
>
|
|
||||||
<QTooltip>{{ t('tableActions.openCalculator') }}</QTooltip>
|
|
||||||
</QBtn>
|
|
||||||
<QBtn
|
|
||||||
icon="exposure_neg_1"
|
icon="exposure_neg_1"
|
||||||
color="primary"
|
color="primary"
|
||||||
flat
|
flat
|
||||||
@click="console.log('request_quote')"
|
:title="t('Invert quantity value')"
|
||||||
title="test"
|
:disable="!selectedRows.length"
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('tableActions.invertQuantitySign') }}</QTooltip>
|
<QList>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<QBtn flat @click="invertQuantitySign(selectedRows, -1)">
|
||||||
|
<span style="font-size: medium">-1</span>
|
||||||
</QBtn>
|
</QBtn>
|
||||||
<QBtn
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<QBtn flat @click="invertQuantitySign(selectedRows, 1)">
|
||||||
|
<span style="font-size: medium">1</span>
|
||||||
|
</QBtn>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</QList>
|
||||||
|
</QBtnDropdown>
|
||||||
|
<QBtnDropdown
|
||||||
icon="price_check"
|
icon="price_check"
|
||||||
color="primary"
|
color="primary"
|
||||||
flat
|
flat
|
||||||
@click="console.log('request_quote')"
|
:title="t('Check buy amount')"
|
||||||
|
:disable="!selectedRows.length"
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('tableActions.checkAmount') }}</QTooltip>
|
<QTooltip>{{}}</QTooltip>
|
||||||
</QBtn>
|
<QList>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
<QBtn
|
<QBtn
|
||||||
icon="price_check"
|
icon="check"
|
||||||
color="primary"
|
|
||||||
flat
|
flat
|
||||||
@click="console.log('request_quote')"
|
@click="setIsChecked(selectedRows, true)"
|
||||||
>
|
/>
|
||||||
<QTooltip>{{ t('tableActions.setMinPrice') }}</QTooltip>
|
</QItemSection>
|
||||||
</QBtn>
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<QBtn
|
||||||
|
icon="close"
|
||||||
|
flat
|
||||||
|
@click="setIsChecked(selectedRows, false)"
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</QList>
|
||||||
|
</QBtnDropdown>
|
||||||
</QBtnGroup>
|
</QBtnGroup>
|
||||||
</Teleport>
|
</Teleport>
|
||||||
<FetchData
|
<FetchData
|
||||||
ref="footerFetchDataRef"
|
ref="footerFetchDataRef"
|
||||||
:url="`Entries/${entityId}/getBuyList`"
|
:url="`Entries/${entityId}/getBuyList`"
|
||||||
:params="{ groupBy: 'GROUP BY b.entryFk' }"
|
:params="{ groupBy: 'GROUP BY b.entryFk' }"
|
||||||
@on-fetch="
|
@on-fetch="(data) => (footer = data[0])"
|
||||||
(data) => {
|
|
||||||
console.log('data: ', data);
|
|
||||||
footer = data[0];
|
|
||||||
}
|
|
||||||
"
|
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
<VnTable
|
<VnTable
|
||||||
ref="tableRef"
|
ref="entryBuysRef"
|
||||||
data-key="EntryBuys"
|
data-key="EntryBuys"
|
||||||
:url="`Entries/${entityId}/getBuyList`"
|
:url="`Entries/${entityId}/getBuyList`"
|
||||||
save-url="Buys/crud"
|
save-url="Buys/crud"
|
||||||
|
@ -431,19 +575,40 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
: {}
|
: {}
|
||||||
"
|
"
|
||||||
|
:create="
|
||||||
|
editableMode
|
||||||
|
? {
|
||||||
|
urlCreate: 'Buys',
|
||||||
|
title: t('Create buy'),
|
||||||
|
onDataSaved: () => {
|
||||||
|
entryBuysRef.reload();
|
||||||
|
footerFetchDataRef.fetch();
|
||||||
|
},
|
||||||
|
formInitialData: { entryFk: entityId, isIgnored: false },
|
||||||
|
isFullWidth: true,
|
||||||
|
containerClass: 'form-container',
|
||||||
|
showSaveAndContinueBtn: true,
|
||||||
|
columnGridStyle: {
|
||||||
|
'max-width': '50%',
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
"
|
||||||
:is-editable="editableMode"
|
:is-editable="editableMode"
|
||||||
:without-header="!editableMode"
|
:without-header="!editableMode"
|
||||||
:with-filters="editableMode"
|
:with-filters="editableMode"
|
||||||
:right-search="false"
|
:right-search="editableMode"
|
||||||
:row-click="false"
|
:row-click="false"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
|
:beforeSaveFn="beforeSave"
|
||||||
class="buyList"
|
class="buyList"
|
||||||
table-height="84vh"
|
table-height="84vh"
|
||||||
auto-load
|
auto-load
|
||||||
footer
|
footer
|
||||||
>
|
>
|
||||||
<template #column-hex="{ row }">
|
<template #column-hex="{ row }">
|
||||||
<VnColor :colors="row?.hexJson" style="height: 100%" />
|
<VnColor :colors="row?.hexJson" style="height: 100%; min-width: 2000px" />
|
||||||
</template>
|
</template>
|
||||||
<template #column-name="{ row }">
|
<template #column-name="{ row }">
|
||||||
<span class="link">
|
<span class="link">
|
||||||
|
@ -456,9 +621,9 @@ onMounted(() => {
|
||||||
</template>
|
</template>
|
||||||
<template #column-stickers="{ row }">
|
<template #column-stickers="{ row }">
|
||||||
<span :class="editableMode ? 'editable-text' : ''">
|
<span :class="editableMode ? 'editable-text' : ''">
|
||||||
<span style="color: var(--vn-label-color)">{{
|
<span style="color: var(--vn-label-color)">
|
||||||
row.printedStickers
|
{{ row.printedStickers }}
|
||||||
}}</span>
|
</span>
|
||||||
<span>/{{ row.stickers }}</span>
|
<span>/{{ row.stickers }}</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
@ -483,6 +648,36 @@ onMounted(() => {
|
||||||
{{ footer?.amount }}
|
{{ footer?.amount }}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
<template #column-create-itemFk="{ data }">
|
||||||
|
<VnSelect
|
||||||
|
url="Items"
|
||||||
|
v-model="data.itemFk"
|
||||||
|
:label="t('Article')"
|
||||||
|
:fields="['id', 'name']"
|
||||||
|
option-label="name"
|
||||||
|
option-value="id"
|
||||||
|
@update:modelValue="
|
||||||
|
async (value) => {
|
||||||
|
setBuyUltimate(value, data);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
:required="true"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #column-create-groupingMode="{ data }">
|
||||||
|
<VnSelectEnum
|
||||||
|
:label="t('Grouping mode')"
|
||||||
|
v-model="data.groupingMode"
|
||||||
|
schema="vn"
|
||||||
|
table="buy"
|
||||||
|
column="groupingMode"
|
||||||
|
option-value="groupingMode"
|
||||||
|
option-label="groupingMode"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #previous-create-dialog="{ data }">
|
||||||
|
<ItemDescriptor :id="data.itemFk" />
|
||||||
|
</template>
|
||||||
</VnTable>
|
</VnTable>
|
||||||
</template>
|
</template>
|
||||||
<i18n>
|
<i18n>
|
||||||
|
@ -508,4 +703,18 @@ es:
|
||||||
Producer: Productor
|
Producer: Productor
|
||||||
Company: Compañia
|
Company: Compañia
|
||||||
Tags: Etiquetas
|
Tags: Etiquetas
|
||||||
|
Grouping mode: Modo de agrupación
|
||||||
|
C.min: P.min
|
||||||
|
Ignore: Ignorar
|
||||||
|
Ignored for available: Ignorado para disponible
|
||||||
|
Grouping selector: Selector de grouping
|
||||||
|
Check min price: Marcar precio mínimo
|
||||||
|
Create buy: Crear compra
|
||||||
|
Invert quantity value: Invertir valor de cantidad
|
||||||
|
Check buy amount: Marcar como correcta la cantidad de compra
|
||||||
</i18n>
|
</i18n>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.test {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -10,6 +10,9 @@ import filter from './EntryFilter.js';
|
||||||
import TravelDescriptorProxy from 'src/pages/Travel/Card/TravelDescriptorProxy.vue';
|
import TravelDescriptorProxy from 'src/pages/Travel/Card/TravelDescriptorProxy.vue';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
import { useQuasar } from 'quasar';
|
||||||
|
|
||||||
|
const quasar = useQuasar();
|
||||||
const { push } = useRouter();
|
const { push } = useRouter();
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
|
@ -56,17 +59,24 @@ const getEntryRedirectionFilter = (entry) => {
|
||||||
function showEntryReport() {
|
function showEntryReport() {
|
||||||
openReport(`Entries/${entityId.value}/entry-order-pdf`);
|
openReport(`Entries/${entityId.value}/entry-order-pdf`);
|
||||||
}
|
}
|
||||||
function recalculateRates() {
|
async function recalculateRates(entity) {
|
||||||
console.log('recalculateRates');
|
const entryConfig = await axios.get('EntryConfigs/findOne');
|
||||||
|
if (entryConfig.data?.inventorySupplierFk === entity.supplierFk) {
|
||||||
|
quasar.notify({
|
||||||
|
type: 'negative',
|
||||||
|
message: t('Cannot recalculate prices because this is an inventory entry'),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await axios.post(`Entries/${entityId.value}/recalcEntryPrices`);
|
||||||
}
|
}
|
||||||
async function cloneEntry() {
|
async function cloneEntry() {
|
||||||
console.log('cloneEntry');
|
|
||||||
await axios
|
await axios
|
||||||
.post(`Entries/${entityId.value}/cloneEntry`)
|
.post(`Entries/${entityId.value}/cloneEntry`)
|
||||||
.then((response) => push(`/entry/${response.data[0].vNewEntryFk}`));
|
.then((response) => push(`/entry/${response.data[0].vNewEntryFk}`));
|
||||||
}
|
}
|
||||||
async function deleteEntry() {
|
async function deleteEntry() {
|
||||||
console.log('deleteEntry');
|
|
||||||
await axios.post(`Entries/${entityId.value}/deleteEntry`).then(() => push(`/entry/`));
|
await axios.post(`Entries/${entityId.value}/deleteEntry`).then(() => push(`/entry/`));
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -118,6 +128,10 @@ async function deleteEntry() {
|
||||||
:label="t('entry.summary.invoiceAmount')"
|
:label="t('entry.summary.invoiceAmount')"
|
||||||
:value="entity?.invoiceAmount"
|
:value="entity?.invoiceAmount"
|
||||||
/>
|
/>
|
||||||
|
<VnLv
|
||||||
|
:label="t('entry.summary.entryType')"
|
||||||
|
:value="entity?.entryType?.description"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #icons="{ entity }">
|
<template #icons="{ entity }">
|
||||||
<QCardActions class="q-gutter-x-md">
|
<QCardActions class="q-gutter-x-md">
|
||||||
|
@ -163,21 +177,6 @@ async function deleteEntry() {
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('Supplier card') }}</QTooltip>
|
<QTooltip>{{ t('Supplier card') }}</QTooltip>
|
||||||
</QBtn>
|
</QBtn>
|
||||||
<QBtn
|
|
||||||
:to="{
|
|
||||||
name: 'TravelMain',
|
|
||||||
query: {
|
|
||||||
params: JSON.stringify({
|
|
||||||
agencyModeFk: entity.travel?.agencyModeFk,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
}"
|
|
||||||
size="md"
|
|
||||||
icon="local_airport"
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
<QTooltip>{{ t('All travels with current agency') }}</QTooltip>
|
|
||||||
</QBtn>
|
|
||||||
<QBtn
|
<QBtn
|
||||||
:to="{
|
:to="{
|
||||||
name: 'EntryMain',
|
name: 'EntryMain',
|
||||||
|
@ -207,4 +206,5 @@ es:
|
||||||
shipped: Enviado
|
shipped: Enviado
|
||||||
landed: Recibido
|
landed: Recibido
|
||||||
This entry is deleted: Esta entrada está eliminada
|
This entry is deleted: Esta entrada está eliminada
|
||||||
|
Cannot recalculate prices because this is an inventory entry: No se pueden recalcular los precios porque es una entrada de inventario
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -46,5 +46,11 @@ export default {
|
||||||
fields: ['id', 'code'],
|
fields: ['id', 'code'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
relation: 'entryType',
|
||||||
|
scope: {
|
||||||
|
fields: ['code', 'description'],
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
|
@ -167,7 +167,12 @@ onMounted(async () => {
|
||||||
:url="`#/entry/{{ entityId }}/buys`"
|
:url="`#/entry/{{ entityId }}/buys`"
|
||||||
:text="t('entry.summary.buys')"
|
:text="t('entry.summary.buys')"
|
||||||
/>
|
/>
|
||||||
<EntryBuys v-if="entityId" :id="entityId" :editable-mode="false" />
|
<EntryBuys
|
||||||
|
v-if="entityId"
|
||||||
|
:id="entityId"
|
||||||
|
:editable-mode="false"
|
||||||
|
:isEditable="false"
|
||||||
|
/>
|
||||||
</QCard>
|
</QCard>
|
||||||
</template>
|
</template>
|
||||||
</CardSummary>
|
</CardSummary>
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { onBeforeMount } from 'vue';
|
||||||
import EntryFilter from './EntryFilter.vue';
|
import EntryFilter from './EntryFilter.vue';
|
||||||
import VnTable from 'components/VnTable/VnTable.vue';
|
import VnTable from 'components/VnTable/VnTable.vue';
|
||||||
import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
|
import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
|
||||||
|
import VnSelectTravelExtended from 'src/components/common/VnSelectTravelExtended.vue';
|
||||||
import { toDate } from 'src/filters';
|
import { toDate } from 'src/filters';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -274,7 +275,7 @@ onBeforeMount(async () => {
|
||||||
<template #advanced-menu>
|
<template #advanced-menu>
|
||||||
<EntryFilter :data-key="dataKey" />
|
<EntryFilter :data-key="dataKey" />
|
||||||
</template>
|
</template>
|
||||||
</VnSection>
|
<template #body>
|
||||||
<VnTable
|
<VnTable
|
||||||
v-if="defaultEntry.defaultSupplierFk"
|
v-if="defaultEntry.defaultSupplierFk"
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
|
@ -312,7 +313,18 @@ onBeforeMount(async () => {
|
||||||
<SupplierDescriptorProxy :id="row.supplierFk" />
|
<SupplierDescriptorProxy :id="row.supplierFk" />
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
<template #column-create-travelFk="{ data }">
|
||||||
|
<VnSelectTravelExtended
|
||||||
|
:data="data"
|
||||||
|
v-model="data.travelFk"
|
||||||
|
:onFilterTravelSelected="
|
||||||
|
(data, result) => (data.travelFk = result)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
</VnTable>
|
</VnTable>
|
||||||
|
</template>
|
||||||
|
</VnSection>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
entry:
|
entry:
|
||||||
|
lock:
|
||||||
|
title: Lock entry
|
||||||
|
message: This entry has been locked by {userName} for {time} minutes. Do you want to unlock it?
|
||||||
list:
|
list:
|
||||||
newEntry: New entry
|
newEntry: New entry
|
||||||
tableVisibleColumns:
|
tableVisibleColumns:
|
||||||
|
@ -20,11 +23,13 @@ entry:
|
||||||
entryTypeDescription: Entry type
|
entryTypeDescription: Entry type
|
||||||
invoiceAmount: Import
|
invoiceAmount: Import
|
||||||
travelFk: Travel
|
travelFk: Travel
|
||||||
|
dated: Dated
|
||||||
inventoryEntry: Inventory entry
|
inventoryEntry: Inventory entry
|
||||||
summary:
|
summary:
|
||||||
commission: Commission
|
commission: Commission
|
||||||
currency: Currency
|
currency: Currency
|
||||||
invoiceNumber: Invoice number
|
invoiceNumber: Invoice number
|
||||||
|
invoiceAmount: Invoice amount
|
||||||
ordered: Ordered
|
ordered: Ordered
|
||||||
booked: Booked
|
booked: Booked
|
||||||
excludedFromAvailable: Inventory
|
excludedFromAvailable: Inventory
|
||||||
|
@ -42,6 +47,7 @@ entry:
|
||||||
buyingValue: Buying value
|
buyingValue: Buying value
|
||||||
import: Import
|
import: Import
|
||||||
pvp: PVP
|
pvp: PVP
|
||||||
|
entryType: Entry type
|
||||||
basicData:
|
basicData:
|
||||||
travel: Travel
|
travel: Travel
|
||||||
currency: Currency
|
currency: Currency
|
||||||
|
@ -78,11 +84,48 @@ entry:
|
||||||
landing: Landing
|
landing: Landing
|
||||||
isExcludedFromAvailable: Es inventory
|
isExcludedFromAvailable: Es inventory
|
||||||
params:
|
params:
|
||||||
toShipped: To
|
isExcludedFromAvailable: Exclude from inventory
|
||||||
fromShipped: From
|
isOrdered: Ordered
|
||||||
daysOnward: Days onward
|
isConfirmed: Ready to label
|
||||||
daysAgo: Days ago
|
isReceived: Received
|
||||||
warehouseInFk: Warehouse in
|
isIgnored: Ignored
|
||||||
|
isRaid: Raid
|
||||||
|
landed: Date
|
||||||
|
supplierFk: Supplier
|
||||||
|
reference: Ref/Alb/Guide
|
||||||
|
invoiceNumber: Invoice
|
||||||
|
agencyModeId: Agency
|
||||||
|
isBooked: Booked
|
||||||
|
companyFk: Company
|
||||||
|
evaNotes: Notes
|
||||||
|
warehouseOutFk: Origin
|
||||||
|
warehouseInFk: Destiny
|
||||||
|
entryTypeDescription: Entry type
|
||||||
|
invoiceAmount: Import
|
||||||
|
travelFk: Travel
|
||||||
|
dated: Dated
|
||||||
|
itemFk: Item id
|
||||||
|
hex: Color
|
||||||
|
name: Item name
|
||||||
|
size: Size
|
||||||
|
stickers: Stickers
|
||||||
|
packagingFk: Packaging
|
||||||
|
weight: Kg
|
||||||
|
groupingMode: Grouping selector
|
||||||
|
grouping: Grouping
|
||||||
|
quantity: Quantity
|
||||||
|
buyingValue: Buying value
|
||||||
|
price2: Package
|
||||||
|
price3: Box
|
||||||
|
minPrice: Minumum price
|
||||||
|
hasMinPrice: Has minimum price
|
||||||
|
packingOut: Packing out
|
||||||
|
comment: Comment
|
||||||
|
subName: Supplier name
|
||||||
|
tags: Tags
|
||||||
|
company_name: Company name
|
||||||
|
itemTypeFk: Item type
|
||||||
|
workerFk: Worker id
|
||||||
search: Search entries
|
search: Search entries
|
||||||
searchInfo: You can search by entry reference
|
searchInfo: You can search by entry reference
|
||||||
entryFilter:
|
entryFilter:
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
entry:
|
entry:
|
||||||
|
lock:
|
||||||
|
title: Entrada bloqueada
|
||||||
|
message: Esta entrada ha sido bloqueada por {userName} hace {time} minutos. ¿Quieres desbloquearla?
|
||||||
|
|
||||||
list:
|
list:
|
||||||
newEntry: Nueva entrada
|
newEntry: Nueva entrada
|
||||||
tableVisibleColumns:
|
tableVisibleColumns:
|
||||||
|
@ -20,11 +24,13 @@ entry:
|
||||||
warehouseInFk: Destino
|
warehouseInFk: Destino
|
||||||
entryTypeDescription: Tipo entrada
|
entryTypeDescription: Tipo entrada
|
||||||
invoiceAmount: Importe
|
invoiceAmount: Importe
|
||||||
|
dated: Fecha
|
||||||
inventoryEntry: Es inventario
|
inventoryEntry: Es inventario
|
||||||
summary:
|
summary:
|
||||||
commission: Comisión
|
commission: Comisión
|
||||||
currency: Moneda
|
currency: Moneda
|
||||||
invoiceNumber: Núm. factura
|
invoiceNumber: Núm. factura
|
||||||
|
invoiceAmount: Importe
|
||||||
ordered: Pedida
|
ordered: Pedida
|
||||||
booked: Contabilizada
|
booked: Contabilizada
|
||||||
excludedFromAvailable: Inventario
|
excludedFromAvailable: Inventario
|
||||||
|
@ -43,6 +49,7 @@ entry:
|
||||||
buyingValue: Coste
|
buyingValue: Coste
|
||||||
import: Importe
|
import: Importe
|
||||||
pvp: PVP
|
pvp: PVP
|
||||||
|
entryType: Tipo entrada
|
||||||
basicData:
|
basicData:
|
||||||
travel: Envío
|
travel: Envío
|
||||||
currency: Moneda
|
currency: Moneda
|
||||||
|
@ -78,14 +85,52 @@ entry:
|
||||||
packingOut: Embalaje envíos
|
packingOut: Embalaje envíos
|
||||||
landing: Llegada
|
landing: Llegada
|
||||||
isExcludedFromAvailable: Es inventario
|
isExcludedFromAvailable: Es inventario
|
||||||
params:
|
|
||||||
toShipped: Hasta
|
|
||||||
fromShipped: Desde
|
|
||||||
warehouseInFk: Alm. entrada
|
|
||||||
daysOnward: Días adelante
|
|
||||||
daysAgo: Días atras
|
|
||||||
search: Buscar entradas
|
search: Buscar entradas
|
||||||
searchInfo: Puedes buscar por referencia de entrada
|
searchInfo: Puedes buscar por referencia de entrada
|
||||||
|
params:
|
||||||
|
isExcludedFromAvailable: Excluir del inventario
|
||||||
|
isOrdered: Pedida
|
||||||
|
isConfirmed: Lista para etiquetar
|
||||||
|
isReceived: Recibida
|
||||||
|
isRaid: Redada
|
||||||
|
isIgnored: Ignorado
|
||||||
|
landed: Fecha
|
||||||
|
supplierFk: Proveedor
|
||||||
|
invoiceNumber: Nº Factura
|
||||||
|
reference: Ref/Alb/Guía
|
||||||
|
agencyModeId: Agencia
|
||||||
|
isBooked: Asentado
|
||||||
|
companyFk: Empresa
|
||||||
|
travelFk: Envio
|
||||||
|
evaNotes: Notas
|
||||||
|
warehouseOutFk: Origen
|
||||||
|
warehouseInFk: Destino
|
||||||
|
entryTypeDescription: Tipo entrada
|
||||||
|
invoiceAmount: Importe
|
||||||
|
dated: Fecha
|
||||||
|
itemFk: Id artículo
|
||||||
|
hex: Color
|
||||||
|
name: Nombre artículo
|
||||||
|
size: Medida
|
||||||
|
stickers: Etiquetas
|
||||||
|
packagingFk: Embalaje
|
||||||
|
weight: Kg
|
||||||
|
groupinMode: Selector de grouping
|
||||||
|
grouping: Grouping
|
||||||
|
quantity: Quantity
|
||||||
|
buyingValue: Precio de compra
|
||||||
|
price2: Paquete
|
||||||
|
price3: Caja
|
||||||
|
minPrice: Precio mínimo
|
||||||
|
hasMinPrice: Tiene precio mínimo
|
||||||
|
packingOut: Packing out
|
||||||
|
comment: Referencia
|
||||||
|
subName: Nombre proveedor
|
||||||
|
tags: Etiquetas
|
||||||
|
company_name: Nombre empresa
|
||||||
|
itemTypeFk: Familia
|
||||||
|
workerFk: Comprador
|
||||||
entryFilter:
|
entryFilter:
|
||||||
params:
|
params:
|
||||||
invoiceNumber: Núm. factura
|
invoiceNumber: Núm. factura
|
||||||
|
|
|
@ -272,7 +272,6 @@ const createInvoiceInCorrection = async () => {
|
||||||
>
|
>
|
||||||
<template #option="{ itemProps, opt }">
|
<template #option="{ itemProps, opt }">
|
||||||
<QItem v-bind="itemProps">
|
<QItem v-bind="itemProps">
|
||||||
{{ console.log('opt: ', opt) }}
|
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<QItemLabel
|
<QItemLabel
|
||||||
>{{ opt.id }} -
|
>{{ opt.id }} -
|
||||||
|
|
|
@ -28,6 +28,7 @@ const cols = computed(() => [
|
||||||
name: 'isBooked',
|
name: 'isBooked',
|
||||||
label: t('invoicein.isBooked'),
|
label: t('invoicein.isBooked'),
|
||||||
columnFilter: false,
|
columnFilter: false,
|
||||||
|
component: 'checkbox',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
@ -176,7 +177,9 @@ const cols = computed(() => [
|
||||||
<QItem v-bind="scope.itemProps">
|
<QItem v-bind="scope.itemProps">
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<QItemLabel>{{ scope.opt?.nickname }}</QItemLabel>
|
<QItemLabel>{{ scope.opt?.nickname }}</QItemLabel>
|
||||||
<QItemLabel caption> #{{ scope.opt?.id }}, {{ scope.opt?.name }} </QItemLabel>
|
<QItemLabel caption>
|
||||||
|
#{{ scope.opt?.id }}, {{ scope.opt?.name }}
|
||||||
|
</QItemLabel>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -157,7 +157,7 @@ const openTab = (id) =>
|
||||||
openConfirmationModal(
|
openConfirmationModal(
|
||||||
$t('globals.deleteConfirmTitle'),
|
$t('globals.deleteConfirmTitle'),
|
||||||
$t('salesOrdersTable.deleteConfirmMessage'),
|
$t('salesOrdersTable.deleteConfirmMessage'),
|
||||||
removeOrders
|
removeOrders,
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
|
|
|
@ -50,7 +50,6 @@ const columns = computed(() => [
|
||||||
name: 'isAnyVolumeAllowed',
|
name: 'isAnyVolumeAllowed',
|
||||||
component: 'checkbox',
|
component: 'checkbox',
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
disable: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'right',
|
align: 'right',
|
||||||
|
@ -80,7 +79,8 @@ const columns = computed(() => [
|
||||||
url="Agencies"
|
url="Agencies"
|
||||||
order="name"
|
order="name"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:right-search="false"
|
is-editable="false"
|
||||||
|
:right-search="true"
|
||||||
:use-model="true"
|
:use-model="true"
|
||||||
redirect="agency"
|
redirect="agency"
|
||||||
default-mode="card"
|
default-mode="card"
|
||||||
|
|
|
@ -68,7 +68,7 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
useLike: false,
|
useLike: false,
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
format: (row, dashIfEmpty) => dashIfEmpty(row.travelRef),
|
format: (row, dashIfEmpty) => dashIfEmpty(row.workerUserName),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
@ -87,6 +87,7 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
columnClass: 'expand',
|
columnClass: 'expand',
|
||||||
|
format: (row, dashIfEmpty) => dashIfEmpty(row.agencyName),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
@ -108,6 +109,7 @@ const columns = computed(() => [
|
||||||
columnFilter: {
|
columnFilter: {
|
||||||
inWhere: true,
|
inWhere: true,
|
||||||
},
|
},
|
||||||
|
format: (row, dashIfEmpty) => dashIfEmpty(row.vehiclePlateNumber),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
@ -117,7 +119,7 @@ const columns = computed(() => [
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
create: true,
|
create: true,
|
||||||
component: 'date',
|
component: 'date',
|
||||||
format: ({ created }) => toDate(created),
|
format: ({ dated }) => toDate(dated),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
@ -127,7 +129,7 @@ const columns = computed(() => [
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
create: true,
|
create: true,
|
||||||
component: 'date',
|
component: 'date',
|
||||||
format: ({ from }) => toDate(from),
|
format: ({ from }) => from,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
@ -152,7 +154,7 @@ const columns = computed(() => [
|
||||||
label: t('route.hourStarted'),
|
label: t('route.hourStarted'),
|
||||||
component: 'time',
|
component: 'time',
|
||||||
columnFilter: false,
|
columnFilter: false,
|
||||||
format: ({ hourStarted }) => toHour(hourStarted),
|
format: ({ started }) => toHour(started),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
@ -160,7 +162,7 @@ const columns = computed(() => [
|
||||||
label: t('route.hourFinished'),
|
label: t('route.hourFinished'),
|
||||||
component: 'time',
|
component: 'time',
|
||||||
columnFilter: false,
|
columnFilter: false,
|
||||||
format: ({ hourFinished }) => toHour(hourFinished),
|
format: ({ finished }) => toHour(finished),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
|
Loading…
Reference in New Issue