feat(dashboard): 优化仪表盘组件加载逻辑,支持异步加载和状态管理

This commit is contained in:
jxxghp
2026-06-07 08:57:25 +08:00
parent 5e3e106d91
commit 8e5b8f7207
9 changed files with 282 additions and 141 deletions
+123 -56
View File
@@ -6,6 +6,8 @@ import DashboardRender from '@/components/render/DashboardRender.vue'
import { isNullOrEmptyObject } from '@/@core/utils' import { isNullOrEmptyObject } from '@/@core/utils'
import { loadRemoteComponent } from '@/utils/federationLoader' import { loadRemoteComponent } from '@/utils/federationLoader'
type DashboardComponentLoader = () => Promise<any>
const DashboardSkeleton = { const DashboardSkeleton = {
setup() { setup() {
const SkeletonLoader = resolveComponent('VSkeletonLoader') const SkeletonLoader = resolveComponent('VSkeletonLoader')
@@ -19,51 +21,59 @@ const asyncDashboardOptions = {
loadingComponent: DashboardSkeleton, loadingComponent: DashboardSkeleton,
} }
const builtInDashboardComponentLoaders: Record<string, DashboardComponentLoader> = {
storage: () => import('@/views/dashboard/AnalyticsStorage.vue'),
mediaStatistic: () => import('@/views/dashboard/AnalyticsMediaStatistic.vue'),
weeklyOverview: () => import('@/views/dashboard/AnalyticsWeeklyOverview.vue'),
speed: () => import('@/views/dashboard/AnalyticsSpeed.vue'),
scheduler: () => import('@/views/dashboard/AnalyticsScheduler.vue'),
cpu: () => import('@/views/dashboard/AnalyticsCpu.vue'),
memory: () => import('@/views/dashboard/AnalyticsMemory.vue'),
network: () => import('@/views/dashboard/AnalyticsNetwork.vue'),
library: () => import('@/views/dashboard/MediaServerLibrary.vue'),
playing: () => import('@/views/dashboard/MediaServerPlaying.vue'),
latest: () => import('@/views/dashboard/MediaServerLatest.vue'),
}
const builtInDashboardComponentPromises = new Map<string, Promise<any>>()
// 复用内置仪表盘组件加载 Promise,让页面层可以等待异步组件模块真正加载完成。
function loadBuiltInDashboardComponent(id: string) {
const loader = builtInDashboardComponentLoaders[id]
if (!loader) return Promise.resolve()
let loadPromise = builtInDashboardComponentPromises.get(id)
if (!loadPromise) {
loadPromise = loader().catch(error => {
builtInDashboardComponentPromises.delete(id)
throw error
})
builtInDashboardComponentPromises.set(id, loadPromise)
}
return loadPromise
}
// 创建内置仪表盘异步组件,并与加载完成上报共享同一份加载 Promise。
function createAsyncDashboardComponent(id: string) {
return defineAsyncComponent({
loader: () => loadBuiltInDashboardComponent(id),
...asyncDashboardOptions,
})
}
// 内置仪表盘按需加载,关闭的卡片不再挤进 dashboard 首屏 chunk。 // 内置仪表盘按需加载,关闭的卡片不再挤进 dashboard 首屏 chunk。
const AnalyticsStorage = defineAsyncComponent({ const AnalyticsStorage = createAsyncDashboardComponent('storage')
loader: () => import('@/views/dashboard/AnalyticsStorage.vue'), const AnalyticsMediaStatistic = createAsyncDashboardComponent('mediaStatistic')
...asyncDashboardOptions, const AnalyticsWeeklyOverview = createAsyncDashboardComponent('weeklyOverview')
}) const AnalyticsSpeed = createAsyncDashboardComponent('speed')
const AnalyticsMediaStatistic = defineAsyncComponent({ const AnalyticsScheduler = createAsyncDashboardComponent('scheduler')
loader: () => import('@/views/dashboard/AnalyticsMediaStatistic.vue'), const AnalyticsCpu = createAsyncDashboardComponent('cpu')
...asyncDashboardOptions, const AnalyticsMemory = createAsyncDashboardComponent('memory')
}) const AnalyticsNetwork = createAsyncDashboardComponent('network')
const AnalyticsWeeklyOverview = defineAsyncComponent({ const MediaServerLibrary = createAsyncDashboardComponent('library')
loader: () => import('@/views/dashboard/AnalyticsWeeklyOverview.vue'), const MediaServerPlaying = createAsyncDashboardComponent('playing')
...asyncDashboardOptions, const MediaServerLatest = createAsyncDashboardComponent('latest')
})
const AnalyticsSpeed = defineAsyncComponent({
loader: () => import('@/views/dashboard/AnalyticsSpeed.vue'),
...asyncDashboardOptions,
})
const AnalyticsScheduler = defineAsyncComponent({
loader: () => import('@/views/dashboard/AnalyticsScheduler.vue'),
...asyncDashboardOptions,
})
const AnalyticsCpu = defineAsyncComponent({
loader: () => import('@/views/dashboard/AnalyticsCpu.vue'),
...asyncDashboardOptions,
})
const AnalyticsMemory = defineAsyncComponent({
loader: () => import('@/views/dashboard/AnalyticsMemory.vue'),
...asyncDashboardOptions,
})
const AnalyticsNetwork = defineAsyncComponent({
loader: () => import('@/views/dashboard/AnalyticsNetwork.vue'),
...asyncDashboardOptions,
})
const MediaServerLibrary = defineAsyncComponent({
loader: () => import('@/views/dashboard/MediaServerLibrary.vue'),
...asyncDashboardOptions,
})
const MediaServerPlaying = defineAsyncComponent({
loader: () => import('@/views/dashboard/MediaServerPlaying.vue'),
...asyncDashboardOptions,
})
const MediaServerLatest = defineAsyncComponent({
loader: () => import('@/views/dashboard/MediaServerLatest.vue'),
...asyncDashboardOptions,
})
// 输入参数 // 输入参数
const props = defineProps({ const props = defineProps({
@@ -78,27 +88,43 @@ const props = defineProps({
}, },
}) })
const emit = defineEmits(['update:refreshStatus']) const emit = defineEmits(['update:refreshStatus', 'loaded'])
// 当前仪表盘节点是否已经向页面层报告过加载完成。
const isDashboardElementLoaded = ref(false)
let isDashboardElementUnmounted = false
let pluginDashboardComponentLoadPromise: Promise<any> | null = null
// 插件UI渲染模式 ('vuetify' 或 'vue') // 插件UI渲染模式 ('vuetify' 或 'vue')
const pluginRenderMode = computed(() => props.config?.render_mode || 'vuetify') const pluginRenderMode = computed(() => props.config?.render_mode || 'vuetify')
// 加载 Vue 模式的插件仪表盘远程组件,并缓存当前节点的加载 Promise。
function loadPluginDashboardComponent() {
if (!props.config?.id) return Promise.reject(new Error('插件ID不存在'))
if (!pluginDashboardComponentLoadPromise) {
pluginDashboardComponentLoadPromise = loadRemoteComponent(props.config.id, 'Dashboard').catch(error => {
pluginDashboardComponentLoadPromise = null
throw error
})
}
return pluginDashboardComponentLoadPromise
}
// Vue 模式:动态加载的组件 // Vue 模式:动态加载的组件
const dynamicPluginComponent = defineAsyncComponent({ const dynamicPluginComponent = defineAsyncComponent({
// 工厂函数 // 工厂函数
loader: async () => { loader: async () => {
try { try {
if (!props.config?.id) { const module = await loadPluginDashboardComponent()
throw new Error('插件ID不存在')
}
// 动态加载远程组件
const module = await loadRemoteComponent(props.config.id, 'Dashboard')
// 直接返回加载的组件,无需再获取default // 直接返回加载的组件,无需再获取default
return module return module
} catch (error) { } catch (error) {
console.error('加载远程组件失败:', error) console.error('加载远程组件失败:', error)
throw error
} }
}, },
// 加载中显示的组件 // 加载中显示的组件
@@ -115,7 +141,53 @@ const dynamicPluginComponent = defineAsyncComponent({
}, },
}) })
// 判断当前配置是否对应内置异步仪表盘组件。
function isBuiltInDashboardElement() {
return !!props.config?.id && !!builtInDashboardComponentLoaders[props.config.id]
}
// 判断当前配置是否需要等待插件 Vue 远程组件加载。
function isVuePluginDashboardElement() {
return !isBuiltInDashboardElement() && pluginRenderMode.value === 'vue' && !isNullOrEmptyObject(props.config)
}
// 向页面层上报当前仪表盘节点已完成首次组件加载。
function emitDashboardElementLoaded() {
if (isDashboardElementLoaded.value || isDashboardElementUnmounted) return
isDashboardElementLoaded.value = true
emit('loaded')
}
// 等待当前仪表盘节点的异步组件加载完成,静态渲染模式则等待一次 DOM 更新。
async function waitForDashboardElementLoaded() {
if (isDashboardElementLoaded.value) return
try {
if (isBuiltInDashboardElement() && props.config?.id) {
await loadBuiltInDashboardComponent(props.config.id)
} else if (isVuePluginDashboardElement()) {
await loadPluginDashboardComponent()
}
await nextTick()
} catch (error) {
console.error(error)
} finally {
emitDashboardElementLoaded()
}
}
watch(
() => [props.config?.id, props.config?.key, pluginRenderMode.value],
() => {
void waitForDashboardElementLoaded()
},
{ immediate: true },
)
onUnmounted(() => { onUnmounted(() => {
isDashboardElementUnmounted = true
// 组件卸载时禁用刷新状态 // 组件卸载时禁用刷新状态
emit('update:refreshStatus', false) emit('update:refreshStatus', false)
}) })
@@ -179,9 +251,4 @@ onUnmounted(() => {
inline-size: 100%; inline-size: 100%;
min-block-size: 0; min-block-size: 0;
} }
.dashboard-plugin-vue-renderer :deep(> *) {
flex: 1 1 auto;
min-block-size: 0;
}
</style> </style>
+159 -51
View File
@@ -61,6 +61,15 @@ const dashboardGridRef = ref<HTMLElement | null>(null)
// GridStack 实例 // GridStack 实例
const dashboardGrid = shallowRef<GridStack | null>(null) const dashboardGrid = shallowRef<GridStack | null>(null)
// 仪表板配置是否已完成首次加载,包含插件仪表板配置。
const isDashboardConfigLoaded = ref(false)
// 仪表板是否已完成首次整体渐现。
const isDashboardRevealed = ref(false)
// 已完成组件模块加载的仪表板项目 ID。
const loadedDashboardGridItemIds = ref<Set<string>>(new Set())
// 是否正在由 Vue 同步 GridStack,避免初始化写入覆盖用户布局 // 是否正在由 Vue 同步 GridStack,避免初始化写入覆盖用户布局
const isSyncingDashboardGrid = ref(false) const isSyncingDashboardGrid = ref(false)
@@ -77,6 +86,8 @@ const dashboardGridObservedContentHeights = new Map<string, number>()
let dashboardGridContentObserver: ResizeObserver | null = null let dashboardGridContentObserver: ResizeObserver | null = null
let dashboardGridContentResizeFrame: number | null = null let dashboardGridContentResizeFrame: number | null = null
let dashboardGridResizeRefreshFrame: number | null = null let dashboardGridResizeRefreshFrame: number | null = null
let dashboardRevealFrame: number | null = null
let isDashboardRevealPending = false
// 是否正在手动缩放组件,避免自动测高抢回用户拖动中的高度。 // 是否正在手动缩放组件,避免自动测高抢回用户拖动中的高度。
const isDashboardGridResizing = ref(false) const isDashboardGridResizing = ref(false)
@@ -226,6 +237,79 @@ const dashboardGridItems = computed<DashboardGridItem[]>(() =>
}), }),
) )
// 获取当前可渲染仪表板项目 ID 列表。
function getDashboardGridItemIds() {
return dashboardGridItems.value.map(item => item.id)
}
// 清理已经不在当前仪表板列表中的加载完成标记。
function syncDashboardLoadedItemIds() {
const currentIds = new Set(getDashboardGridItemIds())
const nextLoadedIds = new Set([...loadedDashboardGridItemIds.value].filter(id => currentIds.has(id)))
if (nextLoadedIds.size !== loadedDashboardGridItemIds.value.size) {
loadedDashboardGridItemIds.value = nextLoadedIds
}
}
// 判断当前启用的仪表板项目是否都已经完成组件加载。
function areDashboardGridItemsLoaded() {
return getDashboardGridItemIds().every(id => loadedDashboardGridItemIds.value.has(id))
}
// 判断 GridStack 是否已经可承载当前仪表板项目。
function isDashboardGridReadyForReveal() {
return getDashboardGridItemIds().length === 0 || !!dashboardGrid.value
}
// 在配置、组件和 GridStack 都就绪后安排仪表板整体渐现。
function scheduleDashboardReveal() {
if (
isDashboardRevealed.value ||
isDashboardRevealPending ||
dashboardRevealFrame !== null ||
!isDashboardConfigLoaded.value ||
!isDashboardGridReadyForReveal() ||
!areDashboardGridItemsLoaded()
) {
return
}
isDashboardRevealPending = true
void nextTick(() => {
isDashboardRevealPending = false
if (
isDashboardRevealed.value ||
!isDashboardConfigLoaded.value ||
!isDashboardGridReadyForReveal() ||
!areDashboardGridItemsLoaded()
) {
return
}
resizeAutoDashboardItemsToContent()
if (typeof window === 'undefined') {
isDashboardRevealed.value = true
return
}
dashboardRevealFrame = window.requestAnimationFrame(() => {
dashboardRevealFrame = null
isDashboardRevealed.value = true
notifyDashboardContentResize()
})
})
}
// 标记单个仪表板项目已经完成首次组件加载。
function markDashboardGridItemLoaded(id: string) {
if (loadedDashboardGridItemIds.value.has(id)) return
loadedDashboardGridItemIds.value = new Set([...loadedDashboardGridItemIds.value, id])
scheduleDashboardReveal()
}
// 将未知数值限制到 GridStack 可接受的整数区间。 // 将未知数值限制到 GridStack 可接受的整数区间。
function clampGridNumber(value: unknown, min: number, max: number, fallback: number) { function clampGridNumber(value: unknown, min: number, max: number, fallback: number) {
const numericValue = Number(value) const numericValue = Number(value)
@@ -486,7 +570,7 @@ async function saveDashboardConfig(payload?: { enabled?: Record<string, boolean>
console.error(error) console.error(error)
} }
// 保存后重新获取插件仪表板 // 保存后重新获取插件仪表板
getPluginDashboardMeta() void getPluginDashboardMeta()
settingsDialogController?.close() settingsDialogController?.close()
settingsDialogController = null settingsDialogController = null
} }
@@ -501,16 +585,19 @@ function buildPluginDashboardId(plugin_id: string, key: string) {
async function getPluginDashboardMeta() { async function getPluginDashboardMeta() {
// 只有超级用户才能获取 // 只有超级用户才能获取
if (!superUser) return if (!superUser) return
pluginDashboardMeta.value = await api.get('/plugin/dashboard/meta')
try { try {
pluginDashboardMeta.value = (await api.get('/plugin/dashboard/meta')) ?? []
if (!isNullOrEmptyObject(pluginDashboardMeta.value)) { if (!isNullOrEmptyObject(pluginDashboardMeta.value)) {
// 下载插件仪表板配置 // 下载插件仪表板配置
pluginDashboardMeta.value.forEach(async (pluginDashboard: { id: string; key: string }) => { await Promise.all(
const pluginDashboardId = buildPluginDashboardId(pluginDashboard.id, pluginDashboard.key) pluginDashboardMeta.value.map(async (pluginDashboard: { id: string; key: string }) => {
// 初始化插件仪表板的刷新状态 const pluginDashboardId = buildPluginDashboardId(pluginDashboard.id, pluginDashboard.key)
pluginDashboardRefreshStatus.value[pluginDashboardId] = true // 初始化插件仪表板的刷新状态
await getPluginDashboard(pluginDashboard.id, pluginDashboard.key) pluginDashboardRefreshStatus.value[pluginDashboardId] = true
}) await getPluginDashboard(pluginDashboard.id, pluginDashboard.key)
}),
)
} }
} catch (error) { } catch (error) {
console.error(error) console.error(error)
@@ -535,7 +622,7 @@ function schedulePluginDashboardRefresh(item: DashboardItem) {
isRequest.value isRequest.value
) { ) {
refreshTimers.value[pluginDashboardId] = setTimeout(() => { refreshTimers.value[pluginDashboardId] = setTimeout(() => {
getPluginDashboard(item.id, item.key) void getPluginDashboard(item.id, item.key)
}, item.attrs.refresh * 1000) }, item.attrs.refresh * 1000)
} }
} }
@@ -546,7 +633,7 @@ function refreshEnabledPluginDashboards() {
pluginDashboardMeta.value.forEach((pluginDashboard: { id: string; key: string }) => { pluginDashboardMeta.value.forEach((pluginDashboard: { id: string; key: string }) => {
const pluginDashboardId = buildPluginDashboardId(pluginDashboard.id, pluginDashboard.key) const pluginDashboardId = buildPluginDashboardId(pluginDashboard.id, pluginDashboard.key)
if (enableConfig.value[pluginDashboardId]) { if (enableConfig.value[pluginDashboardId]) {
getPluginDashboard(pluginDashboard.id, pluginDashboard.key) void getPluginDashboard(pluginDashboard.id, pluginDashboard.key)
} }
}) })
} }
@@ -555,34 +642,32 @@ function refreshEnabledPluginDashboards() {
async function getPluginDashboard(id: string, key: string) { async function getPluginDashboard(id: string, key: string) {
try { try {
const url = key ? `/plugin/dashboard/${id}/${key}` : `/plugin/dashboard/${id}` const url = key ? `/plugin/dashboard/${id}/${key}` : `/plugin/dashboard/${id}`
api.get(url).then((res: any) => { const res: DashboardItem | undefined = await api.get(url)
if (res) { if (res) {
// 名称替换为元信息的名称 // 名称替换为元信息的名称
const meta = pluginDashboardMeta.value.find( const meta = pluginDashboardMeta.value.find(
(item: { id: string; key: string }) => item.id === id && item.key === key, (item: { id: string; key: string }) => item.id === id && item.key === key,
) )
if (meta) res.name = meta.name if (meta) res.name = meta.name
// 保存到仪表板配置中,如果已经存在则替换 // 保存到仪表板配置中,如果已经存在则替换
const index = dashboardConfigs.value.findIndex( const index = dashboardConfigs.value.findIndex(
(item: { id: string; key: string }) => item.id === id && item.key === key, (item: { id: string; key: string }) => item.id === id && item.key === key,
) )
if (index !== -1) { if (index !== -1) {
dashboardConfigs.value[index] = res dashboardConfigs.value[index] = res
} else { } else {
dashboardConfigs.value.push(res) dashboardConfigs.value.push(res)
// 为新增的插件仪表板生成颜色 // 为新增的插件仪表板生成颜色
const pluginDashboardId = buildPluginDashboardId(id, key)
if (!itemColors.value[pluginDashboardId]) {
itemColors.value[pluginDashboardId] = getItemColor(pluginDashboardId)
}
// 排序
sortDashboardConfigs()
}
const pluginDashboardId = buildPluginDashboardId(id, key) const pluginDashboardId = buildPluginDashboardId(id, key)
// 定时刷新 if (!itemColors.value[pluginDashboardId]) {
schedulePluginDashboardRefresh(res) itemColors.value[pluginDashboardId] = getItemColor(pluginDashboardId)
}
// 排序
sortDashboardConfigs()
} }
}) // 定时刷新
schedulePluginDashboardRefresh(res)
}
} catch (error) { } catch (error) {
console.error(error) console.error(error)
} }
@@ -689,7 +774,10 @@ async function syncDashboardGrid() {
grid.batchUpdate(false) grid.batchUpdate(false)
updateDashboardGridEditableState(isLayoutEditing.value) updateDashboardGridEditableState(isLayoutEditing.value)
observeDashboardGridContent() observeDashboardGridContent()
nextTick(resizeAutoDashboardItemsToContent) nextTick(() => {
resizeAutoDashboardItemsToContent()
scheduleDashboardReveal()
})
} finally { } finally {
isSyncingDashboardGrid.value = false isSyncingDashboardGrid.value = false
} }
@@ -731,8 +819,7 @@ function shouldScheduleDashboardContentResize(element: GridItemHTMLElement, next
dashboardGridObservedContentHeights.set(id, nextHeight) dashboardGridObservedContentHeights.set(id, nextHeight)
return ( return (
previousHeight === undefined || previousHeight === undefined || Math.abs(nextHeight - previousHeight) >= DASHBOARD_GRID_CONTENT_RESIZE_THRESHOLD
Math.abs(nextHeight - previousHeight) >= DASHBOARD_GRID_CONTENT_RESIZE_THRESHOLD
) )
} }
@@ -865,7 +952,9 @@ watch(isLayoutEditing, value => {
watch( watch(
dashboardGridItems, dashboardGridItems,
() => { () => {
syncDashboardLoadedItemIds()
syncDashboardGrid() syncDashboardGrid()
scheduleDashboardReveal()
}, },
{ deep: true }, { deep: true },
) )
@@ -873,7 +962,9 @@ watch(
onBeforeMount(async () => { onBeforeMount(async () => {
await loadDashboardConfig() await loadDashboardConfig()
initializeColors() initializeColors()
getPluginDashboardMeta() await getPluginDashboardMeta()
isDashboardConfigLoaded.value = true
scheduleDashboardReveal()
}) })
onMounted(() => { onMounted(() => {
@@ -903,6 +994,10 @@ onBeforeUnmount(() => {
cancelAnimationFrame(dashboardGridResizeRefreshFrame) cancelAnimationFrame(dashboardGridResizeRefreshFrame)
dashboardGridResizeRefreshFrame = null dashboardGridResizeRefreshFrame = null
} }
if (dashboardRevealFrame !== null) {
cancelAnimationFrame(dashboardRevealFrame)
dashboardRevealFrame = null
}
dashboardGridPendingContentResize.clear() dashboardGridPendingContentResize.clear()
dashboardGridObservedContentHeights.clear() dashboardGridObservedContentHeights.clear()
dashboardGridResizeStartHeights.clear() dashboardGridResizeStartHeights.clear()
@@ -913,7 +1008,11 @@ onBeforeUnmount(() => {
<template> <template>
<!-- 仪表板 --> <!-- 仪表板 -->
<div ref="dashboardGridRef" class="grid-stack dashboard-grid" :class="{ 'is-editing': isLayoutEditing }"> <div
ref="dashboardGridRef"
class="grid-stack dashboard-grid"
:class="{ 'is-editing': isLayoutEditing, 'is-ready': isDashboardRevealed }"
>
<div <div
v-for="gridItem in dashboardGridItems" v-for="gridItem in dashboardGridItems"
:key="gridItem.id" :key="gridItem.id"
@@ -935,6 +1034,7 @@ onBeforeUnmount(() => {
:config="gridItem.config" :config="gridItem.config"
:allow-refresh="isRequest" :allow-refresh="isRequest"
v-model:refreshStatus="pluginDashboardRefreshStatus[gridItem.id]" v-model:refreshStatus="pluginDashboardRefreshStatus[gridItem.id]"
@loaded="markDashboardGridItemLoaded(gridItem.id)"
/> />
</div> </div>
<span v-if="isLayoutEditing" class="dashboard-grid-drag-handle" :aria-label="t('dashboard.dragHandle')"> <span v-if="isLayoutEditing" class="dashboard-grid-drag-handle" :aria-label="t('dashboard.dragHandle')">
@@ -979,18 +1079,19 @@ onBeforeUnmount(() => {
/* stylelint-disable selector-pseudo-class-no-unknown */ /* stylelint-disable selector-pseudo-class-no-unknown */
.dashboard-grid { .dashboard-grid {
margin-block: -6px 0; opacity: 0;
pointer-events: none;
transform: translateY(8px);
transition:
opacity 0.45s cubic-bezier(0.25, 1, 0.5, 1),
transform 0.45s cubic-bezier(0.25, 1, 0.5, 1);
will-change: opacity, transform;
} }
.dashboard-grid :deep(.v-card) { .dashboard-grid.is-ready {
overflow: hidden; opacity: 1;
box-shadow: var(--app-surface-shadow) !important; pointer-events: auto;
} transform: translateY(0);
@media (hover: hover) {
.dashboard-grid :deep(.v-card:hover) {
box-shadow: var(--app-surface-hover-shadow) !important;
}
} }
.dashboard-grid-item.is-manual-height :deep(.v-card) { .dashboard-grid-item.is-manual-height :deep(.v-card) {
@@ -1090,4 +1191,11 @@ onBeforeUnmount(() => {
inset-block-end: -4px; inset-block-end: -4px;
inset-inline-end: -4px; inset-inline-end: -4px;
} }
@media (prefers-reduced-motion: reduce) {
.dashboard-grid {
transform: none;
transition: none;
}
}
</style> </style>
-5
View File
@@ -159,9 +159,4 @@ useKeepAliveRefresh(refresh)
min-block-size: 0; min-block-size: 0;
} }
.dashboard-chart-plot :deep(.vue-apexcharts),
.dashboard-chart-plot :deep(.apexcharts-canvas),
.dashboard-chart-plot :deep(svg) {
block-size: 100% !important;
}
</style> </style>
-6
View File
@@ -163,10 +163,4 @@ useKeepAliveRefresh(refresh)
flex: 1 1 auto; flex: 1 1 auto;
min-block-size: 0; min-block-size: 0;
} }
.dashboard-chart-plot :deep(.vue-apexcharts),
.dashboard-chart-plot :deep(.apexcharts-canvas),
.dashboard-chart-plot :deep(svg) {
block-size: 100% !important;
}
</style> </style>
-5
View File
@@ -206,9 +206,4 @@ useKeepAliveRefresh(refresh)
min-block-size: 0; min-block-size: 0;
} }
.dashboard-chart-plot :deep(.vue-apexcharts),
.dashboard-chart-plot :deep(.apexcharts-canvas),
.dashboard-chart-plot :deep(svg) {
block-size: 100% !important;
}
</style> </style>
@@ -164,10 +164,4 @@ onActivated(() => {
flex: 1 1 auto; flex: 1 1 auto;
min-block-size: 0; min-block-size: 0;
} }
.dashboard-work-chart :deep(.vue-apexcharts),
.dashboard-work-chart :deep(.apexcharts-canvas),
.dashboard-work-chart :deep(svg) {
block-size: 100% !important;
}
</style> </style>
@@ -100,8 +100,4 @@ onActivated(() => {
flex: 1 1 auto; flex: 1 1 auto;
min-block-size: 0; min-block-size: 0;
} }
.dashboard-media-grid :deep(.progressive-card-grid__track) {
min-block-size: 100%;
}
</style> </style>
@@ -89,8 +89,4 @@ onActivated(() => {
flex: 1 1 auto; flex: 1 1 auto;
min-block-size: 0; min-block-size: 0;
} }
.dashboard-media-grid :deep(.progressive-card-grid__track) {
min-block-size: 100%;
}
</style> </style>
@@ -90,8 +90,4 @@ onActivated(() => {
flex: 1 1 auto; flex: 1 1 auto;
min-block-size: 0; min-block-size: 0;
} }
.dashboard-media-grid :deep(.progressive-card-grid__track) {
min-block-size: 100%;
}
</style> </style>