<script setup> import { ref, computed, watch, onBeforeMount } from 'vue'; import { useRoute } from 'vue-router'; import SkeletonSummary from 'components/ui/SkeletonSummary.vue'; import VnLv from 'src/components/ui/VnLv.vue'; import { useArrayData } from 'src/composables/useArrayData'; const props = defineProps({ url: { type: String, default: '', }, filter: { type: Object, default: null, }, entityId: { type: Number, default: null, }, dataKey: { type: String, default: '', }, }); const emit = defineEmits(['onFetch']); const route = useRoute(); const isSummary = ref(); const arrayData = useArrayData(props.dataKey || route.meta.moduleName, { url: props.url, filter: props.filter, skip: 0, }); const { store } = arrayData; const entity = computed(() => store.data); const isLoading = ref(false); defineExpose({ entity, fetch, }); onBeforeMount(async () => { isSummary.value = String(route.path).endsWith('/summary'); await fetch(); watch(props, async () => await fetch()); }); async function fetch() { store.url = props.url; isLoading.value = true; const { data } = await arrayData.fetch({ append: false, updateRouter: false }); emit('onFetch', data); isLoading.value = false; } </script> <template> <div class="summary container"> <QCard class="cardSummary"> <SkeletonSummary v-if="!entity || isLoading" /> <template v-if="entity && !isLoading"> <div class="summaryHeader bg-primary q-pa-sm text-weight-bolder"> <slot name="header-left"> <router-link v-if="!isSummary && route.meta.moduleName" class="header link" :to="{ name: `${route.meta.moduleName}Summary`, params: { id: entityId || entity.id }, }" > <QIcon name="open_in_new" color="white" size="sm" /> </router-link> <span v-else></span> </slot> <slot name="header" :entity="entity"> <VnLv :label="`${entity.id} -`" :value="entity.name" /> </slot> <slot name="header-right"> <span></span> </slot> </div> <div class="summaryBody row q-mb-md"> <slot name="body" :entity="entity" /> </div> </template> </QCard> </div> </template> <style lang="scss"> .summary.container { display: flex; justify-content: center; } .cardSummary { width: 100%; .summaryHeader { text-align: center; font-size: 20px; display: flex; justify-content: space-between; } .summaryBody { display: flex; flex-direction: row; flex-wrap: wrap; justify-content: space-evenly; gap: 10px; padding: 10px; background-color: var(--vn-section-color); > .q-card.vn-one { flex: 1; } > .q-card.vn-two { flex: 40%; } > .q-card.vn-three { flex: 75%; } > .q-card.vn-max { flex: 100%; } > .q-card { width: 100%; background-color: var(--vn-section-color); padding: 7px; font-size: 16px; min-width: 275px; .vn-label-value { display: flex; flex-direction: row; margin-top: 2px; .label { color: var(--vn-label-color); width: 8em; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; margin-right: 10px; flex-grow: 0; flex-shrink: 0; } .value { color: var(--vn-text-color); overflow: hidden; } } .header { color: $primary; font-weight: bold; margin-bottom: 10px; font-size: 20px; display: inline-block; } .header.link:hover { color: lighten($primary, 20%); } .q-checkbox { display: flex; margin-bottom: 9px; & .q-checkbox__label { margin-left: 31px; color: var(--vn-text-color); } & .q-checkbox__inner { position: absolute; left: 0; color: var(--vn-label-color); } } } } @media (max-width: $breakpoint-xs) { .summaryBody { padding: 0; } } } </style> <style lang="scss" scoped> .summaryHeader .vn-label-value { display: flex; flex-direction: row; } .summaryHeader { color: $white; } </style>