Browse Source

Merge pull request 'dev-xjf' (#58) from dev-xjf into master

Reviewed-on: http://120.26.116.243:3000/root/alert-front/pulls/58
master
xiaojinfei 10 hours ago
parent
commit
11da93dfdd
  1. 58
      public/example-meter.svg
  2. 1
      public/illustration.svg
  3. 1
      public/illustration1.svg
  4. 1
      public/test.svg
  5. BIN
      public/中速磨煤机.jpg
  6. BIN
      public/凝汽器.png
  7. 1
      public/测试.svg
  8. 7
      public/测试深.svg
  9. BIN
      public/磨煤机.png
  10. BIN
      public/磨煤机生产流程.png
  11. 1
      public/送风机.svg
  12. 6
      src/api/alert/exa/index.ts
  13. 58
      src/assets/example-meter.svg
  14. 1
      src/assets/test.svg
  15. 1
      src/assets/送风机.svg
  16. 13
      src/views/dashboard/demo/components/ParameterInfo.vue
  17. 46
      src/views/dashboard/demo/components/ProjectCard.vue
  18. 2
      src/views/dashboard/demo/components/demo.json
  19. 10
      src/views/dashboard/demo/components/staticImg.vue
  20. 49
      src/views/dashboard/demo/components/staticSvg.vue
  21. 205
      src/views/dashboard/demo/components/svg copy.vue
  22. 287
      src/views/dashboard/demo/components/svg.vue
  23. 68
      src/views/dashboard/demo/index copy.vue
  24. 85
      src/views/dashboard/demo/index.vue

58
public/example-meter.svg

@ -0,0 +1,58 @@
<svg width="400" height="300" viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg">
<rect width="400" height="300" fill="#f5f5f5" rx="10" ry="10"/>
<!-- 仪表盘背景 -->
<circle cx="200" cy="150" r="100" fill="white" stroke="#e8e8e8" stroke-width="2"/>
<circle cx="200" cy="150" r="90" fill="#fafafa"/>
<!-- 刻度 -->
<g id="scale">
<line x1="200" y1="60" x2="200" y2="70" stroke="#333" stroke-width="2"/>
<line x1="265" y1="85" x2="275" y2="95" stroke="#333" stroke-width="2"/>
<line x1="285" y1="150" x2="275" y2="150" stroke="#333" stroke-width="2"/>
<line x1="265" y1="215" x2="275" y2="205" stroke="#333" stroke-width="2"/>
<line x1="200" y1="240" x2="200" y2="230" stroke="#333" stroke-width="2"/>
<line x1="135" y1="215" x2="125" y2="205" stroke="#333" stroke-width="2"/>
<line x1="115" y1="150" x2="125" y2="150" stroke="#333" stroke-width="2"/>
<line x1="135" y1="85" x2="125" y2="95" stroke="#333" stroke-width="2"/>
</g>
<!-- 刻度标签 -->
<text x="200" y="50" text-anchor="middle" font-size="14" fill="#666">0</text>
<text x="290" y="90" text-anchor="middle" font-size="14" fill="#666">45</text>
<text x="290" y="155" text-anchor="middle" font-size="14" fill="#666">90</text>
<text x="290" y="215" text-anchor="middle" font-size="14" fill="#666">135</text>
<text x="200" y="260" text-anchor="middle" font-size="14" fill="#666">180</text>
<text x="110" y="215" text-anchor="middle" font-size="14" fill="#666">225</text>
<text x="110" y="155" text-anchor="middle" font-size="14" fill="#666">270</text>
<text x="110" y="90" text-anchor="middle" font-size="14" fill="#666">315</text>
<!-- 指针 -->
<g id="pointer-group">
<circle cx="200" cy="150" r="8" fill="#1890ff"/>
<line id="pointer" x1="200" y1="150" x2="200" y2="70" stroke="#1890ff" stroke-width="3" stroke-linecap="round" transform="rotate(0 200 150)"/>
<circle cx="200" cy="150" r="4" fill="#fff"/>
</g>
<!-- 实时数据显示区域 -->
<rect x="100" y="220" width="200" height="40" rx="5" ry="5" fill="#e6f7ff" stroke="#91d5ff" stroke-width="1"/>
<text x="120" y="245" font-size="16" fill="#333">当前值:</text>
<text id="current-value" x="200" y="245" text-anchor="middle" font-size="18" font-weight="bold" fill="#1890ff">0</text>
<text x="260" y="245" font-size="16" fill="#333">%</text>
<!-- 阈值指示器 -->
<g id="thresholds">
<rect x="50" y="270" width="30" height="20" rx="3" ry="3" fill="#52c41a"/>
<text x="65" y="284" text-anchor="middle" font-size="12" fill="white">正常</text>
<rect x="110" y="270" width="30" height="20" rx="3" ry="3" fill="#faad14"/>
<text x="125" y="284" text-anchor="middle" font-size="12" fill="white">警告</text>
<rect x="170" y="270" width="30" height="20" rx="3" ry="3" fill="#ff4d4f"/>
<text x="185" y="284" text-anchor="middle" font-size="12" fill="white">危险</text>
<!-- 当前状态指示器 -->
<rect id="status-indicator" x="250" y="270" width="100" height="20" rx="3" ry="3" fill="#52c41a"/>
<text id="status-text" x="300" y="284" text-anchor="middle" font-size="12" fill="white">状态: 正常</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

1
public/illustration.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 70 KiB

1
public/illustration1.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 54 KiB

1
public/test.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 432 KiB

BIN
public/中速磨煤机.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 KiB

BIN
public/凝汽器.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

1
public/测试.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 325 KiB

7
public/测试深.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 325 KiB

BIN
public/磨煤机.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

BIN
public/磨煤机生产流程.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

1
public/送风机.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 467 KiB

6
src/api/alert/exa/index.ts

@ -17,7 +17,10 @@ export interface EXANowReqVO {
itemName?: string itemName?: string
} }
export interface EXANowListReqVO {
itemNameArray?: string[]
}
export interface EXAPoint { export interface EXAPoint {
AssetCode?: string AssetCode?: string
ItemName?: string ItemName?: string
@ -45,6 +48,9 @@ export function getEXAPage(params: EXAPageReqVO) {
export function getExaNowList(itemName: string) { export function getExaNowList(itemName: string) {
return defHttp.get({ url: `/alert/exa/nowList?itemName=${itemName}` }) return defHttp.get({ url: `/alert/exa/nowList?itemName=${itemName}` })
} }
export function getEXANowListReal(data: EXANowListReqVO) {
return defHttp.post({ url: '/alert/exa/nowListReal', data })
}
export function getExaNow(itemName: string) { export function getExaNow(itemName: string) {
return defHttp.get({ url: `/alert/exa/now?itemName=${itemName}` }) return defHttp.get({ url: `/alert/exa/now?itemName=${itemName}` })

58
src/assets/example-meter.svg

@ -0,0 +1,58 @@
<svg width="400" height="300" viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg">
<rect width="400" height="300" fill="#f5f5f5" rx="10" ry="10"/>
<!-- 仪表盘背景 -->
<circle cx="200" cy="150" r="100" fill="white" stroke="#e8e8e8" stroke-width="2"/>
<circle cx="200" cy="150" r="90" fill="#fafafa"/>
<!-- 刻度 -->
<g id="scale">
<line x1="200" y1="60" x2="200" y2="70" stroke="#333" stroke-width="2"/>
<line x1="265" y1="85" x2="275" y2="95" stroke="#333" stroke-width="2"/>
<line x1="285" y1="150" x2="275" y2="150" stroke="#333" stroke-width="2"/>
<line x1="265" y1="215" x2="275" y2="205" stroke="#333" stroke-width="2"/>
<line x1="200" y1="240" x2="200" y2="230" stroke="#333" stroke-width="2"/>
<line x1="135" y1="215" x2="125" y2="205" stroke="#333" stroke-width="2"/>
<line x1="115" y1="150" x2="125" y2="150" stroke="#333" stroke-width="2"/>
<line x1="135" y1="85" x2="125" y2="95" stroke="#333" stroke-width="2"/>
</g>
<!-- 刻度标签 -->
<text x="200" y="50" text-anchor="middle" font-size="14" fill="#666">0</text>
<text x="290" y="90" text-anchor="middle" font-size="14" fill="#666">45</text>
<text x="290" y="155" text-anchor="middle" font-size="14" fill="#666">90</text>
<text x="290" y="215" text-anchor="middle" font-size="14" fill="#666">135</text>
<text x="200" y="260" text-anchor="middle" font-size="14" fill="#666">180</text>
<text x="110" y="215" text-anchor="middle" font-size="14" fill="#666">225</text>
<text x="110" y="155" text-anchor="middle" font-size="14" fill="#666">270</text>
<text x="110" y="90" text-anchor="middle" font-size="14" fill="#666">315</text>
<!-- 指针 -->
<g id="pointer-group">
<circle cx="200" cy="150" r="8" fill="#1890ff"/>
<line id="pointer" x1="200" y1="150" x2="200" y2="70" stroke="#1890ff" stroke-width="3" stroke-linecap="round" transform="rotate(0 200 150)"/>
<circle cx="200" cy="150" r="4" fill="#fff"/>
</g>
<!-- 实时数据显示区域 -->
<rect x="100" y="220" width="200" height="40" rx="5" ry="5" fill="#e6f7ff" stroke="#91d5ff" stroke-width="1"/>
<text x="120" y="245" font-size="16" fill="#333">当前值:</text>
<text id="current-value" x="200" y="245" text-anchor="middle" font-size="18" font-weight="bold" fill="#1890ff">0</text>
<text x="260" y="245" font-size="16" fill="#333">%</text>
<!-- 阈值指示器 -->
<g id="thresholds">
<rect x="50" y="270" width="30" height="20" rx="3" ry="3" fill="#52c41a"/>
<text x="65" y="284" text-anchor="middle" font-size="12" fill="white">正常</text>
<rect x="110" y="270" width="30" height="20" rx="3" ry="3" fill="#faad14"/>
<text x="125" y="284" text-anchor="middle" font-size="12" fill="white">警告</text>
<rect x="170" y="270" width="30" height="20" rx="3" ry="3" fill="#ff4d4f"/>
<text x="185" y="284" text-anchor="middle" font-size="12" fill="white">危险</text>
<!-- 当前状态指示器 -->
<rect id="status-indicator" x="250" y="270" width="100" height="20" rx="3" ry="3" fill="#52c41a"/>
<text id="status-text" x="300" y="284" text-anchor="middle" font-size="12" fill="white">状态: 正常</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

1
src/assets/test.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 432 KiB

1
src/assets/送风机.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 467 KiB

13
src/views/dashboard/demo/components/ParameterInfo.vue

@ -21,13 +21,11 @@ watch(
}, },
) )
function getInterval(record: any) { function getInterval(record: any) {
console.log(record)
if (record.predictValue === '-') if (record.predictValue === '-')
return '-' return '-'
record.predictValue = Number(record.predictValue).toFixed(2) record.predictValue = Number(record.predictValue).toFixed(2)
const threshold = record.ResidualThreshold const threshold = record.ResidualThreshold
console.log(threshold)
const predictValue = record.predictValue || 0 const predictValue = record.predictValue || 0
return `[${Number(predictValue) - threshold},${Number(predictValue) + threshold}]` return `[${Number(predictValue) - threshold},${Number(predictValue) + threshold}]`
} }
@ -40,6 +38,7 @@ const [registerTable, { setTableData }] = useTable({
useSearchForm: false, useSearchForm: false,
showTableSetting: false, showTableSetting: false,
showIndexColumn: false, showIndexColumn: false,
}) })
// //
onBeforeUpdate(async () => { onBeforeUpdate(async () => {
@ -88,7 +87,11 @@ onBeforeUpdate(async () => {
更多 更多
</a-button> </a-button>
</template> --> </template> -->
<BasicTable style="min-height:30vh" :loading="loading" @register="registerTable"> <BasicTable
:pagination="{ pageSize: 6 }"
:min-height="200"
:loading="loading" @register="registerTable"
>
<template #threshold="{ record }"> <template #threshold="{ record }">
<span>{{ getInterval(record) }}</span> <span>{{ getInterval(record) }}</span>
</template> </template>
@ -98,6 +101,8 @@ onBeforeUpdate(async () => {
<style scoped> <style scoped>
::v-deep(.ant-card-body) { ::v-deep(.ant-card-body) {
padding:5px; padding:10px;
height:calc(46vh - 56px)
} }
</style> </style>

46
src/views/dashboard/demo/components/ProjectCard.vue

@ -10,57 +10,13 @@ const props = defineProps({
default: () => {}, default: () => {},
}, },
}) })
const gridData = ref<any>([])
watch( watch(
() => props.data, () => props.data,
(newValue, oldValue) => { (newValue, oldValue) => {
// //
console.log('a has changed', newValue, oldValue) console.log('a has changed', newValue, oldValue)
getNewData()
}, },
) )
async function getNewData() {
const rows = props.data.Content || []
for (const item of rows) {
try {
const param = item.Point
const res = await getExaNow(param)
let ifColor: boolean = false
if (res != null)
ifColor = res === '1'
gridData.value.push(Object.assign({}, item, { ifColor }))
console.log(gridData.value)
}
catch (e) {
}
}
}
//
// onMounted(async () => {
// const rows = props.data.Content || []
// for (const item of rows) {
// try {
// const param = item.Point
// const res = await getExaNow(param)
// let ifColor: boolean = false
// if (res != null)
// ifColor = res === '1'
// gridData.value.push(Object.assign({}, item, { ifColor }))
// console.log(gridData.value)
// }
// catch (e) {
// }
// }
// })
</script> </script>
<template> <template>
@ -71,7 +27,7 @@ async function getNewData() {
</a-button> </a-button>
</template> </template>
<CardGrid v-for="item in gridData" :key="item.Point" :class="{ 'bg-[#990000] bg-opacity-50': item.ifColor }" class="flex flex-col items-center justify-center !h-1/3 !w-full !md:w-1/4"> <CardGrid v-for="item in props.data.Content" :key="item.Point" :class="{ 'bg-[#990000] bg-opacity-50': item.ifColor }" class="flex flex-col items-center justify-center !h-1/3 !w-full !md:w-1/4">
<!-- <Icon :icon="item.icon" :color="item.color" size="30" /> --> <!-- <Icon :icon="item.icon" :color="item.color" size="30" /> -->
<div class="flex flex-col items-center justify-center"> <div class="flex flex-col items-center justify-center">
<div class="text-center text-base"> <div class="text-center text-base">

2
src/views/dashboard/demo/components/demo.json

@ -34,7 +34,7 @@
}, },
"LeftDown": { "LeftDown": {
"Header": "生产流程", "Header": "生产流程",
"path": "svg/illustration.svg" "path": ""
}, },
"RightDown": { "RightDown": {
"Header": "参数信息", "Header": "参数信息",

10
src/views/dashboard/demo/components/staticImg.vue

@ -1,3 +1,4 @@
<!-- 这个文件是直接展示svg,不处理svg中数据 -->
<script lang="ts" setup> <script lang="ts" setup>
import { Card, CardGrid } from 'ant-design-vue' import { Card, CardGrid } from 'ant-design-vue'
import { ref, toRefs, watch } from 'vue' import { ref, toRefs, watch } from 'vue'
@ -24,13 +25,18 @@ watch(
) )
function getAssetsFile() { function getAssetsFile() {
const url = props.data.path const url = props.data.path
console.log(url)
return new URL(`../../../../assets/${url}`, import.meta.url).href return new URL(`../../../../assets/${url}`, import.meta.url).href
} }
</script> </script>
<template> <template>
<Card class="enter-y !my-1" :title="props.data.Header"> <Card class="enter-y !my-1" :title="props.data.Header">
<img class="mx-auto h-70 w-full" :src="props.data.path"> <img class="mx-auto h-full w-full" :src="props.data.path">
</Card> </Card>
</template> </template>
<style scoped>
::v-deep .ant-card-body {
padding: 10px;
}
</style>

49
src/views/dashboard/demo/components/staticSvg.vue

@ -0,0 +1,49 @@
<script lang="ts" setup>
import { ref, watch } from 'vue'
import { Card } from 'ant-design-vue'
import ExpandAltOutlined from '@ant-design/icons-vue/ExpandAltOutlined'
import Svg from './svg.vue'
const props = defineProps({
data: {
type: Object,
default: () => {},
},
})
const path = ref<string>('')
watch(
() => props.data,
(newValue, oldValue) => {
//
console.log('a has changed', newValue, oldValue)
path.value = newValue.path
},
)
const svgRef: any = ref(null)
function fullScreen() {
//
if (svgRef.value) {
// .value 访
svgRef.value.toggleFullscreen()
}
}
</script>
<template>
<Card class="enter-y !my-1" :title="props.data.Header">
<template #extra>
<ExpandAltOutlined style="cursor:pointer" @click="fullScreen" />
</template>
<Svg ref="svgRef" :path="path" />
</Card>
</template>
<style scoped>
::v-deep .ant-card-body {
padding: 5px;
height:calc(46vh - 60px);
}
</style>

205
src/views/dashboard/demo/components/svg copy.vue

@ -0,0 +1,205 @@
<script lang="ts" setup>
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import { getEXANowListReal } from '@/api/alert/exa'
const props = defineProps<{
path: string
default: ''
}>()
// const { data } = toRefs(props)
const svgContent = ref<string>('')
const svgError = ref<string>('')
const point = ref<{ itemNameArray: string[] }>({ itemNameArray: [] })
// const pointElements = ref<NodeListOf<SVGElement> | undefined>()
//
watch(
() => props.path,
(newValue, oldValue) => {
//
console.log('a has changed', newValue)
if (newValue !== oldValue && newValue !== '' && newValue != null)
loadSvg()
},
{ immediate: true },
)
// SVG
async function loadSvg() {
console.log('加载SVG文件...')
if (!props.path) {
svgError.value = '未提供SVG路径'
return
}
svgError.value = ''
try {
// URL
let url = props.path
if (!url.startsWith('http') && !url.startsWith('/')) {
// assets
url = new URL(`../../../../assets/${url}`, import.meta.url).href
}
//
const timestamp = new Date().getTime()
if (url.includes('?'))
url += `&t=${timestamp}`
else
url += `?t=${timestamp}`
const response = await fetch(url)
if (!response.ok)
throw new Error(`无法加载SVG: ${response.statusText}`)
svgContent.value = await response.text()
// DOM
await nextTick()
document.querySelector('.svg-container > svg')?.removeAttribute('width')
document.querySelector('.svg-container > svg')?.removeAttribute('height')
// updateRealtimeValues()
}
catch (error) {
console.error('加载SVG失败:', error)
svgError.value = `加载失败: ${error instanceof Error ? error.message : String(error)}`
}
}
// SVG
async function updateRealtimeValues() {
if (!svgContent.value)
return
try {
const svgElement = document.querySelector('.svg-container > svg')
svgElement?.removeAttribute('width')
svgElement?.removeAttribute('height')
// SVG
if (!svgElement)
return
// point-name
const pointElements = svgElement.querySelectorAll('[point-name]')
const pointList: string[] = []
// 使point-name
pointElements.forEach((element) => {
const pointName = element.getAttribute('point-name')
if (pointName)
pointList.push(pointName)
})
point.value = { itemNameArray: pointList }
const res = await getEXANowListReal(point.value)
if (res && res.ReturnValue === 1 && res.ValueArray) {
const dataValues = res.ValueArray
if (pointElements) {
pointElements.forEach((element, index) => {
//
const value = dataValues[index] || ''
//
element.textContent = String(value)
// data-value便
element.setAttribute('data-value', String(value))
})
}
}
}
catch (error) {
console.error('更新实时数据失败:', error)
}
}
const updateInterval = ref<NodeJS.Timeout | null>(null)
onMounted(() => {
// 便
updateInterval.value = setInterval(() => {
console.log('定时更新数据...')
updateRealtimeValues()
}, 1000)
})
onUnmounted(() => {
//
clearInterval(updateInterval.value!)
})
//
function toggleFullscreen() {
const container = $refs.svgContainer
if (isFullscreen())
exitFullscreen()
else
this.requestFullscreen(container)
}
//
function isFullscreen() {
return document.fullscreenElement
|| document.mozFullScreenElement
|| document.webkitFullscreenElement
|| document.msFullscreenElement
}
//
function requestFullscreen(element) {
if (element.requestFullscreen) {
element.requestFullscreen()
}
else if (element.mozRequestFullScreen) { // Firefox
element.mozRequestFullScreen()
}
else if (element.webkitRequestFullscreen) { // Chrome, Safari and Opera
element.webkitRequestFullscreen()
}
else if (element.msRequestFullscreen) { // IE/Edge
element.msRequestFullscreen()
}
}
//
function exitFullscreen() {
if (document.exitFullscreen) {
document.exitFullscreen()
}
else if (document.mozCancelFullScreen) { // Firefox
document.mozCancelFullScreen()
}
else if (document.webkitExitFullscreen) { // Chrome, Safari and Opera
document.webkitExitFullscreen()
}
else if (document.msExitFullscreen) { // IE/Edge
document.msExitFullscreen()
}
}
</script>
<template>
<!-- <Card class="enter-y !my-1" :title="data.Header || 'SVG可视化'"> -->
<div v-if="svgError" class="h-40 flex items-center justify-center text-red-500">
{{ svgError }}
</div>
<div v-else class="svg-container" 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%;
cursor: pointer; /* 点击时可以手动触发数据更新 */
}
</style>

287
src/views/dashboard/demo/components/svg.vue

@ -0,0 +1,287 @@
<script lang="ts" setup>
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import { getEXANowListReal } from '@/api/alert/exa'
const props = defineProps<{
path: string
}>()
// SVG
const svgContainer = ref<HTMLElement>()
// const { data } = toRefs(props)
const svgContent = ref<string>('')
const svgError = ref<string>('')
const point = ref<{ itemNameArray: string[] }>({ itemNameArray: [] })
// const pointElements = ref<NodeListOf<SVGElement> | undefined>()
//
watch(
() => props.path,
(newValue, oldValue) => {
//
console.log('a has changed', newValue)
if (newValue !== oldValue && newValue !== '' && newValue != null)
loadSvg()
},
{ immediate: true },
)
// SVG
async function loadSvg() {
console.log('加载SVG文件...')
if (!props.path) {
svgError.value = '未提供SVG路径'
return
}
svgError.value = ''
try {
// URL
let url = props.path
if (!url.startsWith('http') && !url.startsWith('/')) {
// assets
url = new URL(`../../../../assets/${url}`, import.meta.url).href
}
//
const timestamp = new Date().getTime()
if (url.includes('?'))
url += `&t=${timestamp}`
else
url += `?t=${timestamp}`
const response = await fetch(url)
if (!response.ok)
throw new Error(`无法加载SVG: ${response.statusText}`)
svgContent.value = await response.text()
// DOM
await nextTick()
document.querySelector('.svg-container > svg')?.setAttribute('width', '100%')
document.querySelector('.svg-container > svg')?.setAttribute('height', '100%')
document.querySelector('.svg-container > svg')?.setAttribute('preserveAspectRatio', 'none')
// updateRealtimeValues()
}
catch (error) {
console.error('加载SVG失败:', error)
svgError.value = `加载失败: ${error instanceof Error ? error.message : String(error)}`
}
}
// SVG
async function updateRealtimeValues() {
if (!svgContent.value)
return
try {
const svgElement = document.querySelector('.svg-container > svg')
svgElement?.setAttribute('width', '100%')
svgElement?.setAttribute('height', '100%')
svgElement?.setAttribute('preserveAspectRatio', 'none')
// SVG
if (!svgElement)
return
// point-name
const pointElements = svgElement.querySelectorAll('[point-name]')
const pointList: string[] = []
// 使point-name
pointElements.forEach((element) => {
const pointName = element.getAttribute('point-name')
if (pointName)
pointList.push(pointName)
})
point.value = { itemNameArray: pointList }
const res = await getEXANowListReal(point.value)
if (res && res.ReturnValue === 1 && res.ValueArray) {
const dataValues = res.ValueArray
if (pointElements) {
pointElements.forEach((element, index) => {
//
const value = dataValues[index] || ''
//
element.textContent = String(value)
// data-value便
element.setAttribute('data-value', String(value))
})
}
}
}
catch (error) {
console.error('更新实时数据失败:', error)
}
}
const updateInterval = ref<NodeJS.Timeout | null>(null)
onMounted(() => {
// 便
updateInterval.value = setInterval(() => {
console.log('定时更新数据...')
updateRealtimeValues()
}, 1000)
})
onUnmounted(() => {
//
clearInterval(updateInterval.value!)
})
//
function toggleFullscreen() {
const container = svgContainer.value
if (!container)
return
if (isFullscreen())
exitFullscreen()
else
requestFullscreen(container)
}
//
function isFullscreen() {
return document.fullscreenElement
|| document.mozFullScreenElement
|| document.webkitFullscreenElement
|| document.msFullscreenElement
}
//
function requestFullscreen(element) {
if (element.requestFullscreen) {
element.requestFullscreen()
}
else if (element.mozRequestFullScreen) { // Firefox
element.mozRequestFullScreen()
}
else if (element.webkitRequestFullscreen) { // Chrome, Safari and Opera
element.webkitRequestFullscreen()
}
else if (element.msRequestFullscreen) { // IE/Edge
element.msRequestFullscreen()
}
}
//
function exitFullscreen() {
if (document.exitFullscreen) {
document.exitFullscreen()
}
else if (document.mozCancelFullScreen) { // Firefox
document.mozCancelFullScreen()
}
else if (document.webkitExitFullscreen) { // Chrome, Safari and Opera
document.webkitExitFullscreen()
}
else if (document.msExitFullscreen) { // IE/Edge
document.msExitFullscreen()
}
}
// 2. 使 defineExpose greet
defineExpose({
toggleFullscreen,
})
</script>
<template>
<div class="svg-wrapper">
<!-- 控制栏
<div class="svg-controls">
<h3 class="svg-title">
SVG可视化
</h3>
<button class="fullscreen-btn" title="切换全屏" @click="toggleFullscreen">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" />
</svg>
</button>
</div> -->
<!-- SVG内容 -->
<div v-if="svgError" class="h-40 flex items-center justify-center text-red-500">
{{ svgError }}
</div>
<div v-else ref="svgContainer" class="svg-container" v-html="svgContent" />
</div>
</template>
<style scoped>
.svg-wrapper {
width:100%;
height:100%;
border: 1px solid #e8e8e8;
border-radius: 6px;
/* overflow: auto; */
}
/* .svg-controls {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 16px;
background-color: #f5f5f5;
border-bottom: 1px solid #e8e8e8;
}
.svg-title {
margin: 0;
font-size: 16px;
font-weight: 500;
color: #333;
} */
.svg-container {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height:100%;
min-height: 300px;
overflow: auto;
}
/* 全屏状态样式 */
:global(.svg-wrapper:fullscreen),
:global(.svg-wrapper:-webkit-full-screen),
:global(.svg-wrapper:-moz-full-screen),
:global(.svg-wrapper:-ms-fullscreen) {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
border: none;
border-radius: 0;
}
:global(.svg-wrapper:fullscreen) .svg-container,
:global(.svg-wrapper:-webkit-full-screen) .svg-container,
:global(.svg-wrapper:-moz-full-screen) .svg-container,
:global(.svg-wrapper:-ms-fullscreen) .svg-container {
flex: 1;
padding: 20px;
width:100%;
height:100%;
}
/* SVG内容自适应 */
.svg-container {
/* max-width: 100%;
max-height: 100%; */
height:100%;
width:100%
}
svg {
height:98%;
width:100%;
}
</style>

68
src/views/dashboard/demo/index copy.vue

@ -1,68 +0,0 @@
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import WorkbenchHeader from './components/WorkbenchHeader.vue'
import ProjectCard from './components/ProjectCard.vue'
import DynamicInfo from './components/DynamicInfo.vue'
import StaticImg from './components/staticImg.vue'
import ParameterInfo from './components/ParameterInfo.vue'
import Operation from './components/Operation.vue'
import data from './components/demo.json'
import { PageWrapper } from '@/components/Page'
const loading = ref(true)
onMounted(() => {
const htmlRoot = document.getElementsByClassName('workbench')
// let theme = window.localStorage.getItem('__APP__DARK__MODE__')
const theme = 'dark'
if (htmlRoot && theme) {
for (let i = 0; i < htmlRoot.length; i++)
htmlRoot[i].setAttribute('data-theme', theme)
}
// theme = htmlRoot = null
})
setTimeout(() => {
loading.value = false
}, 500)
</script>
<template>
<div class="workbench m-1" data-theme="light">
<WorkbenchHeader class="workbench m-1" data-theme="light" :data="data" />
<div class="enter-y workbench h-92 md:flex" data-theme="light">
<StaticImg data-theme="light" class="workbench m-1 w-full md:w-1/4" :loading="loading" :data="data.LeftUp" />
<ProjectCard data-theme="light" class="enter-y workbench m-1 w-full md:w-1/2" :loading="loading" :data="data.LeftMidUp" />
<div class="enter-y w-full !mr-4 md:w-1/4">
<DynamicInfo :loading="loading" data-theme="light" class="workbench enter-y m-1 h-35 w-full" :data="data.RightMidUp" />
<Operation data-theme="light" class="workbench enter-y m-1 h-54 w-full" :loading="loading" :data="data.RightUp" />
</div>
</div>
<div class="enter-y workbench h-95 md:flex" data-theme="light">
<StaticImg data-theme="light" class="workbench m-1 w-full md:w-1/2" :loading="loading" :data="data.LeftDown" />
<ParameterInfo data-theme="light" class="workbench m-1 w-full md:w-1/2" :loading="loading" :data="data.RightDown" />
</div>
<!-- <div class="enter-y w-full !mr-4 lg:w-7/10">
<StaticImg :loading="loading" :data="data.LeftUp" class="enter-y" />
</div> -->
<!-- <div class="enter-y w-full !mr-4 lg:w-7/10">
<ProjectCard :loading="loading" class="enter-y" />
<DynamicInfo :loading="loading" class="enter-y !my-4" />
</div>
<div class="enter-y w-full lg:w-3/10">
<QuickNav :loading="loading" class="enter-y" />
<Card class="enter-y !my-4" :loading="loading">
<img class="mx-auto h-30 xl:h-50" src="@/assets/svg/illustration.svg">
</Card>
<SaleRadar :loading="loading" class="enter-y" />
</div> -->
</div>
</template>
<style lang="less">
</style>

85
src/views/dashboard/demo/index.vue

@ -1,11 +1,11 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onBeforeMount, onMounted, ref } from 'vue' import { onMounted, ref } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { message } from 'ant-design-vue'
import WorkbenchHeader from './components/WorkbenchHeader.vue'
import ProjectCard from './components/ProjectCard.vue' import ProjectCard from './components/ProjectCard.vue'
import DynamicInfo from './components/DynamicInfo.vue' import DynamicInfo from './components/DynamicInfo.vue'
import StaticImg from './components/staticImg.vue' import StaticImg from './components/staticImg.vue'
import StaticSvg from './components/staticSvg.vue'
import ParameterInfo from './components/ParameterInfo.vue' import ParameterInfo from './components/ParameterInfo.vue'
import Operation from './components/Operation.vue' import Operation from './components/Operation.vue'
import data1 from './components/demo.json' import data1 from './components/demo.json'
@ -15,44 +15,42 @@ import { getExaNow } from '@/api/alert/exa'
const loading = ref(true) const loading = ref(true)
const route = useRoute() const route = useRoute()
const gridData = ref<any[]>([])
setTimeout(() => {
loading.value = false
}, 500)
// idcommitbug // idcommitbug
const id = route.path.split('/').pop() || '' const id = route.path.split('/').pop() || ''
const data = ref<any>(data1) const data = ref<any>(data1)
onMounted(async () => { onMounted(async () => {
console.log(route.path)
const res = await getDeviceInfo(id) const res = await getDeviceInfo(id)
console.log(res)
if (res) if (res)
data.value = JSON.parse(res.Page_Content) data.value = JSON.parse(res.Page_Content)
// getColor(data.value) // getNewData LeftMidUp
await getNewData()
loading.value = false
}) })
// async function getColor(data: any) { // ifColor
// const rows = data.LeftMidUp.Content || [] async function getNewData() {
// const gridData = [] as any[] const rows = data.value.LeftMidUp.Content || []
// for (const item of rows) { for (const item of rows) {
// try { try {
// const param = item.Point const param = item.Point
// const res = await getExaNow(param) const res = await getExaNow(param)
console.log(res)
// let ifColor: boolean = false let ifColor: boolean = false
// if (res != null) if (res != null)
// ifColor = res === '1' ifColor = res === '1'
// ifColor
// gridData.push(Object.assign({}, item, { ifColor })) item.ifColor = ifColor
}
// console.log(gridData) catch (e) {
// } // ifColorfalse
// catch (e) { item.ifColor = false
// } }
// } }
// data.LeftMidUp.Content = gridData console.log(data.value)
// } }
</script> </script>
<template> <template>
@ -60,36 +58,19 @@ onMounted(async () => {
<!-- <template #headerContent> <!-- <template #headerContent>
<WorkbenchHeader class="m-1" :data="data" /> <WorkbenchHeader class="m-1" :data="data" />
</template> --> </template> -->
<div class="h-[calc(91vh)] bg-[#f5f5f5]"> <div class="h-[calc(92vh)] bg-[#f5f5f5]">
<div class="enter-y h-[calc(91vh/2)] md:flex"> <div class="enter-y h-[calc(92vh/2)] md:flex">
<StaticImg class="m-1 w-full md:w-1/4" :loading="loading" :data="data.LeftUp || {}" /> <StaticImg class="m-1 w-full md:w-1/4" :loading="loading" :data="data.LeftUp || {}" />
<ProjectCard class="enter-y m-1 w-full md:w-1/2" :loading="loading" :data="data.LeftMidUp || {}" /> <ProjectCard class="enter-y m-1 w-full md:w-1/2" :loading="loading" :data="data.LeftMidUp || {}" />
<div class="enter-y h-[calc(91vh/2)] w-full md:w-1/4"> <div class="enter-y h-[calc(92vh/2)] w-full md:w-1/4">
<DynamicInfo :loading="loading" class="enter-y m-1 h-[calc(17vh)] w-full" :data="data.RightMidUp || {}" /> <DynamicInfo :loading="loading" class="enter-y m-1 h-[calc(17vh)] w-full" :data="data.RightMidUp || {}" />
<Operation class="enter-y m-1 h-[calc(27vh)] w-full" :loading="loading" :data="data.RightUp || {}" /> <Operation class="enter-y m-1 h-[calc(27vh)] w-full" :loading="loading" :data="data.RightUp || {}" />
</div> </div>
</div> </div>
<div class="enter-y h-[calc(91vh/2)] md:flex"> <div class="enter-y h-[calc(92vh/2)] md:flex">
<StaticImg class="m-1 w-full md:w-1/2" :loading="loading" :data="data.LeftDown || {}" /> <StaticSvg class="m-1 w-full md:w-1/2" :loading="loading" :data="data.LeftDown || {}" />
<ParameterInfo class="m-1 w-full md:w-1/2" :loading="loading" :data="data.RightDown || {}" /> <ParameterInfo class="m-1 w-full md:w-1/2" :loading="loading" :data="data.RightDown || {}" />
</div> </div>
<!-- <div class="enter-y w-full !mr-4 lg:w-7/10">
<StaticImg :loading="loading" :data="data.LeftUp" class="enter-y" />
</div> -->
<!-- <div class="enter-y w-full !mr-4 lg:w-7/10">
<ProjectCard :loading="loading" class="enter-y" />
<DynamicInfo :loading="loading" class="enter-y !my-4" />
</div>
<div class="enter-y w-full lg:w-3/10">
<QuickNav :loading="loading" class="enter-y" />
<Card class="enter-y !my-4" :loading="loading">
<img class="mx-auto h-30 xl:h-50" src="@/assets/svg/illustration.svg">
</Card>
<SaleRadar :loading="loading" class="enter-y" />
</div> -->
</div> </div>
</pagewrapper> </pagewrapper>
</template> </template>

Loading…
Cancel
Save