#7283 finish item card sections #588

Merged
jorgep merged 24 commits from 7283-itemSectionsMigration into dev 2024-08-12 12:08:46 +00:00
23 changed files with 185 additions and 194 deletions

View File

@ -7,7 +7,7 @@ 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'; import VnAvatar from './ui/VnAvatar.vue';
const { t } = useI18n(); const { t } = useI18n();
const stateStore = useStateStore(); const stateStore = useStateStore();
@ -72,22 +72,13 @@ const pinnedModulesRef = ref();
</QTooltip> </QTooltip>
<PinnedModules ref="pinnedModulesRef" /> <PinnedModules ref="pinnedModulesRef" />
</QBtn> </QBtn>
<QBtn <QBtn class="q-pa-none" rounded dense flat no-wrap id="user">
:class="{ 'q-pa-none': quasar.platform.is.mobile }" <VnAvatar
Review

Es la foto de un usuario

Es la foto de un usuario
rounded :worker-id="user.id"
dense :title="user.name"
flat size="lg"
no-wrap color="transparent"
id="user"
>
<QAvatar size="lg">
<VnImg
:id="user.id"
collection="user"
size="160x160"
:zoom-size="null"
/> />
</QAvatar>
<QTooltip bottom> <QTooltip bottom>
{{ t('globals.userPanel') }} {{ t('globals.userPanel') }}
</QTooltip> </QTooltip>

View File

@ -11,8 +11,8 @@ import VnSelect from 'src/components/common/VnSelect.vue';
import VnRow from 'components/ui/VnRow.vue'; 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 { useRole } from 'src/composables/useRole'; import { useRole } from 'src/composables/useRole';
import VnAvatar from './ui/VnAvatar.vue';
const state = useState(); const state = useState();
const session = useSession(); const session = useSession();
@ -136,7 +136,7 @@ const isEmployee = computed(() => useRole().isEmployee());
@update:model-value="saveLanguage" @update:model-value="saveLanguage"
:label="t(`globals.lang['${userLocale}']`)" :label="t(`globals.lang['${userLocale}']`)"
icon="public" icon="public"
color="orange" color="primary"
false-value="es" false-value="es"
true-value="en" true-value="en"
/> />
@ -145,7 +145,7 @@ const isEmployee = computed(() => useRole().isEmployee());
@update:model-value="saveDarkMode" @update:model-value="saveDarkMode"
:label="t(`globals.darkMode`)" :label="t(`globals.darkMode`)"
checked-icon="dark_mode" checked-icon="dark_mode"
color="orange" color="primary"
unchecked-icon="light_mode" unchecked-icon="light_mode"
/> />
</div> </div>
@ -153,10 +153,12 @@ const isEmployee = computed(() => useRole().isEmployee());
<QSeparator vertical inset class="q-mx-lg" /> <QSeparator vertical inset class="q-mx-lg" />
<div class="col column items-center q-mb-sm"> <div class="col column items-center q-mb-sm">
<QAvatar size="80px"> <VnAvatar
Review

Es la foto de un usuario.

Es la foto de un usuario.
<VnImg :id="user.id" collection="user" size="160x160" /> :worker-id="user.id"
</QAvatar> :title="user.name"
size="xxl"

en otros sitios se usa size="md" posible usar los genericos.
Pregunta: no he encontrado donde esta en nuestro caso md a cuantos px equivale, donde se está?

en otros sitios se usa size="md" posible usar los genericos. Pregunta: no he encontrado donde esta en nuestro caso md a cuantos px equivale, donde se está?

No lo tenemos definido, es nativo de quasar. He probado a poner xl pero se queda muy pequeño. Creo un tamaño personalizado para q-avatar[size="xxxl"] que sea 80px?

No lo tenemos definido, es nativo de quasar. He probado a poner **xl** pero se queda muy pequeño. Creo un tamaño personalizado para q-avatar[size="xxxl"] que sea 80px?

si

si
color="transparent"
/>
<div class="text-subtitle1 q-mt-md"> <div class="text-subtitle1 q-mt-md">
<strong>{{ user.nickname }}</strong> <strong>{{ user.nickname }}</strong>
</div> </div>
@ -168,7 +170,7 @@ const isEmployee = computed(() => useRole().isEmployee());
</div> </div>
<QBtn <QBtn
id="logout" id="logout"
color="orange" color="primary"
flat flat
:label="t('globals.logOut')" :label="t('globals.logOut')"
size="sm" size="sm"

View File

