refactor: 优化设备和产品详情页组件加载
- 引入 defineAsyncComponent 实现异步组件加载 - 在产品详情页添加 Metadata 组件预取 - 优化标签页 active-key绑定方式
This commit is contained in:
parent
ac343f006a
commit
78c7cff383
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted, onUnmounted } from 'vue';
|
import { computed, defineAsyncComponent, onMounted, onUnmounted } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { Page } from '@vben/common-ui';
|
import { Page } from '@vben/common-ui';
|
||||||
|
@ -12,10 +12,18 @@ import { deviceStateOptions } from '#/constants/dicts';
|
||||||
import { useDeviceStore } from '#/store/device';
|
import { useDeviceStore } from '#/store/device';
|
||||||
import { getWebSocket } from '#/utils/websocket';
|
import { getWebSocket } from '#/utils/websocket';
|
||||||
|
|
||||||
import BasicInfo from './components/BasicInfo.vue';
|
const BasicInfo = defineAsyncComponent(
|
||||||
import DeviceSimulation from './components/DeviceSimulation.vue';
|
() => import('./components/BasicInfo.vue'),
|
||||||
import LogManagement from './components/LogManagement.vue';
|
);
|
||||||
import RunningStatus from './components/RunningStatus.vue';
|
const DeviceSimulation = defineAsyncComponent(
|
||||||
|
() => import('./components/DeviceSimulation.vue'),
|
||||||
|
);
|
||||||
|
const LogManagement = defineAsyncComponent(
|
||||||
|
() => import('./components/LogManagement.vue'),
|
||||||
|
);
|
||||||
|
const RunningStatus = defineAsyncComponent(
|
||||||
|
() => import('./components/RunningStatus.vue'),
|
||||||
|
);
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -207,7 +215,7 @@ onUnmounted(() => {
|
||||||
|
|
||||||
<!-- 标签页内容 -->
|
<!-- 标签页内容 -->
|
||||||
<Tabs
|
<Tabs
|
||||||
v-model:active-key="activeTab"
|
:active-key="activeTab"
|
||||||
class="detail-tabs"
|
class="detail-tabs"
|
||||||
@change="handleTabChange"
|
@change="handleTabChange"
|
||||||
:destroy-inactive-tab-pane="true"
|
:destroy-inactive-tab-pane="true"
|
||||||
|
|
|
@ -1,11 +1,26 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted, onUnmounted } from 'vue';
|
import {
|
||||||
|
computed,
|
||||||
|
defineAsyncComponent,
|
||||||
|
defineComponent,
|
||||||
|
h,
|
||||||
|
onMounted,
|
||||||
|
onUnmounted,
|
||||||
|
} from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { Page } from '@vben/common-ui';
|
import { Page } from '@vben/common-ui';
|
||||||
|
|
||||||
import { ArrowLeftOutlined } from '@ant-design/icons-vue';
|
import { ArrowLeftOutlined } from '@ant-design/icons-vue';
|
||||||
import { Image, message, Modal, Switch, TabPane, Tabs } from 'ant-design-vue';
|
import {
|
||||||
|
Image,
|
||||||
|
message,
|
||||||
|
Modal,
|
||||||
|
Spin,
|
||||||
|
Switch,
|
||||||
|
TabPane,
|
||||||
|
Tabs,
|
||||||
|
} from 'ant-design-vue';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
productPushMetadataById,
|
productPushMetadataById,
|
||||||
|
@ -13,9 +28,35 @@ import {
|
||||||
} from '#/api/device/product';
|
} from '#/api/device/product';
|
||||||
import { useProductStore } from '#/store/product';
|
import { useProductStore } from '#/store/product';
|
||||||
|
|
||||||
import BasicInfo from './components/BasicInfo.vue';
|
const BasicInfo = defineAsyncComponent(
|
||||||
import DeviceAccess from './components/DeviceAccess.vue';
|
() => import('./components/BasicInfo.vue'),
|
||||||
import Metadata from './components/Metadata.vue';
|
);
|
||||||
|
const DeviceAccess = defineAsyncComponent(
|
||||||
|
() => import('./components/DeviceAccess.vue'),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Metadata 异步组件:loading 占位 + 预取
|
||||||
|
const MetadataLoading = defineComponent({
|
||||||
|
name: 'MetadataLoading',
|
||||||
|
setup() {
|
||||||
|
return () =>
|
||||||
|
h(
|
||||||
|
'div',
|
||||||
|
{
|
||||||
|
style:
|
||||||
|
'display:flex;align-items:center;justify-content:center;padding:24px;',
|
||||||
|
},
|
||||||
|
[h(Spin, { tip: '正在加载物模型...' })],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const loadMetadataAsync = () =>
|
||||||
|
import(/* webpackPrefetch: true */ './components/Metadata.vue');
|
||||||
|
const Metadata = defineAsyncComponent({
|
||||||
|
loader: loadMetadataAsync,
|
||||||
|
loadingComponent: MetadataLoading,
|
||||||
|
delay: 200,
|
||||||
|
});
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -32,6 +73,16 @@ const loadProductInfo = async () => {
|
||||||
// TODO: 这里需要添加获取设备数量的逻辑
|
// TODO: 这里需要添加获取设备数量的逻辑
|
||||||
// 暂时设置为 0
|
// 暂时设置为 0
|
||||||
productStore.setDeviceCount(0);
|
productStore.setDeviceCount(0);
|
||||||
|
// 空闲时预取 Metadata 代码,减少首次切换等待
|
||||||
|
if (activeTab.value !== 'Metadata') {
|
||||||
|
const idle = (cb: () => void) =>
|
||||||
|
(window as any).requestIdleCallback
|
||||||
|
? (window as any).requestIdleCallback(cb)
|
||||||
|
: setTimeout(cb, 200);
|
||||||
|
idle(() => {
|
||||||
|
loadMetadataAsync().catch(() => undefined);
|
||||||
|
});
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
message.error('加载产品信息失败');
|
message.error('加载产品信息失败');
|
||||||
}
|
}
|
||||||
|
@ -154,7 +205,7 @@ onUnmounted(() => {
|
||||||
|
|
||||||
<!-- 标签页内容 -->
|
<!-- 标签页内容 -->
|
||||||
<Tabs
|
<Tabs
|
||||||
v-model:active-key="activeTab"
|
:active-key="activeTab"
|
||||||
class="detail-tabs"
|
class="detail-tabs"
|
||||||
@change="handleTabChange"
|
@change="handleTabChange"
|
||||||
>
|
>
|
||||||
|
|
Loading…
Reference in New Issue