0
0
Fork 0

Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 6899_InvoiceOut_End

This commit is contained in:
Jon Elias 2024-07-03 09:46:54 +02:00
commit 7914387735
52 changed files with 880 additions and 746 deletions

BIN
public/no-image-dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
public/no-image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
public/no-user.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@ -90,7 +90,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);
@ -137,7 +137,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 },
); );
} }
}); });
@ -145,7 +145,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(formUrl, async () => { watch(formUrl, async () => {
@ -206,11 +206,11 @@ async function save() {
updateAndEmit('onDataSaved', formData.value, response?.data); updateAndEmit('onDataSaved', formData.value, response?.data);
if ($props.reload) await arrayData.fetch({}); if ($props.reload) await arrayData.fetch({});
hasChanges.value = false;
} catch (err) { } catch (err) {
console.error(err); console.error(err);
notify('errors.writeRequest', 'negative'); notify('errors.writeRequest', 'negative');
} finally { } finally {
hasChanges.value = false;
isLoading.value = false; isLoading.value = false;
} }
} }
@ -239,7 +239,7 @@ function filter(value, update, filterOptions) {
(ref) => { (ref) => {
ref.setOptionIndex(-1); ref.setOptionIndex(-1);
ref.moveOptionSelection(1, true); ref.moveOptionSelection(1, true);
} },
); );
} }

View File

