refactor: refs #8463 simplify CardDescriptor
This commit is contained in:
parent
4d8fb8eb5b
commit
704bf77771
|
@ -1,13 +1,9 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onBeforeMount, watch, computed, ref } from 'vue';
|
import { onBeforeMount, watch, computed, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
import SkeletonDescriptor from 'components/ui/SkeletonDescriptor.vue';
|
|
||||||
import { useArrayData } from 'composables/useArrayData';
|
import { useArrayData } from 'composables/useArrayData';
|
||||||
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
|
||||||
import { useState } from 'src/composables/useState';
|
import { useState } from 'src/composables/useState';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useClipboard } from 'src/composables/useClipboard';
|
import VnDescriptor from './VnDescriptor.vue';
|
||||||
import VnMoreOptions from './VnMoreOptions.vue';
|
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
url: {
|
url: {
|
||||||
|
@ -18,42 +14,19 @@ const $props = defineProps({
|
||||||
type: Object,
|
type: Object,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
subtitle: {
|
|
||||||
type: Number,
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
dataKey: {
|
dataKey: {
|
||||||
type: String,
|
type: String,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
summary: {
|
|
||||||
type: Object,
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
width: {
|
|
||||||
type: String,
|
|
||||||
default: 'md-width',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const state = useState();
|
const state = useState();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
|
||||||
const { t } = useI18n();
|
|
||||||
const { copyText } = useClipboard();
|
|
||||||
const { viewSummary } = useSummaryDialog();
|
|
||||||
let arrayData;
|
let arrayData;
|
||||||
let store;
|
let store;
|
||||||
let entity;
|
let entity;
|
||||||
const isLoading = ref(false);
|
const isLoading = ref(false);
|
||||||
const isSameDataKey = computed(() => $props.dataKey === route.meta.moduleName);
|
const isSameDataKey = computed(() => $props.dataKey === route.meta.moduleName);
|
||||||
const DESCRIPTOR_PROXY = 'DescriptorProxy';
|
|
||||||
const moduleName = ref();
|
|
||||||
const isSameModuleName = route.matched[1].meta.moduleName !== moduleName.value;
|
|
||||||
defineExpose({ getData });
|
defineExpose({ getData });
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
onBeforeMount(async () => {
|
||||||
|
@ -80,18 +53,6 @@ onBeforeMount(async () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
function getName() {
|
|
||||||
let name = $props.dataKey;
|
|
||||||
if ($props.dataKey.includes(DESCRIPTOR_PROXY)) {
|
|
||||||
name = name.split(DESCRIPTOR_PROXY)[0];
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
const routeName = computed(() => {
|
|
||||||
let routeName = getName();
|
|
||||||
return `${routeName}Summary`;
|
|
||||||
});
|
|
||||||
|
|
||||||
async function getData() {
|
async function getData() {
|
||||||
store.url = $props.url;
|
store.url = $props.url;
|
||||||
store.filter = $props.filter ?? {};
|
store.filter = $props.filter ?? {};
|
||||||
|
@ -105,249 +66,13 @@ async function getData() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getValueFromPath(path) {
|
|
||||||
if (!path) return;
|
|
||||||
const keys = path.toString().split('.');
|
|
||||||
let current = entity.value;
|
|
||||||
|
|
||||||
for (const key of keys) {
|
|
||||||
if (current[key] === undefined) return undefined;
|
|
||||||
else current = current[key];
|
|
||||||
}
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
|
|
||||||
function copyIdText(id) {
|
|
||||||
copyText(id, {
|
|
||||||
component: {
|
|
||||||
copyValue: id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const emit = defineEmits(['onFetch']);
|
const emit = defineEmits(['onFetch']);
|
||||||
|
|
||||||
const iconModule = computed(() => {
|
|
||||||
moduleName.value = getName();
|
|
||||||
if (isSameModuleName) {
|
|
||||||
return router.options.routes[1].children.find((r) => r.name === moduleName.value)
|
|
||||||
?.meta?.icon;
|
|
||||||
} else {
|
|
||||||
return route.matched[1].meta.icon;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const toModule = computed(() => {
|
|
||||||
moduleName.value = getName();
|
|
||||||
if (isSameModuleName) {
|
|
||||||
return router.options.routes[1].children.find((r) => r.name === moduleName.value)
|
|
||||||
?.children[0]?.redirect;
|
|
||||||
} else {
|
|
||||||
return route.matched[1].path.split('/').length > 2
|
|
||||||
? route.matched[1].redirect
|
|
||||||
: route.matched[1].children[0].redirect;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="descriptor">
|
<VnDescriptor v-model="entity" v-bind="$attrs" :module="dataKey">
|
||||||
<template v-if="entity && !isLoading">
|
<template v-for="(_, slotName) in $slots" #[slotName]="slotData" :key="slotName">
|
||||||
<div class="header bg-primary q-pa-sm justify-between">
|
<slot :name="slotName" v-bind="slotData ?? {}" :key="slotName" />
|
||||||
<slot name="header-extra-action">
|
|
||||||
<QBtn
|
|
||||||
round
|
|
||||||
flat
|
|
||||||
dense
|
|
||||||
size="md"
|
|
||||||
:icon="iconModule"
|
|
||||||
color="white"
|
|
||||||
class="link"
|
|
||||||
:to="toModule"
|
|
||||||
>
|
|
||||||
<QTooltip>
|
|
||||||
{{ t('globals.goToModuleIndex') }}
|
|
||||||
</QTooltip>
|
|
||||||
</QBtn>
|
|
||||||
</slot>
|
|
||||||
<QBtn
|
|
||||||
@click.stop="viewSummary(entity.id, $props.summary, $props.width)"
|
|
||||||
round
|
|
||||||
flat
|
|
||||||
dense
|
|
||||||
size="md"
|
|
||||||
icon="preview"
|
|
||||||
color="white"
|
|
||||||
class="link"
|
|
||||||
v-if="summary"
|
|
||||||
>
|
|
||||||
<QTooltip>
|
|
||||||
{{ t('components.smartCard.openSummary') }}
|
|
||||||
</QTooltip>
|
|
||||||
</QBtn>
|
|
||||||
<RouterLink :to="{ name: routeName, params: { id: entity.id } }">
|
|
||||||
<QBtn
|
|
||||||
class="link"
|
|
||||||
color="white"
|
|
||||||
dense
|
|
||||||
flat
|
|
||||||
icon="launch"
|
|
||||||
round
|
|
||||||
size="md"
|
|
||||||
>
|
|
||||||
<QTooltip>
|
|
||||||
{{ t('components.cardDescriptor.summary') }}
|
|
||||||
</QTooltip>
|
|
||||||
</QBtn>
|
|
||||||
</RouterLink>
|
|
||||||
<VnMoreOptions v-if="$slots.menu">
|
|
||||||
<template #menu="{ menuRef }">
|
|
||||||
<slot name="menu" :entity="entity" :menu-ref="menuRef" />
|
|
||||||
</template>
|
|
||||||
</VnMoreOptions>
|
|
||||||
</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="getValueFromPath(title)">
|
|
||||||
{{ getValueFromPath(title) ?? $props.title }}
|
|
||||||
</span>
|
|
||||||
<slot v-else name="description" :entity="entity">
|
|
||||||
<span :title="entity.name">
|
|
||||||
{{ entity.name }}
|
|
||||||
</span>
|
|
||||||
</slot>
|
|
||||||
</div>
|
|
||||||
</QItemLabel>
|
|
||||||
<QItem>
|
|
||||||
<QItemLabel class="subtitle">
|
|
||||||
#{{ getValueFromPath(subtitle) ?? entity.id }}
|
|
||||||
</QItemLabel>
|
|
||||||
<QBtn
|
|
||||||
round
|
|
||||||
flat
|
|
||||||
dense
|
|
||||||
size="sm"
|
|
||||||
icon="content_copy"
|
|
||||||
color="primary"
|
|
||||||
@click.stop="copyIdText(entity.id)"
|
|
||||||
>
|
|
||||||
<QTooltip>
|
|
||||||
{{ t('globals.copyId') }}
|
|
||||||
</QTooltip>
|
|
||||||
</QBtn>
|
|
||||||
</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 justify-center" data-cy="descriptor_actions">
|
|
||||||
<slot name="actions" :entity="entity" />
|
|
||||||
</div>
|
|
||||||
<slot name="after" />
|
|
||||||
</template>
|
</template>
|
||||||
<SkeletonDescriptor v-if="!entity || isLoading" />
|
</VnDescriptor>
|
||||||
</div>
|
|
||||||
<QInnerLoading
|
|
||||||
:label="t('globals.pleaseWait')"
|
|
||||||
:showing="isLoading"
|
|
||||||
color="primary"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.body {
|
|
||||||
background-color: var(--vn-section-color);
|
|
||||||
.text-h5 {
|
|
||||||
font-size: 20px;
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 0px;
|
|
||||||
}
|
|
||||||
.q-item {
|
|
||||||
min-height: 20px;
|
|
||||||
|
|
||||||
.link {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.vn-label-value {
|
|
||||||
display: flex;
|
|
||||||
padding: 0px 16px;
|
|
||||||
.label {
|
|
||||||
color: var(--vn-label-color);
|
|
||||||
font-size: 14px;
|
|
||||||
|
|
||||||
&:not(:has(a))::after {
|
|
||||||
content: ':';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.value {
|
|
||||||
color: var(--vn-text-color);
|
|
||||||
font-size: 14px;
|
|
||||||
margin-left: 4px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
.info {
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.title {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
span {
|
|
||||||
color: var(--vn-text-color);
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.subtitle {
|
|
||||||
color: var(--vn-text-color);
|
|
||||||
font-size: 16px;
|
|
||||||
margin-bottom: 2px;
|
|
||||||
}
|
|
||||||
.list-box {
|
|
||||||
.q-item__label {
|
|
||||||
color: var(--vn-label-color);
|
|
||||||
padding-bottom: 0%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.descriptor {
|
|
||||||
width: 256px;
|
|
||||||
.header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.icons {
|
|
||||||
margin: 0 10px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
.q-icon {
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.actions {
|
|
||||||
margin: 0 5px;
|
|
||||||
justify-content: center !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<i18n>
|
|
||||||
en:
|
|
||||||
globals:
|
|
||||||
copyId: Copy ID
|
|
||||||
es:
|
|
||||||
globals:
|
|
||||||
copyId: Copiar ID
|
|
||||||
</i18n>
|
|
||||||
|
|
Loading…
Reference in New Issue