salix-front/src/components/ui/CardDescriptor.vue

251 lines
6.3 KiB
Vue

<script setup>
import { onMounted, useSlots, ref, watch, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { useQuasar } from 'quasar';
import axios from 'axios';
import SkeletonDescriptor from 'components/ui/SkeletonDescriptor.vue';
import { useArrayData } from 'composables/useArrayData';
const $props = defineProps({
url: {
type: String,
default: '',
},
filter: {
type: Object,
default: null,
},
module: {
type: String,
required: true,
},
title: {
type: String,
default: '',
},
subtitle: {
type: Number,
default: 0,
},
dataKey: {
type: String,
default: '',
},
summary: {
type: Object,
default: null,
},
});
const quasar = useQuasar();
const slots = useSlots();
const { t } = useI18n();
const entity = computed(() => useArrayData($props.dataKey).store.data);
defineExpose({
getData,
});
onMounted(async () => {
await getData();
watch(
() => $props.url,
async (newUrl, lastUrl) => {
if (newUrl == lastUrl) return;
entity.value = null;
await getData();
}
);
});
async function getData() {
const arrayData = useArrayData($props.dataKey, {
url: $props.url,
filter: $props.filter,
skip: 0,
});
const { data } = await arrayData.fetch({ append: false, updateRouter: false });
entity.value = data;
emit('onFetch', data);
}
const emit = defineEmits(['onFetch']);
function viewSummary(id) {
quasar.dialog({
component: $props.summary,
componentProps: {
id,
},
});
}
</script>
<template>
<div class="descriptor">
<template v-if="entity">
<div class="header bg-primary q-pa-sm justify-between">
<QBtn
@click.stop="viewSummary(entity.id)"
round
flat
dense
size="md"
icon="preview"
color="white"
class="link"
v-if="summary"
>
<QTooltip>
{{ t('components.smartCard.openSummary') }}
</QTooltip>
</QBtn>
<RouterLink :to="{ name: `${module}Summary`, params: { id: entity.id } }">
<QBtn
class="link"
color="white"
dense
flat
icon="launch"
round
size="md"
>
<QTooltip>
{{ t('components.cardDescriptor.summary') }}
</QTooltip>
</QBtn>
</RouterLink>
<QBtn
color="white"
dense
flat
icon="more_vert"
round
size="md"
v-if="slots.menu"
>
<QTooltip>
{{ t('components.cardDescriptor.moreOptions') }}
</QTooltip>
<QMenu>
<QList>
<slot name="menu" :entity="entity" />
</QList>
</QMenu>
</QBtn>
</div>
<slot name="before" />
<div class="body q-py-sm">
<QList dense>
<QItemLabel header class="ellipsis text-h5" :lines="1">
<div class="title">
<span v-if="$props.title" :title="$props.title">
{{ $props.title }}
</span>
<slot v-else name="description" :entity="entity">
<span :title="entity.name">
{{ entity.name }}
</span>
</slot>
</div>
</QItemLabel>
<QItem dense>
<QItemLabel class="subtitle" caption>
#{{ $props.subtitle ?? entity.id }}
</QItemLabel>
</QItem>
</QList>
<div class="list-box q-mt-xs">
<slot name="body" :entity="entity" />
</div>
</div>
<div class="icons">
<slot name="icons" :entity="entity" />
</div>
<div class="actions">
<slot name="actions" :entity="entity" />
</div>
<slot name="after" />
</template>
<!-- Skeleton -->
<SkeletonDescriptor v-if="!entity" />
</div>
</template>
<style lang="scss">
.body {
.text-h5 {
padding-top: 5px;
padding-bottom: 5px;
}
.q-item {
min-height: 20px;
.link {
margin-left: 5px;
}
}
.vn-label-value {
display: flex;
padding: 2px 16px;
.label {
color: var(--vn-label);
font-size: 12px;
width: 47%;
}
.value {
color: var(--vn-text);
font-size: 14px;
margin-left: 12px;
width: 47%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.info {
margin-left: 5px;
}
}
}
</style>
<style lang="scss" scoped>
.title {
overflow: hidden;
text-overflow: ellipsis;
span {
color: $primary;
font-weight: bold;
}
}
.subtitle {
color: var(--vn-text);
font-size: 16px;
margin-bottom: 15px;
}
.list-box {
width: 90%;
background-color: var(--vn-gray);
margin: 10px auto;
padding: 10px 5px 10px 0px;
border-radius: 8px;
.q-item__label {
color: var(--vn-label);
}
}
.descriptor {
width: 256px;
.header {
display: flex;
}
.icons {
margin: 0 10px;
display: flex;
justify-content: center;
.q-icon {
margin-right: 5px;
}
}
.actions {
margin: 0 5px;
}
}
</style>