@ -31,7 +31,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" zoom-size="lg" class="image" /> <VnImg :id="item.id" class="image" />
Review

Ese lg no hacía nada.

Ese lg no hacía nada.
<div v-if="item.hex && isCatalog" class="item-color-container"> <div v-if="item.hex && isCatalog" class="item-color-container">
<div <div
class="item-color" class="item-color"

View File

@ -1,45 +1,62 @@
<script setup> <script setup>
import { computed, ref } from 'vue'; import { computed, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useSession } from 'src/composables/useSession'; import { useSession } from 'src/composables/useSession';
import { useColor } from 'src/composables/useColor'; import { useColor } from 'src/composables/useColor';
import { getCssVar } from 'quasar';
const $props = defineProps({ const $props = defineProps({
workerId: { type: Number, required: true }, workerId: { type: Number, required: true },
description: { type: String, default: null }, description: { type: String, default: null },
jorgep marked this conversation as resolved Outdated

No siempre se quiere poner un title, ej. cuando hay un desplegable.

No siempre se quiere poner un title, ej. cuando hay un desplegable.

se puede directamente no definir la propiedad? así no es necesario el boolean?

se puede directamente no definir la propiedad? así no es necesario el boolean?
size: { type: String, default: null },
title: { type: String, default: null }, title: { type: String, default: null },

Habilita

Habilita
color: { type: String, default: null },
}); });
const { getTokenMultimedia } = useSession(); const { getTokenMultimedia } = useSession();
const token = getTokenMultimedia(); const token = getTokenMultimedia();
const { t } = useI18n(); const { t } = useI18n();
const title = computed(() => $props.title ?? t('globals.system')); const src = computed(
() => `/api/Images/user/160x160/${$props.workerId}/download?access_token=${token}`
);
const title = computed(() => $props.title?.toUpperCase() || t('globals.system'));
const showLetter = ref(false); const showLetter = ref(false);
const backgroundColor = computed(() => {
const color = $props.color || useColor(title.value);
return getCssVar(color) || color;
});
watch(src, () => (showLetter.value = false));
</script> </script>
<template> <template>
<div class="avatar-picture column items-center"> <div class="column items-center">
<QAvatar <QAvatar
:style="{ :style="{ backgroundColor }"
backgroundColor: useColor(title), v-bind="$attrs"
}" :title="title || t('globals.system')"
:size="$props.size"
:title="title"
> >
<template v-if="showLetter">{{ title.charAt(0) }}</template> <template v-if="showLetter">
<QImg {{ title.charAt(0) }}
v-else </template>
:src="`/api/Images/user/160x160/${$props.workerId}/download?access_token=${token}`" <QImg v-else :src="src" spinner-color="white" @error="showLetter = true" />
spinner-color="white"
@error="showLetter = true"
/>
</QAvatar> </QAvatar>
<div class="description"> <div class="description">
<slot name="description" v-if="$props.description"> <slot name="description" v-if="description">
<p> <p v-text="description" />
{{ $props.description }}
</p>
</slot> </slot>
</div> </div>
</div> </div>
</template> </template>
<style lang="scss" scoped>
[size='xxl'] {
.q-avatar,
.q-img {
width: 80px;
height: 80px;
}
.q-img {
object-fit: cover;
}
}
</style>

View File

