7 changed files with 253 additions and 247 deletions
@ -0,0 +1,157 @@ |
|||||
|
<script lang="ts" setup> |
||||
|
import { nextTick, onMounted, onUnmounted, ref, toRefs, watch } from 'vue' |
||||
|
import { getEXANowListReal } from '@/api/alert/exa' |
||||
|
|
||||
|
const props = defineProps<{ |
||||
|
data: string |
||||
|
}>() |
||||
|
|
||||
|
const { data } = toRefs(props) |
||||
|
const svgContent = ref<string>('') |
||||
|
const isLoading = ref<boolean>(true) |
||||
|
const svgError = ref<string>('') |
||||
|
const point = ref<{ itemNameArray: string[] }>({ itemNameArray: [] }) |
||||
|
const pointElements = ref<NodeListOf<SVGElement> | undefined>() |
||||
|
|
||||
|
let updateInterval: number | undefined |
||||
|
// 加载SVG文件 |
||||
|
async function loadSvg() { |
||||
|
if (!data.value) { |
||||
|
svgError.value = '未提供SVG路径' |
||||
|
isLoading.value = false |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
isLoading.value = true |
||||
|
svgError.value = '' |
||||
|
|
||||
|
// 判断路径是否为完整URL |
||||
|
let url = data.value |
||||
|
if (!url.startsWith('http') && !url.startsWith('/')) { |
||||
|
// 如果是相对路径,尝试从assets加载 |
||||
|
url = new URL(`../../../../assets/${url}`, import.meta.url).href |
||||
|
} |
||||
|
|
||||
|
const response = await fetch(url) |
||||
|
if (!response.ok) |
||||
|
throw new Error(`无法加载SVG: ${response.statusText}`) |
||||
|
|
||||
|
svgContent.value = await response.text() |
||||
|
const svgElement = document.querySelector('.svg-container > svg') |
||||
|
svgElement?.removeAttribute('width') |
||||
|
svgElement?.removeAttribute('height') |
||||
|
|
||||
|
try { |
||||
|
// 获取SVG元素 |
||||
|
const svgElement = document.querySelector('.svg-container > svg') |
||||
|
if (!svgElement) |
||||
|
return |
||||
|
|
||||
|
// 处理拥有point-name属性的元素 |
||||
|
pointElements.value = svgElement.querySelectorAll('[point-name]') |
||||
|
const pointList: string[] = [] |
||||
|
pointElements.value.forEach(async (element) => { |
||||
|
const pointName = element.getAttribute('point-name') |
||||
|
pointName && pointList.push(pointName) |
||||
|
}) |
||||
|
point.value = { itemNameArray: pointList } |
||||
|
|
||||
|
// 等待DOM更新后应用实时数据 |
||||
|
await nextTick() |
||||
|
|
||||
|
// updateRealtimeValues() |
||||
|
} |
||||
|
catch (error) { |
||||
|
console.error('加载SVG失败:', error) |
||||
|
svgError.value = `加载失败: ${error instanceof Error ? error.message : String(error)}` |
||||
|
} |
||||
|
finally { |
||||
|
isLoading.value = false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 更新SVG中的实时数据 |
||||
|
async function updateRealtimeValues() { |
||||
|
if (!svgContent.value || isLoading.value) |
||||
|
return |
||||
|
try { |
||||
|
const res = await getEXANowListReal(point.value) |
||||
|
|
||||
|
if (res.ReturnValue && res.ReturnValue === 1) { |
||||
|
const data = res.ValueArray |
||||
|
console.log(data) |
||||
|
if (pointElements.value) { |
||||
|
pointElements.value.forEach((element, index) => { |
||||
|
console.log(element) |
||||
|
console.log(element.tagName) |
||||
|
|
||||
|
// 根据元素类型设置不同的属性 |
||||
|
if (element.tagName === 'text' || element.tagName === 'tspan' || element.tagName === 'DIV') |
||||
|
console.log(element.tagName) |
||||
|
|
||||
|
element.textContent = String(data[index] || '') |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
catch (error) { |
||||
|
console.error('更新实时数据失败:', error) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 监听数据变化 |
||||
|
watch( |
||||
|
() => data.value, |
||||
|
() => { |
||||
|
loadSvg() |
||||
|
}, |
||||
|
{ immediate: true }, |
||||
|
) |
||||
|
|
||||
|
onMounted(() => { |
||||
|
loadSvg() |
||||
|
// updateRealtimeValues() |
||||
|
setInterval(() => { |
||||
|
updateRealtimeValues() |
||||
|
}, 3000) // 每2秒更新一次实时数据 |
||||
|
}) |
||||
|
|
||||
|
onUnmounted(() => { |
||||
|
// 清理定时器等资源 |
||||
|
clearInterval(updateInterval) |
||||
|
}) |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<!-- <Card class="enter-y !my-1" :title="data.Header || 'SVG可视化'"> --> |
||||
|
<div v-if="isLoading" class="h-40 flex items-center justify-center"> |
||||
|
加载中... |
||||
|
</div> |
||||
|
<div v-else-if="svgError" class="h-40 flex items-center justify-center text-red-500"> |
||||
|
{{ svgError }} |
||||
|
</div> |
||||
|
<div v-else class="svg-container" @click="updateRealtimeValues" v-html="svgContent" /> |
||||
|
<!-- </Card> --> |
||||
|
</template> |
||||
|
|
||||
|
<style scoped> |
||||
|
::v-deep .ant-card-body { |
||||
|
padding: 10px; |
||||
|
overflow: auto; |
||||
|
} |
||||
|
|
||||
|
.svg-container { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
min-height: 300px; |
||||
|
cursor: pointer; /* 点击时可以手动触发数据更新 */ |
||||
|
} |
||||
|
|
||||
|
.svg-container > svg { |
||||
|
max-width: 100%; |
||||
|
max-height: 100%; |
||||
|
} |
||||
|
</style> |
||||
Loading…
Reference in new issue