@ -58,6 +58,7 @@ function addChildren(module, route, parent) {
} }
const items = ref([]); const items = ref([]);
function getRoutes() { function getRoutes() {
if (props.source === 'main') { if (props.source === 'main') {
const modules = Object.assign([], navigation.getModules().value); const modules = Object.assign([], navigation.getModules().value);
@ -66,9 +67,8 @@ function getRoutes() {
const moduleDef = routes.find( const moduleDef = routes.find(
(route) => toLowerCamel(route.name) === item.module (route) => toLowerCamel(route.name) === item.module
); );
item.children = [];
if (!moduleDef) continue; if (!moduleDef) continue;
item.children = [];
addChildren(item.module, moduleDef, item.children); addChildren(item.module, moduleDef, item.children);
} }

View File

@ -1,21 +1,19 @@
<script setup> <script setup>
import { onMounted, ref } from 'vue'; import { onMounted, ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useSession } from 'src/composables/useSession';
import { useState } from 'src/composables/useState'; import { useState } from 'src/composables/useState';
import { useStateStore } from 'stores/useStateStore'; import { useStateStore } from 'stores/useStateStore';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
import PinnedModules from './PinnedModules.vue'; import PinnedModules from './PinnedModules.vue';
import UserPanel from 'components/UserPanel.vue'; import UserPanel from 'components/UserPanel.vue';
import VnBreadcrumbs from './common/VnBreadcrumbs.vue'; import VnBreadcrumbs from './common/VnBreadcrumbs.vue';
import VnImg from 'src/components/ui/VnImg.vue';
const { t } = useI18n(); const { t } = useI18n();
const stateStore = useStateStore(); const stateStore = useStateStore();
const quasar = useQuasar(); const quasar = useQuasar();
const state = useState(); const state = useState();
const user = state.getUser(); const user = state.getUser();
const { getTokenMultimedia } = useSession();
const token = getTokenMultimedia();
const appName = 'Lilium'; const appName = 'Lilium';
onMounted(() => stateStore.setMounted()); onMounted(() => stateStore.setMounted());
@ -83,11 +81,12 @@ const pinnedModulesRef = ref();
id="user" id="user"
> >
<QAvatar size="lg"> <QAvatar size="lg">
<QImg <VnImg
:src="`/api/Images/user/160x160/${user.id}/download?access_token=${token}`" :id="user.id"
spinner-color="primary" collection="user"
> size="160x160"
</QImg> :zoom-size="null"
/>
</QAvatar> </QAvatar>
<QTooltip bottom> <QTooltip bottom>
{{ t('globals.userPanel') }} {{ t('globals.userPanel') }}

View File

@ -12,12 +12,14 @@ import VnRow from 'components/ui/VnRow.vue';
import FetchData from 'components/FetchData.vue'; import FetchData from 'components/FetchData.vue';
import { useClipboard } from 'src/composables/useClipboard'; import { useClipboard } from 'src/composables/useClipboard';
import VnImg from 'src/components/ui/VnImg.vue'; import VnImg from 'src/components/ui/VnImg.vue';
import { useRole } from 'src/composables/useRole';
const state = useState(); const state = useState();
const session = useSession(); const session = useSession();
const router = useRouter(); const router = useRouter();
const { t, locale } = useI18n(); const { t, locale } = useI18n();
const { copyText } = useClipboard(); const { copyText } = useClipboard();
const userLocale = computed({ const userLocale = computed({
get() { get() {
return locale.value; return locale.value;
@ -99,6 +101,7 @@ function saveUserData(param, value) {
axios.post('UserConfigs/setUserConfig', { [param]: value }); axios.post('UserConfigs/setUserConfig', { [param]: value });
localUserData(); localUserData();
} }
const isEmployee = computed(() => useRole().isEmployee());
</script> </script>
<template> <template>
@ -109,12 +112,14 @@ function saveUserData(param, value) {
auto-load auto-load
/> />
<FetchData <FetchData
v-if="isEmployee"
url="Companies" url="Companies"
order="name" order="name"
@on-fetch="(data) => (companiesData = data)" @on-fetch="(data) => (companiesData = data)"
auto-load auto-load
/> />
<FetchData <FetchData
v-if="isEmployee"
url="Accountings" url="Accountings"
order="name" order="name"
@on-fetch="(data) => (accountBankData = data)" @on-fetch="(data) => (accountBankData = data)"

View File

@ -7,6 +7,7 @@ import { useArrayData } from 'composables/useArrayData';
import VnSelect from 'components/common/VnSelect.vue'; import VnSelect from 'components/common/VnSelect.vue';
import VnInput from 'components/common/VnInput.vue'; import VnInput from 'components/common/VnInput.vue';
import VnInputDate from 'components/common/VnInputDate.vue'; import VnInputDate from 'components/common/VnInputDate.vue';
import VnInputTime from 'components/common/VnInputTime.vue';
import VnTableColumn from 'components/VnTable/VnColumn.vue'; import VnTableColumn from 'components/VnTable/VnColumn.vue';
const $props = defineProps({ const $props = defineProps({
@ -75,6 +76,17 @@ const components = {
}, },
forceAttrs, forceAttrs,
}, },
time: {
component: markRaw(VnInputTime),
event: updateEvent,
attrs: {
...defaultAttrs,
disable: !$props.isEditable,
},
forceAttrs: {
label: $props.showLabel && $props.column.label,
},
},
checkbox: { checkbox: {
component: markRaw(QCheckbox), component: markRaw(QCheckbox),
event: updateEvent, event: updateEvent,

View File

@ -1,6 +1,6 @@
<script setup> <script setup>
import { onBeforeMount, computed } from 'vue'; import { onBeforeMount, computed } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute, onBeforeRouteUpdate } from 'vue-router';
import { useArrayData } from 'src/composables/useArrayData'; import { useArrayData } from 'src/composables/useArrayData';
import { useStateStore } from 'stores/useStateStore'; import { useStateStore } from 'stores/useStateStore';
import useCardSize from 'src/composables/useCardSize'; import useCardSize from 'src/composables/useCardSize';
@ -41,6 +41,15 @@ onBeforeMount(async () => {
if (!props.baseUrl) arrayData.store.filter.where = { id: route.params.id }; if (!props.baseUrl) arrayData.store.filter.where = { id: route.params.id };
await arrayData.fetch({ append: false }); await arrayData.fetch({ append: false });
}); });
if (props.baseUrl) {
onBeforeRouteUpdate(async (to, from) => {
if (to.params.id !== from.params.id) {
arrayData.store.url = `${props.baseUrl}/${to.params.id}`;
await arrayData.fetch({ append: false, updateRouter: false });
}
});
}
</script> </script>
<template> <template>
<QDrawer <QDrawer

View File

@ -1,84 +1,31 @@
<script setup> <script setup>
import { computed, ref } from 'vue'; import { onMounted, watch, computed, ref } from 'vue';
import { date } from 'quasar';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import isValidDate from 'filters/isValidDate';
const props = defineProps({ const model = defineModel({ type: String });
modelValue: { const $props = defineProps({
type: String,
default: null,
},
readonly: {
type: Boolean,
default: false,
},
isOutlined: { isOutlined: {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
emitDateFormat: {
type: Boolean,
default: false,
},
}); });
const hover = ref(false);
const emit = defineEmits(['update:modelValue']);
const { t } = useI18n(); const { t } = useI18n();
const requiredFieldRule = (val) => !!val || t('globals.fieldRequired'); const requiredFieldRule = (val) => !!val || t('globals.fieldRequired');
const joinDateAndTime = (date, time) => { const dateFormat = 'DD/MM/YYYY';
if (!date) { const isPopupOpen = ref();
return null; const hover = ref();
} const mask = ref();
if (!time) {
return new Date(date).toISOString();
}
const [year, month, day] = date.split('/');
return new Date(`${year}-${month}-${day}T${time}`).toISOString();
};
const time = computed(() => (props.modelValue ? props.modelValue.split('T')?.[1] : null)); onMounted(() => {
const value = computed({ // fix quasar bug
get() { mask.value = '##/##/####';
return props.modelValue;
},
set(value) {
emit(
'update:modelValue',
props.emitDateFormat ? new Date(value) : joinDateAndTime(value, time.value)
);
},
}); });
const isPopupOpen = ref(false);
const onDateUpdate = (date) => {
value.value = date;
isPopupOpen.value = false;
};
const padDate = (value) => value.toString().padStart(2, '0');
const formatDate = (dateString) => {
const date = new Date(dateString || '');
return `${date.getFullYear()}/${padDate(date.getMonth() + 1)}/${padDate(
date.getDate()
)}`;
};
const displayDate = (dateString) => {
if (!dateString || !isValidDate(dateString)) {
return '';
}
return new Date(dateString).toLocaleDateString([], {
year: 'numeric',
month: '2-digit',
day: '2-digit',
});
};
const styleAttrs = computed(() => { const styleAttrs = computed(() => {
return props.isOutlined return $props.isOutlined
? { ? {
dense: true, dense: true,
outlined: true, outlined: true,
@ -86,52 +33,101 @@ const styleAttrs = computed(() => {
} }
: {}; : {};
}); });
const formattedDate = computed({
get() {
if (!model.value) return model.value;
return date.formatDate(new Date(model.value), dateFormat);
},
set(value) {
if (value == model.value) return;
let newDate;
if (value) {
// parse input
if (value.includes('/') && value.length >= 10) {
if (value.at(2) == '/') value = value.split('/').reverse().join('/');
value = date.formatDate(
new Date(value).toISOString(),
'YYYY-MM-DDTHH:mm:ss.SSSZ'
);
}
let ymd = value.split('-').map((e) => parseInt(e));
newDate = new Date(ymd[0], ymd[1] - 1, ymd[2]);
if (model.value) {
const orgDate =
model.value instanceof Date ? model.value : new Date(model.value);
newDate.setHours(
orgDate.getHours(),
orgDate.getMinutes(),
orgDate.getSeconds(),
orgDate.getMilliseconds()
);
}
}
if (!isNaN(newDate)) model.value = newDate.toISOString();
},
});
const popupDate = computed(() =>
model.value ? date.formatDate(new Date(model.value), 'YYYY/MM/DD') : model.value
);
watch(
() => model.value,
(val) => (formattedDate.value = val),
{ immediate: true }
);
</script> </script>
<template> <template>
<div @mouseover="hover = true" @mouseleave="hover = false"> <div @mouseover="hover = true" @mouseleave="hover = false">
<QInput <QInput
v-model="formattedDate"
class="vn-input-date" class="vn-input-date"
readonly :mask="mask"
:model-value="displayDate(value)" placeholder="dd/mm/aaaa"
v-bind="{ ...$attrs, ...styleAttrs }" v-bind="{ ...$attrs, ...styleAttrs }"
:class="{ required: $attrs.required }" :class="{ required: $attrs.required }"
:rules="$attrs.required ? [requiredFieldRule] : null" :rules="$attrs.required ? [requiredFieldRule] : null"
@click="isPopupOpen = true" :clearable="false"
> >
<template #append> <template #append>
<QIcon <QIcon
name="close" name="close"
size="xs" size="xs"
v-if="hover && value && !readonly" v-if="
@click="onDateUpdate(null)" ($attrs.clearable == undefined || $attrs.clearable) &&
></QIcon> hover &&
<QIcon name="event" class="cursor-pointer"> model &&
<QPopupProxy !$attrs.disable
v-model="isPopupOpen" "
cover @click="
transition-show="scale" model = null;
transition-hide="scale" isPopupOpen = false;
:no-parent-event="props.readonly" "
> />
<QDate <QIcon name="event" class="cursor-pointer" />
:today-btn="true"
:model-value="formatDate(value)"
@update:model-value="onDateUpdate"
/>
</QPopupProxy>
</QIcon>
</template> </template>
<QMenu
transition-show="scale"
transition-hide="scale"
v-model="isPopupOpen"
anchor="bottom left"
self="top start"
:no-focus="true"
>
<QDate
v-model="popupDate"
:today-btn="true"
@update:model-value="
(date) => {
formattedDate = date;
isPopupOpen = false;
}
"
/>
</QMenu>
</QInput> </QInput>
</div> </div>
</template> </template>
<style lang="scss">
.vn-input-date.q-field--standard.q-field--readonly .q-field__control:before {
border-bottom-style: solid;
}
.vn-input-date.q-field--outlined.q-field--readonly .q-field__control:before {
border-style: solid;
}
</style>

View File

@ -1,14 +1,11 @@
<script setup> <script setup>
import { computed, ref } from 'vue'; import { watch, computed, ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import isValidDate from 'filters/isValidDate'; import { date } from 'quasar';
const model = defineModel({ type: String });
const props = defineProps({ const props = defineProps({
modelValue: { timeOnly: {
type: String,
default: null,
},
readonly: {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
@ -17,43 +14,12 @@ const props = defineProps({
default: false, default: false,
}, },
}); });
const emit = defineEmits(['update:modelValue']);
const { t } = useI18n(); const { t } = useI18n();
const requiredFieldRule = (val) => !!val || t('globals.fieldRequired'); const requiredFieldRule = (val) => !!val || t('globals.fieldRequired');
const value = computed({ const dateFormat = 'HH:mm';
get() { const isPopupOpen = ref();
return props.modelValue; const hover = ref();
},
set(value) {
const [hours, minutes] = value.split(':');
const date = new Date(props.modelValue);
date.setHours(Number.parseInt(hours) || 0, Number.parseInt(minutes) || 0, 0, 0);
emit('update:modelValue', value ? date.toISOString() : null);
},
});
const isPopupOpen = ref(false);
const onDateUpdate = (date) => {
internalValue.value = date;
};
const save = () => {
value.value = internalValue.value;
};
const formatTime = (dateString) => {
if (!dateString || !isValidDate(dateString)) {
return '';
}
const date = new Date(dateString || '');
return date.toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit',
});
};
const internalValue = ref(formatTime(value));
const styleAttrs = computed(() => { const styleAttrs = computed(() => {
return props.isOutlined return props.isOutlined
@ -64,65 +30,84 @@ const styleAttrs = computed(() => {
} }
: {}; : {};
}); });
const formattedTime = computed({
get() {
if (!model.value || model.value?.length <= 5) return model.value;
return dateToTime(model.value);
},
set(value) {
if (value == model.value) return;
let time = value;
if (time) {
if (time?.length > 5) time = dateToTime(time);
if (!props.timeOnly) {
const hours = time.split(':');
const date = new Date();
date.setHours(hours[0], hours[1], 0);
time = date.toISOString();
}
}
model.value = time;
},
});
function dateToTime(newDate) {
return date.formatDate(new Date(newDate), dateFormat);
}
watch(
() => model.value,
(val) => (formattedTime.value = val),
{ immediate: true }
);
</script> </script>
<template> <template>
<QInput <div @mouseover="hover = true" @mouseleave="hover = false">
class="vn-input-time" <QInput
readonly class="vn-input-time"
:model-value="formatTime(value)" mask="##:##"
v-bind="{ ...$attrs, ...styleAttrs }" placeholder="--:--"
:class="{ required: $attrs.required }" v-model="formattedTime"
:rules="$attrs.required ? [requiredFieldRule] : null" v-bind="{ ...$attrs, ...styleAttrs }"
@click="isPopupOpen = true" :class="{ required: $attrs.required }"
> style="min-width: 100px"
<template #append> :rules="$attrs.required ? [requiredFieldRule] : null"
<QIcon name="Schedule" class="cursor-pointer"> >
<QPopupProxy <template #append>
v-model="isPopupOpen" <QIcon
cover name="close"
transition-show="scale" size="xs"
transition-hide="scale" v-if="
:no-parent-event="props.readonly" ($attrs.clearable == undefined || $attrs.clearable) &&
> hover &&
<QTime model &&
:format24h="false" !$attrs.disable
:model-value="formatTime(value)" "
@update:model-value="onDateUpdate" @click="
> model = null;
<div class="row items-center justify-end q-gutter-sm"> isPopupOpen = false;
<QBtn "
:label="t('Cancel')" />
color="primary" <QIcon name="Schedule" class="cursor-pointer" />
flat </template>
v-close-popup <QMenu
/> transition-show="scale"
<QBtn transition-hide="scale"
label="Ok" v-model="isPopupOpen"
color="primary" anchor="bottom left"
flat self="top start"
@click="save" :no-focus="true"
v-close-popup >
/> <QTime
</div> :format24h="false"
</QTime> v-model="formattedTime"
</QPopupProxy> mask="HH:mm"
</QIcon> landscape
</template> now-btn
</QInput> />
</QMenu>
</QInput>
</div>
</template> </template>
<style lang="scss">
.vn-input-time.q-field--standard.q-field--readonly .q-field__control:before {
border-bottom-style: solid;
}
.vn-input-time.q-field--outlined.q-field--readonly .q-field__control:before {
border-style: solid;
}
</style>
<i18n>
es:
Cancel: Cancelar
</i18n>

View File

@ -46,8 +46,7 @@ let arrayData;
let store; let store;
let entity; let entity;
const isLoading = ref(false); const isLoading = ref(false);
const menuRef = ref({}); const isSameDataKey = computed(() => $props.dataKey === route.meta.moduleName);
defineExpose({ getData }); defineExpose({ getData });
onBeforeMount(async () => { onBeforeMount(async () => {
@ -59,10 +58,12 @@ onBeforeMount(async () => {
store = arrayData.store; store = arrayData.store;
entity = computed(() => (Array.isArray(store.data) ? store.data[0] : store.data)); entity = computed(() => (Array.isArray(store.data) ? store.data[0] : store.data));
// It enables to load data only once if the module is the same as the dataKey // It enables to load data only once if the module is the same as the dataKey
if ($props.dataKey !== route.meta.moduleName || !route.params.id) await getData(); if (!isSameDataKey.value || !route.params.id) await getData();
watch( watch(
() => [$props.url, $props.filter], () => [$props.url, $props.filter],
async () => await getData() async () => {
if (!isSameDataKey.value) await getData();
}
); );
}); });
@ -78,6 +79,19 @@ async function getData() {
isLoading.value = false; isLoading.value = false;
} }
} }
function getValueFromPath(path) {
if (!path) return;
const keys = path.toString().split('.');
let current = entity.value;
for (let i = 0; i < keys.length; i++) {
if (current[keys[i]] === undefined) return undefined;
else current = current[keys[i]];
}
return current;
}
const emit = defineEmits(['onFetch']); const emit = defineEmits(['onFetch']);
</script> </script>
@ -140,8 +154,8 @@ const emit = defineEmits(['onFetch']);
<QList dense> <QList dense>
<QItemLabel header class="ellipsis text-h5" :lines="1"> <QItemLabel header class="ellipsis text-h5" :lines="1">
<div class="title"> <div class="title">
<span v-if="$props.title" :title="$props.title"> <span v-if="$props.title" :title="getValueFromPath(title)">
{{ entity[title] ?? $props.title }} {{ getValueFromPath(title) ?? $props.title }}
</span> </span>
<slot v-else name="description" :entity="entity"> <slot v-else name="description" :entity="entity">
<span :title="entity.name"> <span :title="entity.name">
@ -152,7 +166,7 @@ const emit = defineEmits(['onFetch']);
</QItemLabel> </QItemLabel>
<QItem dense> <QItem dense>
<QItemLabel class="subtitle" caption> <QItemLabel class="subtitle" caption>
#{{ $props.subtitle ?? entity.id }} #{{ getValueFromPath(subtitle) ?? entity.id }}
</QItemLabel> </QItemLabel>
</QItem> </QItem>
</QList> </QList>

View File

@ -114,6 +114,7 @@ async function search(evt) {
store.userParamsChanged = true; store.userParamsChanged = true;
store.filter.skip = 0; store.filter.skip = 0;
store.skip = 0; store.skip = 0;
store.page = 1;
const { params: newParams } = await arrayData.addFilter({ params: userParams.value }); const { params: newParams } = await arrayData.addFilter({ params: userParams.value });
userParams.value = newParams; userParams.value = newParams;
@ -126,7 +127,8 @@ async function search(evt) {
async function reload() { async function reload() {
isLoading.value = true; isLoading.value = true;
const params = Object.values(userParams.value).filter((param) => param); const params = Object.values(userParams.value).filter((param) => param);
store.skip = 0;
store.page = 1;
await arrayData.fetch({ append: false }); await arrayData.fetch({ append: false });
if (!$props.showAll && !params.length) store.data = []; if (!$props.showAll && !params.length) store.data = [];
isLoading.value = false; isLoading.value = false;
@ -138,6 +140,7 @@ async function clearFilters() {
store.userParamsChanged = true; store.userParamsChanged = true;
store.filter.skip = 0; store.filter.skip = 0;
store.skip = 0; store.skip = 0;
store.page = 1;
// 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)

View File

@ -1,5 +1,5 @@
<script setup> <script setup>
import { ref, computed, onMounted } from 'vue'; import { ref, computed } from 'vue';
import { useSession } from 'src/composables/useSession'; import { useSession } from 'src/composables/useSession';
const $props = defineProps({ const $props = defineProps({
@ -28,21 +28,29 @@ const $props = defineProps({
const show = ref(false); const show = ref(false);
const token = useSession().getTokenMultimedia(); const token = useSession().getTokenMultimedia();
const timeStamp = ref(`timestamp=${Date.now()}`); const timeStamp = ref(`timestamp=${Date.now()}`);
const url = computed( import noImage from '/public/no-user.png';
() => import { useRole } from 'src/composables/useRole';
`/api/${$props.storage}/${$props.collection}/${$props.size}/${$props.id}/download?access_token=${token}&${timeStamp.value}` const url = computed(() => {
); const isEmployee = useRole().isEmployee();
return isEmployee
? `/api/${$props.storage}/${$props.collection}/${$props.size}/${$props.id}/download?access_token=${token}&${timeStamp.value}`
: noImage;
});
const reload = () => { const reload = () => {
timeStamp.value = `timestamp=${Date.now()}`; timeStamp.value = `timestamp=${Date.now()}`;
}; };
defineExpose({ defineExpose({
reload, reload,
}); });
onMounted(() => {});
</script> </script>
<template> <template>
<QImg :src="url" v-bind="$attrs" @click="show = !show" spinner-color="primary" /> <QImg
:class="{ zoomIn: $props.zoomSize }"
:src="url"
v-bind="$attrs"
@click="show = !show"
spinner-color="primary"
/>
<QDialog v-model="show" v-if="$props.zoomSize"> <QDialog v-model="show" v-if="$props.zoomSize">
<QImg <QImg
:src="url" :src="url"
@ -56,7 +64,9 @@ onMounted(() => {});
<style lang="scss" scoped> <style lang="scss" scoped>
.q-img { .q-img {
cursor: zoom-in; &.zoomIn {
cursor: zoom-in;
}
min-width: 50px; min-width: 50px;
} }
.rounded { .rounded {

View File

@ -104,6 +104,7 @@ async function search() {
([key, value]) => value && (props.staticParams || []).includes(key) ([key, value]) => value && (props.staticParams || []).includes(key)
); );
store.skip = 0; store.skip = 0;
store.page = 1;
if (props.makeFetch) if (props.makeFetch)
await arrayData.applyFilter({ await arrayData.applyFilter({

View File

@ -1,4 +1,4 @@
import { onMounted, ref, computed } from 'vue'; import { onMounted, computed } from 'vue';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import axios from 'axios'; import axios from 'axios';
import { useArrayDataStore } from 'stores/useArrayDataStore'; import { useArrayDataStore } from 'stores/useArrayDataStore';
@ -16,8 +16,6 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
const router = useRouter(); const router = useRouter();
let canceller = null; let canceller = null;
const page = ref(1);
onMounted(() => { onMounted(() => {
setOptions(); setOptions();
store.skip = 0; store.skip = 0;
@ -87,13 +85,13 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
} }
Object.assign(filter, store.userFilter, exprFilter); Object.assign(filter, store.userFilter, exprFilter);
Object.assign(store.filter, { ...filter, skip: store.skip }); Object.assign(store.filter, filter);
const params = { const params = { filter: store.filter };
filter: JSON.stringify(store.filter),
};
Object.assign(params, userParams); Object.assign(params, userParams);
params.filter.skip = store.skip;
params.filter = JSON.stringify(params.filter);
store.currentFilter = params; store.currentFilter = params;
store.isLoading = true; store.isLoading = true;
const response = await axios.get(store.url, { const response = await axios.get(store.url, {
@ -154,8 +152,7 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
store.userParams = userParams; store.userParams = userParams;
store.skip = 0; store.skip = 0;
store.filter.skip = 0; store.filter.skip = 0;
page.value = 1; store.page = 1;
await fetch({ append: false }); await fetch({ append: false });
return { filter, params }; return { filter, params };
} }
@ -187,10 +184,11 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
async function loadMore() { async function loadMore() {
if (!store.hasMoreData) return; if (!store.hasMoreData) return;
store.skip = store.limit * page.value; store.skip = store.limit * store.page;
page.value += 1; store.page += 1;
await fetch({ append: true }); await fetch({ append: true });
updateStateParams();
} }
async function refresh() { async function refresh() {

View File

@ -27,8 +27,12 @@ export function useRole() {
return false; return false;
} }
function isEmployee() {
return hasAny(['employee']);
}
return { return {
isEmployee,
fetch, fetch,
hasAny, hasAny,
state, state,

View File

@ -100,13 +100,143 @@ globals:
modes: Modes modes: Modes
zones: Zones zones: Zones
zonesList: Zones zonesList: Zones
deliveryList: Delivery days deliveryDays: Delivery days
upcomingList: Upcoming deliveries upcomingDeliveries: Upcoming deliveries
role: Role role: Role
alias: Alias alias: Alias
aliasUsers: Users aliasUsers: Users
subRoles: Subroles subRoles: Subroles
inheritedRoles: Inherited Roles inheritedRoles: Inherited Roles
customers: Customers
list: List
webPayments: Web Payments
extendedList: Extended list
notifications: Notifications
defaulter: Defaulter
customerCreate: New customer
fiscalData: Fiscal data
billingData: Billing data
consignees: Consignees
notes: Notes
credits: Credits
greuges: Greuges
balance: Balance
recoveries: Recoveries
webAccess: Web access
sms: Sms
creditManagement: Credit management
creditContracts: Credit contracts
creditOpinion: Credit opinion
others: Others
samples: Samples
consumption: Consumption
mandates: Mandates
contacts: Contacts
webPayment: Web payment
fileManagement: File management
unpaid: Unpaid
entries: Entries
buys: Buys
dms: File management
entryCreate: New entry
latestBuys: Latest buys
tickets: Tickets
ticketCreate: New Tickets
boxing: Boxing
sale: Sale
claims: Claims
claimCreate: New claim
lines: Lines
photos: Photos
development: Development
action: Action
invoiceOuts: Invoice out
negativeBases: Negative Bases
globalInvoicing: Global invoicing
invoiceOutCreate: Create invoice out
shelving: Shelving
shelvingList: Shelving List
shelvingCreate: New shelving
invoiceIns: Invoices In
invoiceInCreate: Create invoice in
vat: VAT
dueDay: Due day
intrastat: Intrastat
corrective: Corrective
order: Orders
orderList: List
orderCreate: New order
catalog: Catalog
volume: Volume
workers: Workers
workerCreate: New worker
department: Department
pda: PDA
pbx: Private Branch Exchange
calendar: Calendar
timeControl: Time control
locker: Locker
wagons: Wagons
wagonsList: Wagons List
wagonCreate: Create wagon
wagonEdit: Edit wagon
typesList: Types List
typeCreate: Create type
typeEdit: Edit type
wagonCounter: Trolley counter
roadmap: Roadmap
stops: Stops
routes: Routes
cmrsList: CMRs list
RouteList: List
routeCreate: New route
RouteRoadmap: Roadmaps
RouteRoadmapCreate: Create roadmap
autonomous: Autonomous
suppliers: Suppliers
supplier: Supplier
labeler: Labeler
supplierCreate: New supplier
accounts: Accounts
addresses: Addresses
agencyTerm: Agency agreement
travel: Travels
extraCommunity: Extra community
travelCreate: New travel
history: Log
thermographs: Thermograph
items: Items
diary: Diary
tags: Tags
create: Create
buyRequest: Buy requests
fixedPrice: Fixed prices
wasteBreakdown: Waste breakdown
itemCreate: New item
barcode: Barcodes
tax: Tax
botanical: Botanical
itemTypeCreate: New item type
family: Item Type
lastEntries: Last entries
itemType: Item type
monitors: Monitors
dashboard: Dashboard
users: Users
createTicket: Create ticket
ticketAdvance: Advance tickets
futureTickets: Future tickets
purchaseRequest: Purchase request
weeklyTickets: Weekly tickets
formation: Formation
locations: Locations
warehouses: Warehouses
roles: Roles
connections: Connections
acls: ACLs
mailForwarding: Mail forwarding
mailAlias: Mail alias
privileges: Privileges
created: Created created: Created
worker: Worker worker: Worker
now: Now now: Now
@ -148,40 +278,8 @@ verifyEmail:
verifyEmail: Email verification verifyEmail: Email verification
dashboard: dashboard:
pageTitles: pageTitles:
dashboard: Dashboard
customer: customer:
pageTitles:
customers: Customers
list: List
webPayments: Web Payments
extendedList: Extended list
notifications: Notifications
defaulter: Defaulter
customerCreate: New customer
summary: Summary
basicData: Basic data
fiscalData: Fiscal data
billingData: Billing data
consignees: Consignees
notes: Notes
credits: Credits
greuges: Greuges
balance: Balance
recoveries: Recoveries
webAccess: Web access
log: Log
sms: Sms
creditManagement: Credit management
creditContracts: Credit contracts
creditOpinion: Credit opinion
others: Others
samples: Samples
consumption: Consumption
mandates: Mandates
contacts: Contacts
webPayment: Web payment
fileManagement: File management
unpaid: Unpaid
list: list:
phone: Phone phone: Phone
email: Email email: Email
@ -311,17 +409,6 @@ customer:
hasCoreVnl: VNL core received hasCoreVnl: VNL core received
hasSepaVnl: VNL B2B received hasSepaVnl: VNL B2B received
entry: entry:
pageTitles:
entries: Entries
list: List
summary: Summary
basicData: Basic data
buys: Buys
notes: Notes
dms: File management
log: Log
entryCreate: New entry
latestBuys: Latest buys
list: list:
newEntry: New entry newEntry: New entry
landed: Landed landed: Landed
@ -526,18 +613,6 @@ ticket:
warehouse: Warehouse warehouse: Warehouse
agency: Agency agency: Agency
claim: claim:
pageTitles:
claims: Claims
list: List
claimCreate: New claim
summary: Summary
basicData: Basic Data
lines: Lines
photos: Photos
development: Development
log: Audit logs
notes: Notes
action: Action
list: list:
customer: Customer customer: Customer
assignedTo: Assigned assignedTo: Assigned
@ -601,14 +676,6 @@ claim:
noData: 'There are no images/videos, click here or drag and drop the file' noData: 'There are no images/videos, click here or drag and drop the file'
dragDrop: Drag and drop it here dragDrop: Drag and drop it here
invoiceOut: invoiceOut:
pageTitles:
invoiceOuts: Invoice out
list: List
negativeBases: Negative Bases
globalInvoicing: Global invoicing
invoiceOutCreate: Create invoice out
summary: Summary
basicData: Basic Data
list: list:
ref: Reference ref: Reference
issued: Issued issued: Issued
@ -676,13 +743,6 @@ invoiceOut:
errors: errors:
downloadCsvFailed: CSV download failed downloadCsvFailed: CSV download failed
shelving: shelving:
pageTitles:
shelving: Shelving
shelvingList: Shelving List
shelvingCreate: New shelving
summary: Summary
basicData: Basic Data
log: Logs
list: list:
parking: Parking parking: Parking
priority: Priority priority: Priority
@ -709,17 +769,6 @@ parking:
info: You can search by parking code info: You can search by parking code
label: Search parking... label: Search parking...
invoiceIn: invoiceIn:
pageTitles:
invoiceIns: Invoices In
list: List
invoiceInCreate: Create invoice in
summary: Summary
basicData: Basic data
vat: VAT
dueDay: Due day
intrastat: Intrastat
corrective: Corrective
log: Logs
list: list:
ref: Reference ref: Reference
supplier: Supplier supplier: Supplier
@ -770,15 +819,6 @@ invoiceIn:
stems: Stems stems: Stems
country: Country country: Country
order: order:
pageTitles:
order: Orders
orderList: List
orderCreate: New order
summary: Summary
basicData: Basic Data
catalog: Catalog
volume: Volume
lines: Lines
field: field:
salesPersonFk: Sales Person salesPersonFk: Sales Person
clientFk: Client clientFk: Client
@ -854,7 +894,6 @@ worker:
timeControl: Time control timeControl: Time control
locker: Locker locker: Locker
balance: Balance balance: Balance
formation: Formation
list: list:
name: Name name: Name
email: Email email: Email
@ -943,15 +982,6 @@ worker:
credit: Have credit: Have
concept: Concept concept: Concept
wagon: wagon:
pageTitles:
wagons: Wagons
wagonsList: Wagons List
wagonCreate: Create wagon
wagonEdit: Edit wagon
typesList: Types List
typeCreate: Create type
typeEdit: Edit type
wagonCounter: Trolley counter
type: type:
name: Name name: Name
submit: Submit submit: Submit
@ -980,31 +1010,7 @@ wagon:
minHeightBetweenTrays: 'The minimum height between trays is ' minHeightBetweenTrays: 'The minimum height between trays is '
maxWagonHeight: 'The maximum height of the wagon is ' maxWagonHeight: 'The maximum height of the wagon is '
uncompleteTrays: There are incomplete trays uncompleteTrays: There are incomplete trays
route/roadmap:
pageTitles:
roadmap: Roadmap
summary: Summary
basicData: Basic Data
stops: Stops
roadmap:
pageTitles:
roadmap: Roadmap
summary: Summary
basicData: Basic Data
stops: Stops
route: route:
pageTitles:
routes: Routes
cmrsList: CMRs list
RouteList: List
routeCreate: New route
basicData: Basic Data
summary: Summary
RouteRoadmap: Roadmaps
RouteRoadmapCreate: Create roadmap
tickets: Tickets
log: Log
autonomous: Autonomous
cmr: cmr:
list: list:
results: results results: results
@ -1032,22 +1038,6 @@ route:
volume: Volume volume: Volume
finished: Finished finished: Finished
supplier: supplier:
pageTitles:
suppliers: Suppliers
supplier: Supplier
list: List
supplierCreate: New supplier
summary: Summary
basicData: Basic data
fiscalData: Fiscal data
billingData: Billing data
log: Log
accounts: Accounts
contacts: Contacts
addresses: Addresses
consumption: Consumption
agencyTerm: Agency agreement
dms: File management
list: list:
payMethod: Pay method payMethod: Pay method
payDeadline: Pay deadline payDeadline: Pay deadline
@ -1139,15 +1129,6 @@ supplier:
date: Date date: Date
reference: Reference reference: Reference
travel: travel:
pageTitles:
travel: Travels
list: List
summary: Summary
extraCommunity: Extra community
travelCreate: New travel
basicData: Basic data
history: Log
thermographs: Thermograph
summary: summary:
confirmed: Confirmed confirmed: Confirmed
entryId: Entry Id entryId: Entry Id
@ -1194,24 +1175,6 @@ travel:
travelFileDescription: 'Travel id { travelId }' travelFileDescription: 'Travel id { travelId }'
file: File file: File
item: item:
pageTitles:
items: Items
list: List
diary: Diary
tags: Tags
create: Create
buyRequest: Buy requests
fixedPrice: Fixed prices
wasteBreakdown: Waste breakdown
itemCreate: New item
barcode: Barcodes
tax: Tax
log: Log
botanical: Botanical
shelving: Shelving
itemTypeCreate: New item type
family: Item Type
lastEntries: Last entries
descriptor: descriptor:
item: Item item: Item
buyer: Buyer buyer: Buyer
@ -1297,22 +1260,6 @@ item:
minSalesQuantity: 'Cantidad mínima de venta' minSalesQuantity: 'Cantidad mínima de venta'
genus: 'Genus' genus: 'Genus'
specie: 'Specie' specie: 'Specie'
item/itemType:
pageTitles:
itemType: Item type
basicData: Basic data
summary: Summary
monitor:
pageTitles:
monitors: Monitors
list: List
zone:
pageTitles:
zones: Zones
zonesList: Zones
deliveryList: Delivery days
upcomingList: Upcoming deliveries
components: components:
topbar: {} topbar: {}
itemsFilterPanel: itemsFilterPanel:

View File

@ -100,14 +100,144 @@ globals:
modes: Modos modes: Modos
zones: Zonas zones: Zonas
zonesList: Zonas zonesList: Zonas
deliveryList: Días de entrega deliveryDays: Días de entrega
upcomingList: Próximos repartos upcomingDeliveries: Próximos repartos
role: Role role: Role
alias: Alias alias: Alias
aliasUsers: Usuarios aliasUsers: Usuarios
subRoles: Subroles subRoles: Subroles
inheritedRoles: Roles heredados inheritedRoles: Roles heredados
customers: Clientes
customerCreate: Nuevo cliente
list: Listado
webPayments: Pagos Web
extendedList: Listado extendido
notifications: Notificaciones
defaulter: Morosos
createCustomer: Crear cliente
fiscalData: Datos fiscales
billingData: Forma de pago
consignees: Consignatarios
notes: Notas
credits: Créditos
greuges: Greuges
balance: Balance
recoveries: Recobros
webAccess: Acceso web
sms: Sms
creditManagement: Gestión de crédito
creditContracts: Contratos de crédito
creditOpinion: Opinión de crédito
others: Otros
samples: Plantillas
consumption: Consumo
mandates: Mandatos
contacts: Contactos
webPayment: Pago web
fileManagement: Gestión documental
unpaid: Impago
entries: Entradas
buys: Compras
dms: Gestión documental
entryCreate: Nueva entrada
latestBuys: Últimas compras
tickets: Tickets
ticketCreate: Nuevo ticket
boxing: Encajado
sale: Lineas del pedido
claims: Reclamaciones
claimCreate: Crear reclamación
lines: Líneas
development: Trazabilidad
photos: Fotos
action: Acción
invoiceOuts: Fact. emitidas
negativeBases: Bases Negativas
globalInvoicing: Facturación global
invoiceOutCreate: Crear fact. emitida
order: Cesta
orderList: Listado
orderCreate: Nueva orden
catalog: Catálogo
volume: Volumen
shelving: Carros
shelvingList: Listado de carros
shelvingCreate: Nuevo carro
invoiceIns: Fact. recibidas
invoiceInCreate: Crear fact. recibida
vat: IVA
labeler: Etiquetas
dueDay: Vencimiento
intrastat: Intrastat
corrective: Rectificativa
workers: Trabajadores workers: Trabajadores
workerCreate: Nuevo trabajador
department: Departamentos
pda: PDA
pbx: Centralita
calendar: Calendario
timeControl: Control de horario
locker: Taquilla
wagons: Vagones
wagonsList: Listado vagones
wagonCreate: Crear tipo
wagonEdit: Editar tipo
typesList: Listado tipos
typeCreate: Crear tipo
typeEdit: Editar tipo
wagonCounter: Contador de carros
roadmap: Troncales
stops: Paradas
routes: Rutas
cmrsList: Listado de CMRs
RouteList: Listado
routeCreate: Nueva ruta
RouteRoadmap: Troncales
RouteRoadmapCreate: Crear troncal
autonomous: Autónomos
suppliers: Proveedores
supplier: Proveedor
supplierCreate: Nuevo proveedor
accounts: Cuentas
addresses: Direcciones
agencyTerm: Acuerdo agencia
travel: Envíos
create: Crear
extraCommunity: Extra comunitarios
travelCreate: Nuevo envío
history: Historial
thermographs: Termógrafos
items: Artículos
diary: Histórico
tags: Etiquetas
fixedPrice: Precios fijados
buyRequest: Peticiones de compra
wasteBreakdown: Deglose de mermas
itemCreate: Nuevo artículo
tax: 'IVA'
botanical: 'Botánico'
barcode: 'Código de barras'
itemTypeCreate: Nueva familia
family: Familia
lastEntries: Últimas entradas
itemType: Familia
monitors: Monitores
dashboard: Tablón
users: Usuarios
createTicket: Crear ticket
ticketAdvance: Adelantar tickets
futureTickets: Tickets a futuro
purchaseRequest: Petición de compra
weeklyTickets: Tickets programados
formation: Formación
locations: Ubicaciones
warehouses: Almacenes
roles: Roles
connections: Conexiones
acls: ACLs
mailForwarding: Reenvío de correo
mailAlias: Alias de correo
privileges: Privilegios
created: Fecha creación created: Fecha creación
worker: Trabajador worker: Trabajador
now: Ahora now: Ahora
@ -147,41 +277,8 @@ verifyEmail:
verifyEmail: Verificación de correo verifyEmail: Verificación de correo
dashboard: dashboard:
pageTitles: pageTitles:
dashboard: Tablón
customer: customer:
pageTitles:
customers: Clientes
customerCreate: Nuevo cliente
list: Listado
webPayments: Pagos Web
extendedList: Listado extendido
notifications: Notificaciones
defaulter: Morosos
createCustomer: Crear cliente
summary: Resumen
basicData: Datos básicos
fiscalData: Datos fiscales
billingData: Forma de pago
consignees: Consignatarios
notes: Notas
credits: Créditos
greuges: Greuges
balance: Balance
recoveries: Recobros
webAccess: Acceso web
log: Historial
sms: Sms
creditManagement: Gestión de crédito
creditContracts: Contratos de crédito
creditOpinion: Opinión de crédito
others: Otros
samples: Plantillas
consumption: Consumo
mandates: Mandatos
contacts: Contactos
webPayment: Pago web
fileManagement: Gestión documental
unpaid: Impago
list: list:
phone: Teléfono phone: Teléfono
email: Email email: Email
@ -310,17 +407,6 @@ customer:
hasCoreVnl: Recibido core VNL hasCoreVnl: Recibido core VNL
hasSepaVnl: Recibido B2B VNL hasSepaVnl: Recibido B2B VNL
entry: entry:
pageTitles:
entries: Entradas
list: Listado
summary: Resumen
basicData: Datos básicos
buys: Compras
notes: Notas
dms: Gestión documental
log: Historial
entryCreate: Nueva entrada
latestBuys: Últimas compras
list: list:
newEntry: Nueva entrada newEntry: Nueva entrada
landed: F. entrega landed: F. entrega
@ -525,18 +611,6 @@ ticket:
warehouse: Almacén warehouse: Almacén
agency: Agencia agency: Agencia
claim: claim:
pageTitles:
claims: Reclamaciones
list: Listado
claimCreate: Crear reclamación
summary: Resumen
basicData: Datos básicos
lines: Líneas
development: Trazabilidad
photos: Fotos
log: Historial
notes: Notas
action: Acción
list: list:
customer: Cliente customer: Cliente
assignedTo: Asignada a assignedTo: Asignada a
@ -600,14 +674,6 @@ claim:
noData: No hay imágenes/videos haz click aquí o arrastra y suelta el archivo noData: No hay imágenes/videos haz click aquí o arrastra y suelta el archivo
dragDrop: Arrástralo y sueltalo aquí dragDrop: Arrástralo y sueltalo aquí
invoiceOut: invoiceOut:
pageTitles:
invoiceOuts: Fact. emitidas
list: Listado
negativeBases: Bases Negativas
globalInvoicing: Facturación global
invoiceOutCreate: Crear fact. emitida
summary: Resumen
basicData: Datos básicos
list: list:
ref: Referencia ref: Referencia
issued: Fecha emisión issued: Fecha emisión
@ -675,15 +741,6 @@ invoiceOut:
errors: errors:
downloadCsvFailed: Error al descargar CSV downloadCsvFailed: Error al descargar CSV
order: order:
pageTitles:
order: Cesta
orderList: Listado
orderCreate: Nueva orden
summary: Resumen
basicData: Datos básicos
catalog: Catálogo
volume: Volumen
lines: Líneas
field: field:
salesPersonFk: Comercial salesPersonFk: Comercial
clientFk: Cliente clientFk: Cliente
@ -725,13 +782,6 @@ order:
price: Precio price: Precio
amount: Monto amount: Monto
shelving: shelving:
pageTitles:
shelving: Carros
shelvingList: Listado de carros
shelvingCreate: Nuevo carro
summary: Resumen
basicData: Datos básicos
log: Historial
list: list:
parking: Parking parking: Parking
priority: Prioridad priority: Prioridad
@ -757,17 +807,6 @@ parking:
info: Puedes buscar por código de parking info: Puedes buscar por código de parking
label: Buscar parking... label: Buscar parking...
invoiceIn: invoiceIn:
pageTitles:
invoiceIns: Fact. recibidas
list: Listado
invoiceInCreate: Crear fact. recibida
summary: Resumen
basicData: Datos básicos
vat: IVA
dueDay: Vencimiento
intrastat: Intrastat
corrective: Rectificativa
log: Historial
list: list:
ref: Referencia ref: Referencia
supplier: Proveedor supplier: Proveedor
@ -850,7 +889,6 @@ worker:
timeControl: Control de horario timeControl: Control de horario
locker: Taquilla locker: Taquilla
balance: Balance balance: Balance
formation: Formación
list: list:
name: Nombre name: Nombre
email: Email email: Email
@ -930,15 +968,6 @@ worker:
credit: Haber credit: Haber
concept: Concepto concept: Concepto
wagon: wagon:
pageTitles:
wagons: Vagones
wagonsList: Listado vagones
wagonCreate: Crear tipo
wagonEdit: Editar tipo
typesList: Listado tipos
typeCreate: Crear tipo
typeEdit: Editar tipo
wagonCounter: Contador de carros
type: type:
name: Nombre name: Nombre
submit: Guardar submit: Guardar
@ -967,31 +996,7 @@ wagon:
minHeightBetweenTrays: 'La distancia mínima entre bandejas es ' minHeightBetweenTrays: 'La distancia mínima entre bandejas es '
maxWagonHeight: 'La altura máxima del vagón es ' maxWagonHeight: 'La altura máxima del vagón es '
uncompleteTrays: Hay bandejas sin completar uncompleteTrays: Hay bandejas sin completar
route/roadmap:
pageTitles:
roadmap: Troncales
summary: Resumen
basicData: Datos básicos
stops: Paradas
roadmap:
pageTitles:
roadmap: Troncales
summary: Resumen
basicData: Datos básicos
stops: Paradas
route: route:
pageTitles:
routes: Rutas
cmrsList: Listado de CMRs
RouteList: Listado
routeCreate: Nueva ruta
basicData: Datos básicos
summary: Resumen
RouteRoadmap: Troncales
RouteRoadmapCreate: Crear troncal
tickets: Tickets
log: Historial
autonomous: Autónomos
cmr: cmr:
list: list:
results: resultados results: resultados
@ -1019,22 +1024,6 @@ route:
volume: Volumen volume: Volumen
finished: Finalizada finished: Finalizada
supplier: supplier:
pageTitles:
suppliers: Proveedores
supplier: Proveedor
list: Listado
supplierCreate: Nuevo proveedor
summary: Resumen
basicData: Datos básicos
fiscalData: Datos fiscales
billingData: Forma de pago
log: Historial
accounts: Cuentas
contacts: Contactos
addresses: Direcciones
consumption: Consumo
agencyTerm: Acuerdo agencia
dms: Gestión documental
list: list:
payMethod: Método de pago payMethod: Método de pago
payDeadline: Plazo de pago payDeadline: Plazo de pago
@ -1126,16 +1115,6 @@ supplier:
date: Fecha date: Fecha
reference: Referencia reference: Referencia
travel: travel:
pageTitles:
travel: Envíos
list: Listado
create: Crear
summary: Resumen
extraCommunity: Extra comunitarios
travelCreate: Nuevo envío
basicData: Datos básicos
history: Historial
thermographs: Termógrafos
summary: summary:
confirmed: Confirmado confirmed: Confirmado
entryId: Id entrada entryId: Id entrada
@ -1182,24 +1161,6 @@ travel:
travelFileDescription: 'Id envío { travelId }' travelFileDescription: 'Id envío { travelId }'
file: Fichero file: Fichero
item: item:
pageTitles:
items: Artículos
list: Listado
diary: Histórico
tags: Etiquetas
fixedPrice: Precios fijados
buyRequest: Peticiones de compra
wasteBreakdown: Deglose de mermas
itemCreate: Nuevo artículo
basicData: 'Datos básicos'
tax: 'IVA'
botanical: 'Botánico'
barcode: 'Código de barras'
log: Historial
shelving: Carros
itemTypeCreate: Nueva familia
family: Familia
lastEntries: Últimas entradas
descriptor: descriptor:
item: Artículo item: Artículo
buyer: Comprador buyer: Comprador
@ -1285,27 +1246,6 @@ item:
achieved: 'Conseguido' achieved: 'Conseguido'
concept: 'Concepto' concept: 'Concepto'
state: 'Estado' state: 'Estado'
item/itemType:
pageTitles:
itemType: Familia
basicData: Datos básicos
summary: Resumen
zone:
pageTitles:
zones: Zonas
list: Zonas
deliveryList: Días de entrega
upcomingList: Próximos repartos
role:
pageTitles:
zones: Zonas
list: Zonas
deliveryList: Días de entrega
upcomingList: Próximos repartos
monitor:
pageTitles:
monitors: Monitores
list: Listado
components: components:
topbar: {} topbar: {}
itemsFilterPanel: itemsFilterPanel:

View File

@ -56,8 +56,7 @@ onMounted(async () => {
:url="`Claims/${entityId}`" :url="`Claims/${entityId}`"
:filter="filter" :filter="filter"
module="Claim" module="Claim"
:title="data.title" title="client.name"
:subtitle="data.subtitle"
@on-fetch="setData" @on-fetch="setData"
data-key="Claim" data-key="Claim"
> >

View File

@ -224,7 +224,7 @@ async function changeState(value) {
<QCard class="vn-one"> <QCard class="vn-one">
<VnTitle <VnTitle
:url="`#/claim/${entityId}/basic-data`" :url="`#/claim/${entityId}/basic-data`"
:text="t('claim.pageTitles.basicData')" :text="t('globals.pageTitles.basicData')"
/> />
<VnLv <VnLv
:label="t('claim.summary.created')" :label="t('claim.summary.created')"

View File

@ -0,0 +1,120 @@
<script setup>
import { computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { QBtn } from 'quasar';
import VnPaginate from 'src/components/ui/VnPaginate.vue';
import { usePrintService } from 'composables/usePrintService';
const { openReport } = usePrintService();
const route = useRoute();
const { t } = useI18n();
const $props = defineProps({
id: {
type: String,
required: false,
default: null,
},
});
const entityId = computed(() => $props.id || route.params.id);
const entriesTableColumns = computed(() => [
{
align: 'left',
name: 'itemFk',
field: 'itemFk',
label: t('globals.id'),
},
{
align: 'left',
name: 'item',
label: t('entry.summary.item'),
field: (row) => row.item.name,
},
{
align: 'left',
name: 'packagingFk',
label: t('entry.summary.package'),
field: 'packagingFk',
},
{
align: 'left',
name: 'stickers',
label: t('entry.summary.stickers'),
field: 'stickers',
},
{
align: 'left',
name: 'packing',
label: t('entry.summary.packing'),
field: 'packing',
},
{
align: 'left',
name: 'grouping',
label: t('entry.summary.grouping'),
field: 'grouping',
},
]);
</script>
<template>
<QDialog ref="dialogRef">
<QCard style="min-width: 800px">
<QCardSection class="row items-center q-pb-none">
<QAvatar
:icon="icon"
color="primary"
text-color="white"
size="xl"
v-if="icon"
/>
<span class="text-h6 text-grey">{{ title }}</span>
<QSpace />
<QBtn icon="close" :disable="isLoading" flat round dense v-close-popup />
</QCardSection>
<QCardActions align="right">
<QBtn
:label="t('Print buys')"
color="primary"
icon="print"
:loading="isLoading"
@click="openReport(`Entries/${entityId}/buy-label`)"
unelevated
autofocus
/>
</QCardActions>
<QCardSection class="row items-center">
<VnPaginate
ref="entryBuysPaginateRef"
:limit="0"
data-key="EntryBuys"
:url="`Entries/${entityId}/getBuys`"
auto-load
>
<template #body="{ rows }">
<QTable
:rows="rows"
:columns="entriesTableColumns"
row-key="id"
flat
dense
class="q-ml-lg"
:grid="$q.screen.lt.md"
:no-data-label="t('globals.noResults')"
>
<template #body="props">
<QTr>
<QTd v-for="col in props.cols" :key="col.name">
{{ col.value }}
</QTd>
</QTr>
</template>
</QTable>
</template>
</VnPaginate>
</QCardSection>
</QCard>
</QDialog>
</template>

View File

@ -0,0 +1,106 @@
<script setup>
import { computed, onMounted } from 'vue';
import { useI18n } from 'vue-i18n';
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
import { useStateStore } from 'stores/useStateStore';
import { toDate } from 'src/filters/index';
import { useQuasar } from 'quasar';
import EntryBuysTableDialog from './EntryBuysTableDialog.vue';
import VnTable from 'components/VnTable/VnTable.vue';
const stateStore = useStateStore();
const { t } = useI18n();
const quasar = useQuasar();
onMounted(async () => {
stateStore.rightDrawer = true;
});
const columns = computed(() => [
{
align: 'left',
name: 'id',
label: t('customer.extendedList.tableVisibleColumns.id'),
chip: {
condition: () => true,
},
isId: true,
isTitle: false,
},
{
align: 'left',
label: t('shipped'),
name: 'shipped',
isTitle: false,
create: true,
cardVisible: true,
format: ({ shipped }) => toDate(shipped),
},
{
align: 'left',
label: t('landed'),
name: 'landed',
isTitle: false,
create: true,
cardVisible: false,
format: ({ landed }) => toDate(landed),
},
{
align: 'left',
label: t('globals.wareHouseIn'),
name: 'warehouseInName',
isTitle: false,
cardVisible: true,
create: false,
},
{
align: 'right',
name: 'tableActions',
computed,
actions: [
{
title: t('printBuys'),
icon: 'print',
action: (row) => printBuys(row.id),
},
],
},
]);
const printBuys = (rowId) => {
quasar.dialog({
component: EntryBuysTableDialog,
componentProps: {
id: rowId,
},
});
};
</script>
<template>
<VnSearchbar
data-key="EntryList"
url="Entries/filter"
:label="t('Search entries')"
:info="t('You can search by entry reference')"
/>
<QPage class="column items-center q-pa-md">
<div class="vn-card-list">
<VnTable
ref="myEntriesRef"
data-key="myEntriesList"
url="Entries/filter"
:order="['landed DESC', 'id DESC']"
:columns="columns"
default-mode="card"
auto-load
>
</VnTable>
</div>
</QPage>
</template>
<i18n>
es:
Search entries: Buscar entradas
You can search by entry reference: Puedes buscar por referencia de la entrada
</i18n>

View File

@ -8,3 +8,4 @@ entryFilter:
reference: Reference reference: Reference
landed: Landed landed: Landed
shipped: Shipped shipped: Shipped
printBuys: Print buys

View File

@ -1,5 +1,6 @@
Search entries: Buscar entradas Search entries: Buscar entradas
You can search by entry reference: Puedes buscar por referencia de la entrada You can search by entry reference: Puedes buscar por referencia de la entrada
entryList: entryList:
list: list:
inventoryEntry: Es inventario inventoryEntry: Es inventario
@ -11,3 +12,4 @@ entryFilter:
landed: F. llegada landed: F. llegada
shipped: F. salida shipped: F. salida
Print buys: Imprimir etiquetas

View File

@ -209,7 +209,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
<QCardSection class="q-pa-none"> <QCardSection class="q-pa-none">
<VnTitle <VnTitle
:url="getLink('basic-data')" :url="getLink('basic-data')"
:text="t('invoiceIn.pageTitles.basicData')" :text="t('globals.pageTitles.basicData')"
/> />
</QCardSection> </QCardSection>
<VnLv <VnLv
@ -240,7 +240,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
<QCardSection class="q-pa-none"> <QCardSection class="q-pa-none">
<VnTitle <VnTitle
:url="getLink('basic-data')" :url="getLink('basic-data')"
:text="t('invoiceIn.pageTitles.basicData')" :text="t('globals.pageTitles.basicData')"
/> />
</QCardSection> </QCardSection>
<VnLv <VnLv
@ -265,7 +265,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
<QCardSection class="q-pa-none"> <QCardSection class="q-pa-none">
<VnTitle <VnTitle
:url="getLink('basic-data')" :url="getLink('basic-data')"
:text="t('invoiceIn.pageTitles.basicData')" :text="t('globals.pageTitles.basicData')"
/> />
</QCardSection> </QCardSection>
<VnLv <VnLv
@ -289,7 +289,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
<QCardSection class="q-pa-none"> <QCardSection class="q-pa-none">
<VnTitle <VnTitle
:url="getLink('basic-data')" :url="getLink('basic-data')"
:text="t('invoiceIn.pageTitles.basicData')" :text="t('globals.pageTitles.basicData')"
/> />
</QCardSection> </QCardSection>
<QCardSection class="q-pa-none"> <QCardSection class="q-pa-none">

View File

@ -200,16 +200,10 @@ onUnmounted(() => (stateStore.rightDrawer = false));
<VnInputDate <VnInputDate
:label="t('lastEntries.since')" :label="t('lastEntries.since')"
dense dense
emit-date-format
v-model="from" v-model="from"
class="q-mr-lg" class="q-mr-lg"
/> />
<VnInputDate <VnInputDate :label="t('lastEntries.to')" dense v-model="to" />
:label="t('lastEntries.to')"
dense
emit-date-format
v-model="to"
/>
</div> </div>
<QSpace /> <QSpace />
<div id="st-actions"></div> <div id="st-actions"></div>

View File

@ -192,7 +192,6 @@ const decrement = (paramsObj, key) => {
v-model="params.from" v-model="params.from"
@update:model-value="searchFn()" @update:model-value="searchFn()"
is-outlined is-outlined
emit-date-format
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>
@ -203,7 +202,6 @@ const decrement = (paramsObj, key) => {
v-model="params.to" v-model="params.to"
@update:model-value="searchFn()" @update:model-value="searchFn()"
is-outlined is-outlined
emit-date-format
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>

View File

@ -169,7 +169,6 @@ const columns = computed(() => [
<VnInputDate <VnInputDate
:label="t('salesClientsTable.from')" :label="t('salesClientsTable.from')"
dense dense
emit-date-format
v-model="from" v-model="from"
class="q-mr-lg" class="q-mr-lg"
style="width: 150px" style="width: 150px"
@ -177,7 +176,6 @@ const columns = computed(() => [
<VnInputDate <VnInputDate
:label="t('salesClientsTable.to')" :label="t('salesClientsTable.to')"
dense dense
emit-date-format
v-model="to" v-model="to"
style="width: 150px" style="width: 150px"
/> />

View File

@ -2,7 +2,6 @@
import VnCard from 'components/common/VnCard.vue'; import VnCard from 'components/common/VnCard.vue';
import OrderDescriptor from 'pages/Order/Card/OrderDescriptor.vue'; import OrderDescriptor from 'pages/Order/Card/OrderDescriptor.vue';
import OrderFilter from './OrderFilter.vue'; import OrderFilter from './OrderFilter.vue';
import OrderSearchbar from './OrderSearchbar.vue';
</script> </script>
<template> <template>
<VnCard <VnCard
@ -11,9 +10,7 @@ import OrderSearchbar from './OrderSearchbar.vue';
:descriptor="OrderDescriptor" :descriptor="OrderDescriptor"
:filter-panel="OrderFilter" :filter-panel="OrderFilter"
search-data-key="OrderList" search-data-key="OrderList"
> searchbar-label="Search order"
<template #searchbar> searchbar-info="ypu can search by order id or name"
<OrderSearchbar /> />
</template>
</VnCard>
</template> </template>

View File

@ -37,6 +37,10 @@ const selectedOrder = ref(null);
const selectedOrderField = ref(null); const selectedOrderField = ref(null);
const moreFields = ref([]); const moreFields = ref([]);
const moreFieldsOrder = ref([]); const moreFieldsOrder = ref([]);
const selectedTag = ref(null);
const tagValues = ref([{}]);
const tagOptions = ref([]);
const createValue = (val, done) => { const createValue = (val, done) => {
if (val.length > 2) { if (val.length > 2) {
if (!tagOptions.value.includes(val)) { if (!tagOptions.value.includes(val)) {
@ -95,10 +99,6 @@ function exprBuilder(param, value) {
} }
} }
const selectedTag = ref(null);
const tagValues = ref([{}]);
const tagOptions = ref([]);
const applyTagFilter = (params, search) => { const applyTagFilter = (params, search) => {
if (!tagValues.value?.length) { if (!tagValues.value?.length) {
params.tagGroups = null; params.tagGroups = null;
@ -139,34 +139,22 @@ const onOrderChange = (value, params) => {
}; };
const onOrderFieldChange = (value, params) => { const onOrderFieldChange = (value, params) => {
const tagObj = JSON.parse(params.orderBy); // esto donde va const tagObj = JSON.parse(params.orderBy);
const fields = {
Relevancy: (value) => value + ' DESC, name',
ColorAndPrice: 'showOrder, price',
Name: 'name',
Price: 'price',
};
let tagField = fields[value];
if (!tagField) return;
if (typeof tagField === 'function') tagField = tagField(value);
tagObj.field = tagField;
params.orderBy = JSON.stringify(tagObj);
switch (value) { switch (value) {
case 'Relevancy': case 'Relevancy':
tagObj.field = value + ' DESC, name'; tagObj.name = value + ' DESC, name';
params.orderBy = JSON.stringify(tagObj); params.orderBy = JSON.stringify(tagObj);
break; break;
case 'ColorAndPrice': case 'ColorAndPrice':
tagObj.field = 'showOrder, price'; tagObj.name = 'showOrder, price';
params.orderBy = JSON.stringify(tagObj); params.orderBy = JSON.stringify(tagObj);
break; break;
case 'Name': case 'Name':
tagObj.field = 'name'; tagObj.name = 'name';
params.orderBy = JSON.stringify(tagObj); params.orderBy = JSON.stringify(tagObj);
break; break;
case 'Price': case 'Price':
tagObj.field = 'price'; tagObj.name = 'price';
params.orderBy = JSON.stringify(tagObj); params.orderBy = JSON.stringify(tagObj);
break; break;
} }
@ -308,6 +296,7 @@ const useLang = (values) => {
v-model="selectedOrder" v-model="selectedOrder"
:options="moreFields" :options="moreFields"
option-label="label" option-label="label"
option-value="way"
dense dense
outlined outlined
rounded rounded

View File

@ -27,7 +27,7 @@ const dialog = ref(null);
<div class="container order-catalog-item overflow-hidden"> <div class="container order-catalog-item overflow-hidden">
<QCard class="card shadow-6"> <QCard class="card shadow-6">
<div class="img-wrapper"> <div class="img-wrapper">
<VnImg :id="item.id" class="image" /> <VnImg :id="item.id" zoom-size="lg" class="image" />
<div v-if="item.hex" class="item-color-container"> <div v-if="item.hex" class="item-color-container">
<div <div
class="item-color" class="item-color"

View File

@ -7,6 +7,8 @@ import VnLv from 'components/ui/VnLv.vue';
import CardSummary from 'components/ui/CardSummary.vue'; import CardSummary from 'components/ui/CardSummary.vue';
import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue'; import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue';
import FetchedTags from 'components/ui/FetchedTags.vue'; import FetchedTags from 'components/ui/FetchedTags.vue';
import VnTitle from 'src/components/common/VnTitle.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute(); const route = useRoute();
@ -62,6 +64,10 @@ const detailsColumns = ref([
</template> </template>
<template #body="{ entity }"> <template #body="{ entity }">
<QCard class="vn-one"> <QCard class="vn-one">
<VnTitle
:url="`#/order/${entity.id}/basic-data`"
:text="t('globals.pageTitles.basicData')"
/>
<VnLv label="ID" :value="entity.id" /> <VnLv label="ID" :value="entity.id" />
<VnLv :label="t('order.summary.nickname')" dash> <VnLv :label="t('order.summary.nickname')" dash>
<template #value> <template #value>
@ -81,6 +87,10 @@ const detailsColumns = ref([
/> />
</QCard> </QCard>
<QCard class="vn-one"> <QCard class="vn-one">
<VnTitle
:url="`#/order/${entity.id}/basic-data`"
:text="t('globals.pageTitles.basicData')"
/>
<VnLv <VnLv
:label="t('order.summary.created')" :label="t('order.summary.created')"
:value="toDateHourMinSec(entity?.created)" :value="toDateHourMinSec(entity?.created)"
@ -116,14 +126,13 @@ const detailsColumns = ref([
/> />
</QCard> </QCard>
<QCard class="vn-one"> <QCard class="vn-one">
<p class="header"> <VnTitle :text="t('globals.pageTitles.notes')" />
{{ t('order.summary.notes') }}
</p>
<p v-if="entity?.note" class="no-margin"> <p v-if="entity?.note" class="no-margin">
{{ entity?.note }} {{ entity?.note }}
</p> </p>
</QCard> </QCard>
<QCard class="vn-one"> <QCard class="vn-one">
<VnTitle :text="t('order.summary.total')" />
<VnLv> <VnLv>
<template #label> <template #label>
<span class="text-h6">{{ t('order.summary.subtotal') }}</span> <span class="text-h6">{{ t('order.summary.subtotal') }}</span>
@ -152,9 +161,7 @@ const detailsColumns = ref([
</VnLv> </VnLv>
</QCard> </QCard>
<QCard> <QCard>
<p class="header"> <VnTitle :text="t('order.summary.details')" />
{{ t('order.summary.details') }}
</p>
<QTable :columns="detailsColumns" :rows="entity?.rows" flat> <QTable :columns="detailsColumns" :rows="entity?.rows" flat>
<template #header="props"> <template #header="props">
<QTr :props="props"> <QTr :props="props">
@ -168,7 +175,10 @@ const detailsColumns = ref([
<template #body="props"> <template #body="props">
<QTr :props="props"> <QTr :props="props">
<QTd key="item" :props="props" class="item"> <QTd key="item" :props="props" class="item">
{{ props.row.item?.id }} <span class="link">
{{ props.row.item?.id }}
<ItemDescriptorProxy :id="props.row.item?.id" />
</span>
</QTd> </QTd>
<QTd key="description" :props="props" class="description"> <QTd key="description" :props="props" class="description">
<div class="name"> <div class="name">

View File

@ -70,6 +70,7 @@ function extractValueTags(items) {
:user-params="catalogParams" :user-params="catalogParams"
auto-load auto-load
@on-fetch="extractTags" @on-fetch="extractTags"
:update-router="false"
> >
<template #body="{ rows }"> <template #body="{ rows }">
<div class="catalog-list"> <div class="catalog-list">

View File

@ -9,7 +9,7 @@ import WorkerDescriptorProxy from 'pages/Worker/Card/WorkerDescriptorProxy.vue';
import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue'; import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue';
import VnPaginate from 'components/ui/VnPaginate.vue'; import VnPaginate from 'components/ui/VnPaginate.vue';
import VnLv from 'components/ui/VnLv.vue'; import VnLv from 'components/ui/VnLv.vue';
import OrderSearchbar from 'pages/Order/Card/OrderSearchbar.vue'; import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
import OrderFilter from 'pages/Order/Card/OrderFilter.vue'; import OrderFilter from 'pages/Order/Card/OrderFilter.vue';
import OrderSummary from 'pages/Order/Card/OrderSummary.vue'; import OrderSummary from 'pages/Order/Card/OrderSummary.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog'; import { useSummaryDialog } from 'src/composables/useSummaryDialog';
@ -28,7 +28,11 @@ function navigate(id) {
} }
</script> </script>
<template> <template>
<OrderSearchbar /> <VnSearchbar
data-key="OrderList"
:label="t('Search order')"
:info="t('You can search orders by reference')"
/>
<RightMenu> <RightMenu>
<template #right-panel> <template #right-panel>
<OrderFilter data-key="OrderList" /> <OrderFilter data-key="OrderList" />

View File

@ -2,7 +2,6 @@
import { computed } from 'vue'; import { computed } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useArrayData } from 'src/composables/useArrayData';
import CardDescriptor from 'components/ui/CardDescriptor.vue'; import CardDescriptor from 'components/ui/CardDescriptor.vue';
import VnLv from 'components/ui/VnLv.vue'; import VnLv from 'components/ui/VnLv.vue';
@ -17,8 +16,7 @@ const props = defineProps({
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute(); const route = useRoute();
const entityId = computed(() => props.id || route.params.id); const entityId = computed(() => props.id || route.params.id);
const { store } = useArrayData('Parking');
const parking = computed(() => store.data);
const filter = { const filter = {
fields: ['id', 'sectorFk', 'code', 'pickingOrder', 'row', 'column'], fields: ['id', 'sectorFk', 'code', 'pickingOrder', 'row', 'column'],
include: [{ relation: 'sector', scope: { fields: ['id', 'description'] } }], include: [{ relation: 'sector', scope: { fields: ['id', 'description'] } }],
@ -29,15 +27,13 @@ const filter = {
module="Parking" module="Parking"
data-key="Parking" data-key="Parking"
:url="`Parkings/${entityId}`" :url="`Parkings/${entityId}`"
:title="parking?.code" title="code"
:subtitle="parking?.id"
:filter="filter" :filter="filter"
@on-fetch="(data) => (parking = data)"
> >
<template #body> <template #body="{ entity }">
<VnLv :label="t('globals.code')" :value="parking.code" /> <VnLv :label="t('globals.code')" :value="entity.code" />
<VnLv :label="t('parking.pickingOrder')" :value="parking.pickingOrder" /> <VnLv :label="t('parking.pickingOrder')" :value="entity.pickingOrder" />
<VnLv :label="t('parking.sector')" :value="parking.sector?.description" /> <VnLv :label="t('parking.sector')" :value="entity.sector?.description" />
</template> </template>
</CardDescriptor> </CardDescriptor>
</template> </template>

View File

@ -1,10 +1,9 @@
<script setup> <script setup>
import { ref, computed } from 'vue'; import { computed } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import CardSummary from 'components/ui/CardSummary.vue'; import CardSummary from 'components/ui/CardSummary.vue';
import VnLv from 'components/ui/VnLv.vue'; import VnLv from 'components/ui/VnLv.vue';
import { useArrayData } from 'src/composables/useArrayData';
const $props = defineProps({ const $props = defineProps({
id: { id: {
@ -15,9 +14,7 @@ const $props = defineProps({
const router = useRoute(); const router = useRoute();
const { t } = useI18n(); const { t } = useI18n();
const entityId = computed(() => $props.id || router.params.id); const entityId = computed(() => $props.id || router.params.id);
const { store } = useArrayData('Parking');
const parking = ref(store.data);
const filter = { const filter = {
fields: ['id', 'sectorFk', 'code', 'pickingOrder', 'row', 'column'], fields: ['id', 'sectorFk', 'code', 'pickingOrder', 'row', 'column'],
include: [{ relation: 'sector', scope: { fields: ['id', 'description'] } }], include: [{ relation: 'sector', scope: { fields: ['id', 'description'] } }],
@ -26,14 +23,9 @@ const filter = {
<template> <template>
<div class="q-pa-md"> <div class="q-pa-md">
<CardSummary <CardSummary :url="`Parkings/${entityId}`" data-key="Parking" :filter="filter">
:url="`Parkings/${entityId}`" <template #header="{ entity }">{{ entity.code }}</template>
:filter="filter" <template #body="{ entity }">
@on-fetch="(data) => (parking = data)"
data-key="Parking"
>
<template #header>{{ parking.code }}</template>
<template #body>
<QCard class="vn-one"> <QCard class="vn-one">
<QCardSection class="q-pa-none"> <QCardSection class="q-pa-none">
<a <a
@ -44,17 +36,17 @@ const filter = {
<QIcon name="open_in_new" /> <QIcon name="open_in_new" />
</a> </a>
</QCardSection> </QCardSection>
<VnLv :label="t('globals.code')" :value="parking.code" /> <VnLv :label="t('globals.code')" :value="entity.code" />
<VnLv <VnLv
:label="t('parking.pickingOrder')" :label="t('parking.pickingOrder')"
:value="parking.pickingOrder" :value="entity.pickingOrder"
/> />
<VnLv <VnLv
:label="t('parking.sector')" :label="t('parking.sector')"
:value="parking.sector?.description" :value="entity.sector?.description"
/> />
<VnLv :label="t('parking.row')" :value="parking.row" /> <VnLv :label="t('parking.row')" :value="entity.row" />
<VnLv :label="t('parking.column')" :value="parking.column" /> <VnLv :label="t('parking.column')" :value="entity.column" />
</QCard> </QCard>
</template> </template>
</CardSummary> </CardSummary>

View File

@ -51,7 +51,7 @@ const filter = {
class="header header-link" class="header header-link"
:to="{ name: 'ShelvingBasicData', params: { id: entityId } }" :to="{ name: 'ShelvingBasicData', params: { id: entityId } }"
> >
{{ t('shelving.pageTitles.basicData') }} {{ t('globals.pageTitles.basicData') }}
<QIcon name="open_in_new" /> <QIcon name="open_in_new" />
</RouterLink> </RouterLink>
<VnLv :label="t('shelving.summary.code')" :value="entity.code" /> <VnLv :label="t('shelving.summary.code')" :value="entity.code" />

View File

@ -17,15 +17,6 @@ const props = defineProps({
}, },
}); });
const from = Date.vnNew();
const to = Date.vnNew();
to.setDate(to.getDate() + 1);
const defaultParams = {
from: toDateString(from),
to: toDateString(to),
};
const workers = ref(); const workers = ref();
const provinces = ref(); const provinces = ref();
const states = ref(); const states = ref();
@ -44,11 +35,7 @@ const warehouses = ref();
@on-fetch="(data) => (workers = data)" @on-fetch="(data) => (workers = data)"
auto-load auto-load
/> />
<VnFilterPanel <VnFilterPanel :data-key="props.dataKey" :search-button="true">
:data-key="props.dataKey"
:params="defaultParams"
:search-button="true"
>
<template #tags="{ tag, formatFn }"> <template #tags="{ tag, formatFn }">
<div class="q-gutter-x-xs"> <div class="q-gutter-x-xs">
<strong>{{ t(`params.${tag.label}`) }}: </strong> <strong>{{ t(`params.${tag.label}`) }}: </strong>

View File

@ -26,8 +26,8 @@ const to = Date.vnNew();
to.setDate(to.getDate() + 1); to.setDate(to.getDate() + 1);
const userParams = { const userParams = {
from: toDateString(from), from: from.toISOString(),
to: toDateString(to), to: to.toISOString(),
}; };
function navigate(id) { function navigate(id) {

View File

@ -49,7 +49,7 @@ const entriesTableColumns = computed(() => {
showValue: false, showValue: false,
}, },
{ {
label: t('supplier.pageTitles.supplier'), label: t('globals.pageTitles.supplier'),
field: 'supplierName', field: 'supplierName',
name: 'supplierName', name: 'supplierName',
align: 'left', align: 'left',
@ -248,7 +248,7 @@ const getLink = (param) => `#/travel/${entityId.value}/${param}`;
<QCardSection class="q-pa-none"> <QCardSection class="q-pa-none">
<VnTitle <VnTitle
:url="getLink('basic-data')" :url="getLink('basic-data')"
:text="t('travel.pageTitles.basicData')" :text="t('globals.pageTitles.basicData')"
/> />
</QCardSection> </QCardSection>
<VnLv :label="t('globals.shipped')" :value="toDate(travel.shipped)" /> <VnLv :label="t('globals.shipped')" :value="toDate(travel.shipped)" />
@ -266,7 +266,7 @@ const getLink = (param) => `#/travel/${entityId.value}/${param}`;
<QCardSection class="q-pa-none"> <QCardSection class="q-pa-none">
<VnTitle <VnTitle
:url="getLink('basic-data')" :url="getLink('basic-data')"
:text="t('travel.pageTitles.basicData')" :text="t('globals.pageTitles.basicData')"
/> />
</QCardSection> </QCardSection>
<VnLv :label="t('globals.landed')" :value="toDate(travel.landed)" /> <VnLv :label="t('globals.landed')" :value="toDate(travel.landed)" />
@ -284,7 +284,7 @@ const getLink = (param) => `#/travel/${entityId.value}/${param}`;
<QCardSection class="q-pa-none"> <QCardSection class="q-pa-none">
<VnTitle <VnTitle
:url="getLink('basic-data')" :url="getLink('basic-data')"
:text="t('travel.pageTitles.basicData')" :text="t('globals.pageTitles.basicData')"
/> />
</QCardSection> </QCardSection>
<VnLv :label="t('globals.agency')" :value="travel.agency?.name" /> <VnLv :label="t('globals.agency')" :value="travel.agency?.name" />

View File

@ -140,7 +140,7 @@ const columns = computed(() => [
sortable: true, sortable: true,
}, },
{ {
label: t('supplier.pageTitles.supplier'), label: t('globals.pageTitles.supplier'),
field: 'cargoSupplierNickname', field: 'cargoSupplierNickname',
name: 'cargoSupplierNickname', name: 'cargoSupplierNickname',
align: 'left', align: 'left',

View File

@ -218,7 +218,7 @@ warehouses();
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnSelect <VnSelect
:label="t('supplier.pageTitles.supplier')" :label="t('globals.pageTitles.supplier')"
v-model="params.cargoSupplierFk" v-model="params.cargoSupplierFk"
:options="suppliersOptions" :options="suppliersOptions"
option-value="id" option-value="id"

View File

@ -74,7 +74,7 @@ const agencyOptions = ref([]);
type="number" type="number"
min="0" min="0"
/> />
<VnInputTime v-model="data.hour" :label="t('Closing')" clearable /> <VnInputTime v-model="data.hour" :label="t('Closing')" />
</VnRow> </VnRow>
<VnRow class="row q-gutter-md q-mb-md"> <VnRow class="row q-gutter-md q-mb-md">

View File

@ -11,7 +11,6 @@ import { useState } from 'src/composables/useState';
import { useSession } from 'src/composables/useSession'; import { useSession } from 'src/composables/useSession';
import { useRole } from 'src/composables/useRole'; import { useRole } from 'src/composables/useRole';
import { useUserConfig } from 'src/composables/useUserConfig'; import { useUserConfig } from 'src/composables/useUserConfig';
import { toLowerCamel } from 'src/filters';
import { useTokenConfig } from 'src/composables/useTokenConfig'; import { useTokenConfig } from 'src/composables/useTokenConfig';
import { useAcl } from 'src/composables/useAcl'; import { useAcl } from 'src/composables/useAcl';
@ -79,13 +78,11 @@ export default route(function (/* { store, ssrContext } */) {
let title = t(`login.title`); let title = t(`login.title`);
const matches = to.matched; const matches = to.matched;
let moduleName;
if (matches && matches.length > 1) { if (matches && matches.length > 1) {
const module = matches[1]; const module = matches[1];
const moduleTitle = module.meta && module.meta.title; const moduleTitle = module.meta && module.meta.title;
moduleName = toLowerCamel(module.name);
if (moduleTitle) { if (moduleTitle) {
title = t(`${moduleName}.pageTitles.${moduleTitle}`); title = t(`globals.pageTitles.${moduleTitle}`);
} }
} }
@ -94,7 +91,7 @@ export default route(function (/* { store, ssrContext } */) {
if (childPageTitle && matches.length > 2) { if (childPageTitle && matches.length > 2) {
if (title != '') title += ': '; if (title != '') title += ': ';
const moduleLocale = `${moduleName}.pageTitles.${childPageTitle}`; const moduleLocale = `globals.pageTitles.${childPageTitle}`;
const pageTitle = te(moduleLocale) const pageTitle = te(moduleLocale)
? t(moduleLocale) ? t(moduleLocale)
: t(`globals.pageTitles.${childPageTitle}`); : t(`globals.pageTitles.${childPageTitle}`);

View File

@ -11,7 +11,7 @@ export default {
component: RouterView, component: RouterView,
redirect: { name: 'EntryMain' }, redirect: { name: 'EntryMain' },
menus: { menus: {
main: ['EntryList', 'EntryLatestBuys'], main: ['EntryList', 'MyEntries', 'EntryLatestBuys'],
card: ['EntryBasicData', 'EntryBuys', 'EntryNotes', 'EntryDms', 'EntryLog'], card: ['EntryBasicData', 'EntryBuys', 'EntryNotes', 'EntryDms', 'EntryLog'],
}, },
children: [ children: [
@ -30,6 +30,15 @@ export default {
}, },
component: () => import('src/pages/Entry/EntryList.vue'), component: () => import('src/pages/Entry/EntryList.vue'),
}, },
{
path: 'my',
name: 'MyEntries',
meta: {
title: 'labeler',
icon: 'sell',
},
component: () => import('src/pages/Entry/MyEntries.vue'),
},
{ {
path: 'create', path: 'create',
name: 'EntryCreate', name: 'EntryCreate',

View File

@ -201,15 +201,6 @@ export default {
}, },
component: () => import('src/pages/Item/Card/ItemLog.vue'), component: () => import('src/pages/Item/Card/ItemLog.vue'),
}, },
{
path: 'botanical',
name: 'ItemBotanical',
meta: {
title: 'botanical',
icon: 'vn:botanical',
},
component: () => import('src/pages/Item/Card/ItemBotanical.vue'),
},
], ],
}, },
], ],

View File

@ -23,6 +23,7 @@ export const useArrayDataStore = defineStore('arrayDataStore', () => {
exprBuilder: null, exprBuilder: null,
searchUrl: 'params', searchUrl: 'params',
navigate: null, navigate: null,
page: 1,
}; };
} }

View File

@ -60,7 +60,7 @@ export const useNavigationStore = defineStore('navigationStore', () => {
menuChildren = menuChildren.map(({ name, title, icon }) => ({ menuChildren = menuChildren.map(({ name, title, icon }) => ({
name, name,
icon, icon,
title: `${module}.pageTitles.${title}`, title: `globals.pageTitles.${title}`,
})); }));
if (meta && meta.roles && role.hasAny(meta.roles) === false) return; if (meta && meta.roles && role.hasAny(meta.roles) === false) return;
@ -70,7 +70,7 @@ export const useNavigationStore = defineStore('navigationStore', () => {
children: menuChildren, children: menuChildren,
}; };
if (meta) { if (meta) {
item.title = `${module}.pageTitles.${meta.title}`; item.title = `globals.pageTitles.${meta.title}`;
item.icon = meta.icon; item.icon = meta.icon;
} }

View File

@ -0,0 +1,20 @@
describe('WagonTypeCreate', () => {
beforeEach(() => {
cy.viewport(1920, 1080);
cy.login('customer');
cy.visit(`/#/entry/my`, {
onBeforeLoad(win) {
cy.stub(win, 'open');
},
});
cy.waitForElement('.q-page', 6000);
});
it('should create edit and remove new dms', () => {
cy.get(
'[to="/null/2"] > .q-card > .column > .q-btn > .q-btn__content > .q-icon'
).click();
cy.get('.q-card__actions > .q-btn').click();
cy.window().its('open').should('be.called');
});
});

View File

@ -50,8 +50,8 @@ Cypress.Commands.add('login', (user) => {
}); });
}); });
Cypress.Commands.add('waitForElement', (element) => { Cypress.Commands.add('waitForElement', (element, timeout = 5000) => {
cy.get(element, { timeout: 5000 }).should('be.visible'); cy.get(element, { timeout }).should('be.visible');
}); });
Cypress.Commands.add('getValue', (selector) => { Cypress.Commands.add('getValue', (selector) => {
@ -241,4 +241,3 @@ Cypress.Commands.add('validateContent', (selector, expectedValue) => {
Cypress.Commands.add('openActionsDescriptor', () => { Cypress.Commands.add('openActionsDescriptor', () => {
cy.get('.descriptor > .header > .q-btn').click(); cy.get('.descriptor > .header > .q-btn').click();
}); });
// registerCommands();

View File

@ -78,13 +78,13 @@ describe('Leftmenu', () => {
{ {
children: null, children: null,
name: 'CustomerList', name: 'CustomerList',
title: 'customer.pageTitles.list', title: 'globals.pageTitles.list',
icon: 'view_list', icon: 'view_list',
}, },
{ {
children: null, children: null,
name: 'CustomerCreate', name: 'CustomerCreate',
title: 'customer.pageTitles.createCustomer', title: 'globals.pageTitles.createCustomer',
icon: 'vn:addperson', icon: 'vn:addperson',
}, },
]; ];