@ -1,6 +1,8 @@
<script setup> <script setup>
import { ref, computed } from 'vue'; import { ref } from 'vue';
import { useSession } from 'src/composables/useSession'; import { useSession } from 'src/composables/useSession';
import noImage from '/no-user.png';
import { useRole } from 'src/composables/useRole';
const $props = defineProps({ const $props = defineProps({
storage: { storage: {
@ -11,14 +13,17 @@ const $props = defineProps({
type: String, type: String,
default: 'catalog', default: 'catalog',
}, },
size: { resolution: {
Review

Realmente no se le estaba indicando el tamaño, solo la resolución

Realmente no se le estaba indicando el tamaño, solo la resolución
type: String, type: String,
default: '200x200', default: '200x200',
}, },
zoomSize: { zoomResolution: {
type: String, type: String,
required: false, default: null,
default: 'lg', },
zoom: {
Review

No siempre se quiere hacer zoom, ej. contador de carros.

No siempre se quiere hacer zoom, ej. contador de carros.
type: Boolean,
default: true,
}, },
id: { id: {
type: Number, type: Number,
@ -28,14 +33,16 @@ 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()}`);
import noImage from '/no-user.png';
import { useRole } from 'src/composables/useRole';
const url = computed(() => {
const isEmployee = useRole().isEmployee(); const isEmployee = useRole().isEmployee();
const getUrl = (zoom = false) => {
const curResolution = zoom
? $props.zoomResolution || $props.resolution
: $props.resolution;
return isEmployee return isEmployee
? `/api/${$props.storage}/${$props.collection}/${$props.size}/${$props.id}/download?access_token=${token}&${timeStamp.value}` ? `/api/${$props.storage}/${$props.collection}/${curResolution}/${$props.id}/download?access_token=${token}&${timeStamp.value}`
: noImage; : noImage;
}); };
const reload = () => { const reload = () => {
timeStamp.value = `timestamp=${Date.now()}`; timeStamp.value = `timestamp=${Date.now()}`;
}; };
@ -45,23 +52,21 @@ defineExpose({
</script> </script>
<template> <template>
<QImg <QImg
:class="{ zoomIn: $props.zoomSize }" :class="{ zoomIn: zoom }"
:src="url" :src="getUrl()"
v-bind="$attrs" v-bind="$attrs"
@click="show = !show" @click.stop="show = $props.zoom ? true : false"
spinner-color="primary" spinner-color="primary"
/> />
<QDialog v-model="show" v-if="$props.zoomSize"> <QDialog v-if="$props.zoom" v-model="show">
<QImg <QImg
:src="url" :src="getUrl(true)"
size="full"
class="img_zoom"
v-bind="$attrs" v-bind="$attrs"
spinner-color="primary" spinner-color="primary"
class="img_zoom"
/> />
</QDialog> </QDialog>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.q-img { .q-img {
&.zoomIn { &.zoomIn {

View File

@ -221,7 +221,7 @@ defineExpose({ fetch, addFilter, paginate });
> >
<slot name="body" :rows="store.data"></slot> <slot name="body" :rows="store.data"></slot>
<div v-if="isLoading" class="info-row q-pa-md text-center"> <div v-if="isLoading" class="info-row q-pa-md text-center">
<QSpinner color="orange" size="md" /> <QSpinner color="primary" size="md" />
</div> </div>
</QInfiniteScroll> </QInfiniteScroll>
</template> </template>

View File

@ -1,15 +1,12 @@
<script setup>
defineProps({ wrap: { type: Boolean, default: false } });
</script>
<template> <template>
<div class="vn-row q-gutter-md q-mb-md" :class="{ wrap }"> <div class="vn-row q-gutter-md q-mb-md">
<slot></slot> <slot />
Review

wrap no hace nada, se deshicieron los cambios.

wrap no hace nada, se deshicieron los cambios.
</div> </div>
</template> </template>
<style lang="scss" scopped> <style lang="scss" scoped>
.vn-row { .vn-row {

scopped lleva solo una p, antes era un style global. Con :deep y scoped funciona correctamente

scopped lleva solo una p, antes era un style global. Con **:deep** y **scoped** funciona correctamente
display: flex; display: flex;
> * { > :deep(*) {
flex: 1; flex: 1;
} }
} }

View File

@ -54,7 +54,7 @@ const hasAccount = ref(false);
</template> </template>
<template #before> <template #before>
<!-- falla id :id="entityId.value" collection="user" size="160x160" --> <!-- falla id :id="entityId.value" collection="user" size="160x160" -->
<VnImg :id="entityId" collection="user" size="160x160" class="photo"> <VnImg :id="entityId" collection="user" resolution="160x160" class="photo">
<template #error> <template #error>
<div <div
class="absolute-full picture text-center q-pa-md flex flex-center" class="absolute-full picture text-center q-pa-md flex flex-center"

View File

@ -10,13 +10,10 @@ import VnInput from 'src/components/common/VnInput.vue';
import VnInputDate from 'components/common/VnInputDate.vue'; import VnInputDate from 'components/common/VnInputDate.vue';
import axios from 'axios'; import axios from 'axios';
// import { useSession } from 'src/composables/useSession'; import VnAvatar from 'src/components/ui/VnAvatar.vue';
import VnImg from 'src/components/ui/VnImg.vue';
const route = useRoute(); const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
// const { getTokenMultimedia } = useSession();
// const token = getTokenMultimedia();
const claimStates = ref([]); const claimStates = ref([]);
const claimStatesCopy = ref([]); const claimStatesCopy = ref([]);
@ -94,15 +91,14 @@ const statesFilter = {
:rules="validate('claim.claimStateFk')" :rules="validate('claim.claimStateFk')"
> >
<template #before> <template #before>
<QAvatar color="orange"> <VnAvatar
<VnImg :worker-id="data.workerFk"
v-if="data.workerFk" size="md"
:size="'160x160'" :title="
:id="data.workerFk" workersOptions.find(({ id }) => id == data.workerFk)?.name
collection="user" "
spinner-color="white" color="primary"
/> />
</QAvatar>
</template> </template>
</VnSelect> </VnSelect>
<QSelect <QSelect

View File

@ -7,14 +7,15 @@ 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 VnImg from 'src/components/ui/VnImg.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
import VnAvatar from 'src/components/ui/VnAvatar.vue';
const route = useRoute(); const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
const businessTypes = ref([]); const businessTypes = ref([]);
const contactChannels = ref([]); const contactChannels = ref([]);
const title = ref();
</script> </script>
<template> <template>
<FetchData <FetchData
@ -95,16 +96,15 @@ const contactChannels = ref([]);
:label="t('customer.basicData.salesPerson')" :label="t('customer.basicData.salesPerson')"
:rules="validate('client.salesPersonFk')" :rules="validate('client.salesPersonFk')"
:use-like="false" :use-like="false"
:emit-value="false"
@update:model-value="(val) => (title = val?.nickname)"
> >
<template #prepend> <template #prepend>
jorgep marked this conversation as resolved Outdated

los colores estan en quasar.variables.scss
usa las variables, de paso puedes reemplazar los orange que encuentres

los colores estan en quasar.variables.scss usa las variables, de paso puedes reemplazar los orange que encuentres
<QAvatar color="orange"> <VnAvatar
<VnImg :worker-id="data.salesPersonFk"
v-if="data.salesPersonFk" color="primary"
:id="data.salesPersonFk" :title="title"
collection="user"
spinner-color="white"
/> />
</QAvatar>
</template> </template>
</VnSelect> </VnSelect>
<QSelect <QSelect

View File

@ -10,7 +10,6 @@ import FetchData from 'src/components/FetchData.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
import { toCurrency } from 'src/filters'; import { toCurrency } from 'src/filters';
import useNotify from 'src/composables/useNotify.js'; import useNotify from 'src/composables/useNotify.js';
import VnInput from 'src/components/common/VnInput.vue';
import VnInputDate from 'src/components/common/VnInputDate.vue'; import VnInputDate from 'src/components/common/VnInputDate.vue';
import VnInputNumber from 'src/components/common/VnInputNumber.vue'; import VnInputNumber from 'src/components/common/VnInputNumber.vue';

View File

@ -36,15 +36,6 @@ const onIntrastatCreated = (response, formData) => {
@on-fetch="(data) => (itemTypesOptions = data)" @on-fetch="(data) => (itemTypesOptions = data)"
auto-load auto-load
/> />
<FetchData
url="Items/withName"
:filter="{
fields: ['id', 'name'],
order: 'id DESC',
}"
@on-fetch="(data) => (itemsWithNameOptions = data)"
auto-load
/>
<FetchData <FetchData
url="Intrastats" url="Intrastats"
:filter="{ :filter="{
@ -73,7 +64,7 @@ const onIntrastatCreated = (response, formData) => {
<template #form="{ data }"> <template #form="{ data }">
<VnRow> <VnRow>
<VnSelect <VnSelect
:label="t('basicData.type')" :label="t('itemBasicData.type')"
Review

hay otro archivo donde ya se usa la clave basicData, por lo que daba conflicto

hay otro archivo donde ya se usa la clave basicData, por lo que daba conflicto
v-model="data.typeFk" v-model="data.typeFk"
:options="itemTypesOptions" :options="itemTypesOptions"
option-value="id" option-value="id"
@ -92,19 +83,21 @@ const onIntrastatCreated = (response, formData) => {
</QItem> </QItem>
</template> </template>
</VnSelect> </VnSelect>
<VnInput :label="t('basicData.reference')" v-model="data.comment" /> <VnInput :label="t('itemBasicData.reference')" v-model="data.comment" />
<VnInput :label="t('basicData.relevancy')" v-model="data.relevancy" /> <VnInput :label="t('itemBasicData.relevancy')" v-model="data.relevancy" />
</VnRow> </VnRow>
<VnRow> <VnRow>
<VnInput :label="t('basicData.stems')" v-model="data.stems" /> <VnInput :label="t('itemBasicData.stems')" v-model="data.stems" />
<VnInput <VnInput
:label="t('basicData.multiplier')" :label="t('itemBasicData.multiplier')"
v-model="data.stemMultiplier" v-model="data.stemMultiplier"
/> />
<VnSelectDialog <VnSelectDialog
:label="t('basicData.generic')" :label="t('itemBasicData.generic')"
v-model="data.genericFk" v-model="data.genericFk"
:options="itemsWithNameOptions" url="Items/withName"
:fields="['id', 'name']"
sort-by="id DESC"
option-value="id" option-value="id"
option-label="name" option-label="name"
map-options map-options
@ -129,7 +122,7 @@ const onIntrastatCreated = (response, formData) => {
</VnRow> </VnRow>
<VnRow> <VnRow>
<VnSelectDialog <VnSelectDialog
:label="t('basicData.intrastat')" :label="t('itemBasicData.intrastat')"
v-model="data.intrastatFk" v-model="data.intrastatFk"
:options="intrastatsOptions" :options="intrastatsOptions"
option-value="id" option-value="id"
@ -156,7 +149,7 @@ const onIntrastatCreated = (response, formData) => {
</VnSelectDialog> </VnSelectDialog>
<div class="col"> <div class="col">
<VnSelect <VnSelect
:label="t('basicData.expense')" :label="t('itemBasicData.expense')"
v-model="data.expenseFk" v-model="data.expenseFk"
:options="expensesOptions" :options="expensesOptions"
option-value="id" option-value="id"
@ -168,61 +161,64 @@ const onIntrastatCreated = (response, formData) => {
</VnRow> </VnRow>
<VnRow> <VnRow>
<VnInput <VnInput
:label="t('basicData.weightByPiece')" :label="t('itemBasicData.weightByPiece')"
v-model.number="data.weightByPiece" v-model.number="data.weightByPiece"
:min="0" :min="0"
type="number" type="number"
/> />
<VnInput <VnInput
:label="t('basicData.boxUnits')" :label="t('itemBasicData.boxUnits')"
v-model.number="data.packingOut" v-model.number="data.packingOut"
:min="0" :min="0"
type="number" type="number"
/> />
<VnInput <VnInput
:label="t('basicData.recycledPlastic')" :label="t('itemBasicData.recycledPlastic')"
v-model.number="data.recycledPlastic" v-model.number="data.recycledPlastic"
:min="0" :min="0"
type="number" type="number"
/> />
<VnInput <VnInput
:label="t('basicData.nonRecycledPlastic')" :label="t('itemBasicData.nonRecycledPlastic')"
v-model.number="data.nonRecycledPlastic" v-model.number="data.nonRecycledPlastic"
:min="0" :min="0"
type="number" type="number"
/> />
</VnRow> </VnRow>
<VnRow> <VnRow>
<QCheckbox v-model="data.isActive" :label="t('basicData.isActive')" /> <QCheckbox v-model="data.isActive" :label="t('itemBasicData.isActive')" />
<QCheckbox v-model="data.hasKgPrice" :label="t('basicData.hasKgPrice')" /> <QCheckbox
v-model="data.hasKgPrice"
:label="t('itemBasicData.hasKgPrice')"
/>
<div> <div>
<QCheckbox <QCheckbox
v-model="data.isFragile" v-model="data.isFragile"
:label="t('basicData.isFragile')" :label="t('itemBasicData.isFragile')"
class="q-mr-sm" class="q-mr-sm"
/> />
<QIcon name="info" class="cursor-pointer" size="xs"> <QIcon name="info" class="cursor-pointer" size="xs">
<QTooltip max-width="300px"> <QTooltip max-width="300px">
{{ t('basicData.isFragileTooltip') }} {{ t('itemBasicData.isFragileTooltip') }}
</QTooltip> </QTooltip>
</QIcon> </QIcon>
</div> </div>
<div> <div>
<QCheckbox <QCheckbox
v-model="data.isPhotoRequested" v-model="data.isPhotoRequested"
:label="t('basicData.isPhotoRequested')" :label="t('itemBasicData.isPhotoRequested')"
class="q-mr-sm" class="q-mr-sm"
/> />
<QIcon name="info" class="cursor-pointer" size="xs"> <QIcon name="info" class="cursor-pointer" size="xs">
<QTooltip> <QTooltip>
{{ t('basicData.isPhotoRequestedTooltip') }} {{ t('itemBasicData.isPhotoRequestedTooltip') }}
</QTooltip> </QTooltip>
</QIcon> </QIcon>
</div> </div>
</VnRow> </VnRow>
<VnRow> <VnRow>
<VnInput <VnInput
:label="t('basicData.description')" :label="t('itemBasicData.description')"
type="textarea" type="textarea"
v-model="data.description" v-model="data.description"
fill-input fill-input

View File

@ -112,7 +112,7 @@ const openCloneDialog = async () => {
.dialog({ .dialog({
component: VnConfirm, component: VnConfirm,
componentProps: { componentProps: {
title: t("All it's properties will be copied"), title: t('All its properties will be copied'),
message: t('Do you want to clone this item?'), message: t('Do you want to clone this item?'),
}, },
}) })
@ -215,7 +215,7 @@ const openCloneDialog = async () => {
<i18n> <i18n>
es: es:
Regularize stock: Regularizar stock Regularize stock: Regularizar stock
All it's properties will be copied: Todas sus propiedades serán copiadas All its properties will be copied: Todas sus propiedades serán copiadas
Do you want to clone this item?: ¿Desea clonar este artículo? Do you want to clone this item?: ¿Desea clonar este artículo?
</i18n> </i18n>

View File

@ -64,7 +64,7 @@ const handlePhotoUpdated = (evt = false) => {
<template> <template>
<div class="relative-position"> <div class="relative-position">
<VnImg ref="image" :id="$props.entityId" @refresh="handlePhotoUpdated(true)"> <VnImg ref="image" :id="$props.entityId" zoom-resolution="1600x900">
<template #error> <template #error>
<div class="absolute-full picture text-center q-pa-md flex flex-center"> <div class="absolute-full picture text-center q-pa-md flex flex-center">
<div> <div>

View File

@ -1,5 +1,5 @@
<script setup> <script setup>
import { onMounted, computed, onUnmounted, reactive, ref } from 'vue'; import { onMounted, computed, onUnmounted, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { dateRange } from 'src/filters'; import { dateRange } from 'src/filters';
@ -11,6 +11,7 @@ import { toDateTimeFormat } from 'src/filters/date.js';
import { dashIfEmpty } from 'src/filters'; import { dashIfEmpty } from 'src/filters';
import { toCurrency } from 'filters/index'; import { toCurrency } from 'filters/index';
import { useArrayData } from 'composables/useArrayData'; import { useArrayData } from 'composables/useArrayData';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute(); const route = useRoute();
@ -35,26 +36,8 @@ const exprBuilder = (param, value) => {
} }
}; };
const datedRange = reactive({ const from = ref();
from: null, const to = ref();
to: null,
});
const from = computed({
get: () => datedRange.from,
set: (val) => {
updateFrom(val);
updateFilter();
},
});
const to = computed({
get: () => datedRange.to,
set: (val) => {
updateTo(val);
updateFilter();
},
});
const arrayData = useArrayData('ItemLastEntries', { const arrayData = useArrayData('ItemLastEntries', {
url: 'Items/lastEntriesFilter', url: 'Items/lastEntriesFilter',
@ -162,41 +145,48 @@ const fetchItemLastEntries = async () => {
itemLastEntries.value = data; itemLastEntries.value = data;
}; };
const updateFrom = async (date) => { const getDate = (date, type) => {
if (type == 'from') {
date.setHours(0, 0, 0, 0); date.setHours(0, 0, 0, 0);
datedRange.from = date.toISOString(); } else if (type == 'to') {
}; date.setHours(23, 59, 59, 999);
}
const updateTo = async (date) => { return date.toISOString();
date.setHours(23, 59, 59, 59);
datedRange.to = date.toISOString();
}; };
const updateFilter = async () => { const updateFilter = async () => {
arrayData.store.userFilter.where.landed = { let filter;
between: [datedRange.from, datedRange.to], if (!from.value && to.value) filter = { lte: to.value };
}; else if (from.value && !to.value) filter = { gte: from.value };
else if (from.value && to.value) filter = { between: [from.value, to.value] };
arrayData.store.userFilter.where.landed = filter;
await fetchItemLastEntries(); await fetchItemLastEntries();
}; };
onMounted(async () => { onMounted(async () => {
const _from = Date.vnNew(); const _from = Date.vnNew();
_from.setDate(_from.getDate() - 75); _from.setDate(_from.getDate() - 75);
updateFrom(_from); from.value = getDate(_from, 'from');
const _to = Date.vnNew(); const _to = Date.vnNew();
_to.setDate(_to.getDate() + 10); _to.setDate(_to.getDate() + 10);
updateTo(_to); to.value = getDate(Date.vnNew(), 'to');
updateFilter(); updateFilter();
watch([from, to], ([nFrom, nTo], [oFrom, oTo]) => {
if (nFrom && nFrom != oFrom) nFrom = getDate(new Date(nFrom), 'from');
if (nTo && nTo != oTo) nTo = getDate(new Date(nTo), 'to');
updateFilter();
});
}); });
onUnmounted(() => (stateStore.rightDrawer = false)); onUnmounted(() => (stateStore.rightDrawer = false));
</script> </script>
<template> <template>
<QToolbar class="justify-end"> <VnSubToolbar>
<div id="st-data" class="row"> <template #st-data>
<VnInputDate <VnInputDate
:label="t('lastEntries.since')" :label="t('lastEntries.since')"
dense dense
@ -204,11 +194,9 @@ onUnmounted(() => (stateStore.rightDrawer = false));
class="q-mr-lg" class="q-mr-lg"
/> />
<VnInputDate :label="t('lastEntries.to')" dense v-model="to" /> <VnInputDate :label="t('lastEntries.to')" dense v-model="to" />
</div> </template>
<QSpace /> </VnSubToolbar>
<div id="st-actions"></div> <QPage class="column items-center q-pa-xd">
</QToolbar>
<QPage class="column items-center q-pa-md">
<QTable <QTable
:rows="itemLastEntries" :rows="itemLastEntries"
:columns="columns" :columns="columns"

View File

@ -42,9 +42,10 @@ const onItemTagsFetched = async (itemTags) => {
}); });
}; };
const handleTagSelected = (rows, index, tag) => { const handleTagSelected = (rows, index, tagId) => {
Review

Ahora se recoge correctamente el tag

Ahora se recoge correctamente el tag
const tag = tagOptions.value.find((t) => t.id === tagId);
rows[index].tag = tag; rows[index].tag = tag;
rows[index].tagFk = tag.id; rows[index].tagFk = tagId;
rows[index].value = null; rows[index].value = null;
getSelectedTagValues(rows[index]); getSelectedTagValues(rows[index]);
}; };
@ -94,7 +95,6 @@ const insertTag = (rows) => {
:filter="{ :filter="{
fields: ['id', 'itemFk', 'tagFk', 'value', 'priority'], fields: ['id', 'itemFk', 'tagFk', 'value', 'priority'],
where: { itemFk: route.params.id }, where: { itemFk: route.params.id },
order: 'priority ASC',
include: { include: {
relation: 'tag', relation: 'tag',
scope: { scope: {
@ -102,16 +102,13 @@ const insertTag = (rows) => {
}, },
}, },
}" }"
order="priority"
auto-load auto-load
@on-fetch="onItemTagsFetched" @on-fetch="onItemTagsFetched"
> >
<template #body="{ rows, validate }"> <template #body="{ rows, validate }">
<QCard class="q-pl-lg q-py-md"> <QCard class="q-px-lg q-pt-md q-pb-sm">
<VnRow <VnRow v-for="(row, index) in rows" :key="index">
v-for="(row, index) in rows"
:key="index"
class="row q-gutter-md q-mb-md"

No hacía nada.

No hacía nada.
>
<VnSelect <VnSelect
:label="t('itemTags.tag')" :label="t('itemTags.tag')"
:options="tagOptions" :options="tagOptions"
@ -119,7 +116,7 @@ const insertTag = (rows) => {
option-label="name" option-label="name"
hide-selected hide-selected
@update:model-value=" @update:model-value="
($event) => handleTagSelected(rows, index, $event) (val) => handleTagSelected(rows, index, val)
Review

más descriptivo, es un evt/fn personalizado.

más descriptivo, es un evt/fn personalizado.
" "
:required="true" :required="true"
:rules="validate('itemTag.tagFk')" :rules="validate('itemTag.tagFk')"
@ -146,7 +143,6 @@ const insertTag = (rows) => {
v-model="row.value" v-model="row.value"
:label="t('itemTags.value')" :label="t('itemTags.value')"
:is-clearable="false" :is-clearable="false"
style="width: 100%"
/> />
<VnInput <VnInput
:label="t('itemTags.relevancy')" :label="t('itemTags.relevancy')"
@ -155,7 +151,7 @@ const insertTag = (rows) => {
:required="true" :required="true"
:rules="validate('itemTag.priority')" :rules="validate('itemTag.priority')"
/> />
<div class="col-1 row justify-center items-center"> <div class="row justify-center items-center" style="flex: 0">
Review

El basurero se alinea a la derecha y ocupa el mínimo espacio posible.

El basurero se alinea a la derecha y ocupa el mínimo espacio posible.
<QIcon <QIcon
@click="itemTagsRef.remove([row])" @click="itemTagsRef.remove([row])"
class="fill-icon-on-hover" class="fill-icon-on-hover"
@ -169,7 +165,7 @@ const insertTag = (rows) => {
</QIcon> </QIcon>
</div> </div>
</VnRow> </VnRow>
<VnRow> <VnRow class="justify-center items-center">
<QIcon <QIcon
@click="insertTag(rows)" @click="insertTag(rows)"
class="cursor-pointer" class="cursor-pointer"
@ -177,6 +173,7 @@ const insertTag = (rows) => {
color="primary" color="primary"
name="add" name="add"
size="sm" size="sm"
style="flex: 0"
Review

El area "clicable" era bastante más ancha que el propio icono. ahora ocupa solo el espacio del icono.

El area "clicable" era bastante más ancha que el propio icono. ahora ocupa solo el espacio del icono.
> >
<QTooltip> <QTooltip>
{{ t('itemTags.addTag') }} {{ t('itemTags.addTag') }}

View File

@ -25,7 +25,7 @@ itemDiary:
showBefore: Show what's before the inventory showBefore: Show what's before the inventory
since: Since since: Since
warehouse: Warehouse warehouse: Warehouse
basicData: itemBasicData:
type: Type type: Type
reference: Reference reference: Reference
relevancy: Relevancy relevancy: Relevancy

View File

@ -25,7 +25,7 @@ itemDiary:
showBefore: Mostrar lo anterior al inventario showBefore: Mostrar lo anterior al inventario
since: Desde since: Desde
warehouse: Almacén warehouse: Almacén
basicData: itemBasicData:
type: Tipo type: Tipo
reference: Referencia reference: Referencia
relevancy: Relevancia relevancy: Relevancia

View File

@ -105,14 +105,14 @@ async function getVideoList(expeditionId, timed) {
label label
markers markers
snap snap
color="orange" color="primary"
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem v-if="lastExpedition && videoList.length"> <QItem v-if="lastExpedition && videoList.length">
<QItemSection> <QItemSection>
<QSelect <QSelect
color="orange" color="primary"
v-model="slide" v-model="slide"
:options="videoList" :options="videoList"
:label="t('ticket.boxing.selectVideo')" :label="t('ticket.boxing.selectVideo')"

View File

@ -34,7 +34,7 @@ const cancel = () => {
<template> <template>
<QPopupProxy ref="QPopupProxyRef"> <QPopupProxy ref="QPopupProxyRef">
<div class="container"> <div class="container">
<QSpinner v-if="!mana" color="orange" size="md" /> <QSpinner v-if="!mana" color="primary" size="md" />
<div v-else> <div v-else>
<div class="header">Mana: {{ toCurrency(mana) }}</div> <div class="header">Mana: {{ toCurrency(mana) }}</div>
<div class="q-pa-md"> <div class="q-pa-md">

View File

@ -64,7 +64,12 @@ function confirm() {
<QList class="row q-mx-auto q-mt-xl"> <QList class="row q-mx-auto q-mt-xl">
<QItem v-for="(props, name) in counters" :key="name" class="col-6"> <QItem v-for="(props, name) in counters" :key="name" class="col-6">
<QItemSection> <QItemSection>
<VnImg :id="props.id" width="130px" @click="handleEvent(name, 'add')" /> <VnImg
Review

si haces click para sumar 1 también te hace zoom. No tenía sentido.

si haces click para sumar 1 también te hace zoom. No tenía sentido.
:id="props.id"
width="130px"
@click="handleEvent(name, 'add')"
:zoom="false"
/>
<p class="title">{{ props.title }}</p> <p class="title">{{ props.title }}</p>
</QItemSection> </QItemSection>
<QItemSection class="q-ma-none"> <QItemSection class="q-ma-none">

View File

@ -147,7 +147,7 @@ const refetch = async () => await cardDescriptorRef.value.getData();
<VnImg <VnImg
:id="parseInt(entityId)" :id="parseInt(entityId)"
collection="user" collection="user"
size="520x520" resolution="520x520"
class="photo" class="photo"
> >
<template #error> <template #error>

View File

@ -7,9 +7,7 @@ describe('Logout', () => {
}); });
describe('by user', () => { describe('by user', () => {
it('should logout', () => { it('should logout', () => {
cy.get( cy.get('#user').click();
'#user > .q-btn__content > .q-avatar > .q-avatar__content > .q-img > .q-img__container > .q-img__image'
).click();
cy.get('.block').click(); cy.get('.block').click();
}); });
}); });