|
|
@@ -3,27 +3,108 @@
|
|
|
</template>
|
|
|
<script setup lang="ts">
|
|
|
import { WebtopoProjectApi, parseWebtopoDataModel } from '@/api/pms/maotu'
|
|
|
+import { IotDeviceApi } from '@/api/pms/device'
|
|
|
import type { IExportJson } from '@/components/mt-edit/components/types'
|
|
|
import { MtPreview } from '@/export'
|
|
|
import { ElMessage } from 'element-plus'
|
|
|
-import { nextTick, onMounted, ref } from 'vue'
|
|
|
+import { nextTick, onMounted, onUnmounted, ref } from 'vue'
|
|
|
import { useRoute } from 'vue-router'
|
|
|
|
|
|
const route = useRoute()
|
|
|
const MtPreviewRef = ref<InstanceType<typeof MtPreview>>()
|
|
|
+const previewData = ref<IExportJson>()
|
|
|
+const pollingTimer = ref<number>()
|
|
|
+const polling = ref(false)
|
|
|
|
|
|
const getProjectId = () => {
|
|
|
const id = Number(route.params.id)
|
|
|
return Number.isFinite(id) && id > 0 ? id : undefined
|
|
|
}
|
|
|
|
|
|
+type DevicePointData = {
|
|
|
+ identifier?: string
|
|
|
+ value?: unknown
|
|
|
+}
|
|
|
+
|
|
|
const setPreviewData = async (dataModel: unknown) => {
|
|
|
if (!dataModel) {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
+ previewData.value = dataModel as IExportJson
|
|
|
await nextTick()
|
|
|
- MtPreviewRef.value?.setImportJson(dataModel as IExportJson)
|
|
|
+ MtPreviewRef.value?.setImportJson(previewData.value)
|
|
|
+}
|
|
|
+
|
|
|
+const getDeviceBindItems = () => {
|
|
|
+ return (previewData.value?.json || []).flatMap((item) =>
|
|
|
+ (item.deviceBinds || [])
|
|
|
+ .filter((bind) => bind.deviceId && bind.deviceProp && bind.nodeProp)
|
|
|
+ .map((bind) => ({
|
|
|
+ itemId: item.id,
|
|
|
+ deviceId: bind.deviceId!,
|
|
|
+ deviceProp: bind.deviceProp!,
|
|
|
+ nodeProp: bind.nodeProp!
|
|
|
+ }))
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+const refreshDeviceBindValues = async () => {
|
|
|
+ if (polling.value) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const bindItems = getDeviceBindItems()
|
|
|
+ const deviceIds = Array.from(new Set(bindItems.map((item) => item.deviceId)))
|
|
|
+ if (!bindItems.length || !deviceIds.length) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ polling.value = true
|
|
|
+ try {
|
|
|
+ const deviceDataList = await Promise.all(
|
|
|
+ deviceIds.map(async (deviceId) => {
|
|
|
+ const data = ((await IotDeviceApi.getIotDeviceTds(deviceId)) || []) as DevicePointData[]
|
|
|
+ return { deviceId, data }
|
|
|
+ })
|
|
|
+ )
|
|
|
+ const valueMap = new Map<string, unknown>()
|
|
|
+ deviceDataList.forEach(({ deviceId, data }) => {
|
|
|
+ data.forEach((item) => {
|
|
|
+ if (item.identifier) {
|
|
|
+ valueMap.set(`${deviceId}:${item.identifier}`, item.value)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ MtPreviewRef.value?.setItemAttrs(
|
|
|
+ bindItems
|
|
|
+ .filter((item) => valueMap.has(`${item.deviceId}:${item.deviceProp}`))
|
|
|
+ .map((item) => ({
|
|
|
+ id: item.itemId,
|
|
|
+ key: item.nodeProp,
|
|
|
+ val: valueMap.get(`${item.deviceId}:${item.deviceProp}`)
|
|
|
+ }))
|
|
|
+ )
|
|
|
+ } finally {
|
|
|
+ polling.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const startDeviceBindPolling = () => {
|
|
|
+ if (pollingTimer.value) {
|
|
|
+ clearInterval(pollingTimer.value)
|
|
|
+ }
|
|
|
+
|
|
|
+ refreshDeviceBindValues()
|
|
|
+ pollingTimer.value = window.setInterval(refreshDeviceBindValues, 5000)
|
|
|
+}
|
|
|
+
|
|
|
+const stopDeviceBindPolling = () => {
|
|
|
+ if (pollingTimer.value) {
|
|
|
+ clearInterval(pollingTimer.value)
|
|
|
+ pollingTimer.value = undefined
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
const loadProject = async () => {
|
|
|
@@ -31,12 +112,14 @@ const loadProject = async () => {
|
|
|
if (!id) {
|
|
|
const exportJson = sessionStorage.getItem('exportJson')
|
|
|
await setPreviewData(parseWebtopoDataModel(exportJson))
|
|
|
+ startDeviceBindPolling()
|
|
|
return
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
const data = await WebtopoProjectApi.getWebtopoProject(id)
|
|
|
await setPreviewData(data?.dataModel)
|
|
|
+ startDeviceBindPolling()
|
|
|
} catch {
|
|
|
// ElMessage.error('拓扑数据加载失败')
|
|
|
}
|
|
|
@@ -53,4 +136,8 @@ const onEventCallBack = (type: string, item_id: string) => {
|
|
|
onMounted(() => {
|
|
|
loadProject()
|
|
|
})
|
|
|
+
|
|
|
+onUnmounted(() => {
|
|
|
+ stopDeviceBindPolling()
|
|
|
+})
|
|
|
</script>
|