物联组态 添加冻干二 并实现动态虚线 冻干二数据对接

This commit is contained in:
shih
2026-05-09 12:35:03 +08:00
parent 760eccdecc
commit bbfd57e737
6 changed files with 1885 additions and 272 deletions

BIN
src/assets/picture/dg2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 641 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 880 KiB

View File

@@ -139,6 +139,11 @@ export const constantRoutes = [
component: () => import('@/views/scada/picture/screen'),
hidden: true,
},
{
path: '/scada/picture/screen2',
component: () => import('@/views/scada/picture/screen2'),
hidden: true,
},
];
// 动态路由,基于用户权限动态去加载

View File

@@ -2,12 +2,10 @@
<div class="center-wrap">
<div v-if="showType == 'card'">
<el-row :gutter="15">
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6" style="margin-top: 7.5px; margin-bottom: 7.5px"
v-for="item in centerList" :key="item.id">
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6" style="margin-top: 7.5px; margin-bottom: 7.5px" v-for="item in centerList" :key="item.id">
<el-card class="card-wrap" :body-style="{ padding: '10px' }">
<div class="img-wrap" @click="goToDetail(item)">
<el-image style="width: 100%; height: 100%; border-radius: 5px" lazy
:src="item.pageImage" fit="cover"></el-image>
<el-image style="width: 100%; height: 100%; border-radius: 5px" lazy :src="item.pageImage" fit="cover"></el-image>
</div>
<div class="tag-wrap">
<span>{{ item.pageResolution ? item.pageResolution : '未知' }}</span>
@@ -33,31 +31,59 @@ export default {
// 固定数据
centerList: [
{
"createBy": "1",
"createTime": "2026-03-23 17:31:51",
"updateBy": null,
"updateTime": "2026-03-23 17:31:51",
"remark": null,
"pageNum": null,
"pageSize": null,
"id": 5,
"guid": "2b5759ba-8ee7-43e8-bb72-234986e52715",
"scadaData": null,
"serialNumbers": null,
"deviceName": null,
"isMainPage": null,
"pageName": "国瑞药业冻干物联组态",
"pageResolution": null,
"isShare": null,
"shareUrl": null,
"sharePass": null,
"pageImage": require("../../../assets/picture/fengmian.png"),
"tenantId": null,
"tenantName": null,
"delFlag": 0,
"base64": null,
"bindDeviceList": null
}
createBy: '1',
createTime: '2026-05-07 10:00:00',
updateBy: null,
updateTime: '2026-05-07 10:00:00',
remark: null,
pageNum: null,
pageSize: null,
id: 6,
guid: '3c5859cb-9ff8-54f9-cc33-455077f66c26',
scadaData: null,
serialNumbers: null,
deviceName: null,
isMainPage: null,
pageName: '国瑞药业冻干物联组态',
pageResolution: null,
isShare: null,
shareUrl: null,
sharePass: null,
pageImage: require('../../../assets/picture/dg2slt.png'),
tenantId: null,
tenantName: null,
delFlag: 0,
base64: null,
bindDeviceList: null,
pagePath: 'screen2',
},
{
createBy: '1',
createTime: '2026-03-23 17:31:51',
updateBy: null,
updateTime: '2026-03-23 17:31:51',
remark: null,
pageNum: null,
pageSize: null,
id: 5,
guid: '2b5759ba-8ee7-43e8-bb72-234986e52715',
scadaData: null,
serialNumbers: null,
deviceName: null,
isMainPage: null,
pageName: '国瑞药业冻干三物联组态',
pageResolution: null,
isShare: null,
shareUrl: null,
sharePass: null,
pageImage: require('../../../assets/picture/fengmian.png'),
tenantId: null,
tenantName: null,
delFlag: 0,
base64: null,
bindDeviceList: null,
pagePath: 'screen',
},
],
total: 1, // 总条数
showType: 'card', // 展示方式
@@ -77,10 +103,11 @@ export default {
// guid: row.guid,
// },
// });
// 方法2: 在新标签页打开
const pagePath = row.pagePath || 'screen';
const routeData = this.$router.resolve({
path: '/scada/picture/screen',
path: `/scada/picture/${pagePath}`,
query: {
id: row.id,
guid: row.guid,
@@ -155,4 +182,4 @@ export default {
display: none !important;
}
}
</style>
</style>

View File

@@ -123,36 +123,60 @@
<div class="layout-container">
<img src="../../../assets/picture/c354ee887a2f66c387ef3cd49be905b3.png" alt="设备布局" class="layout-image" />
<!-- 标记点 -->
<div class="marker marker-1" @mouseenter="(e) => handleMarkerMouseEnter(1, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(1, e)"></div>
<div class="marker marker-2" @mouseenter="(e) => handleMarkerMouseEnter(2, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(2, e)"></div>
<div class="marker marker-3" @mouseenter="(e) => handleMarkerMouseEnter(3, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(3, e)"></div>
<div class="marker marker-4" @mouseenter="(e) => handleMarkerMouseEnter(4, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(4, e)"></div>
<div class="marker marker-5" @mouseenter="(e) => handleMarkerMouseEnter(5, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(5, e)"></div>
<div class="marker marker-6" @mouseenter="(e) => handleMarkerMouseEnter(6, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(6, e)"></div>
<div class="marker marker-7" @mouseenter="(e) => handleMarkerMouseEnter(7, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(7, e)"></div>
<div class="marker marker-8" @mouseenter="(e) => handleMarkerMouseEnter(8, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(8, e)"></div>
<div class="marker marker-9" @mouseenter="(e) => handleMarkerMouseEnter(98, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(9, e)"></div>
<div class="marker marker-16" @mouseenter="(e) => handleMarkerMouseEnter(16, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(10, e)"></div>
<div class="marker marker-15" @mouseenter="(e) => handleMarkerMouseEnter(15, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(11, e)"></div>
<div class="marker marker-17" @mouseenter="(e) => handleMarkerMouseEnter(17, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(12, e)"></div>
<!-- 流动线 -->
<div class="marker marker-1" @mouseenter="(e) => handleMarkerMouseEnter(1, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(1, 255, e)"></div>
<div class="marker marker-2" @mouseenter="(e) => handleMarkerMouseEnter(2, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(2, 256, e)"></div>
<div class="marker marker-3" @mouseenter="(e) => handleMarkerMouseEnter(3, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(3, 257, e)"></div>
<div class="marker marker-4" @mouseenter="(e) => handleMarkerMouseEnter(4, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(4, 258, e)"></div>
<div class="marker marker-5" @mouseenter="(e) => handleMarkerMouseEnter(5, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(5, 251, e)"></div>
<div class="marker marker-6" @mouseenter="(e) => handleMarkerMouseEnter(6, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(6, 252, e)"></div>
<div class="marker marker-7" @mouseenter="(e) => handleMarkerMouseEnter(7, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(7, 267, e)"></div>
<div class="marker marker-8" @mouseenter="(e) => handleMarkerMouseEnter(8, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(8, 269, e)"></div>
<div class="marker marker-9" @mouseenter="(e) => handleMarkerMouseEnter(98, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(9, 270, e)"></div>
<div class="marker marker-16" @mouseenter="(e) => handleMarkerMouseEnter(16, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(10, 250, e)"></div>
<div class="marker marker-15" @mouseenter="(e) => handleMarkerMouseEnter(15, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(11, 253, e)"></div>
<div class="marker marker-17" @mouseenter="(e) => handleMarkerMouseEnter(17, e)" @mouseleave="handleMarkerMouseLeave" @click.stop="(e) => handleMarkerClick(12, 282, e)"></div>
<!-- 流动线 -->
<div class="dashed-line dashed-line-1"></div>
<div class="dashed-line dashed-line-2"></div>
<div class="dashed-line dashed-line-3"></div>
<div class="dashed-line dashed-line-4"></div>
<div class="dashed-line dashed-line-5"></div>
<div class="dashed-line dashed-line-6"></div>
<div class="dashed-line dashed-line-7"></div>
<div class="dashed-line dashed-line-8"></div>
<div class="dashed-line dashed-line-9"></div>
<div class="dashed-line dashed-line-10"></div>
<div class="dashed-line dashed-line-11"></div>
<div class="dashed-line dashed-line-12"></div>
<div class="dashed-line dashed-line-13"></div>
<div class="dashed-line dashed-line-14"></div>
<div class="dashed-line dashed-line-15"></div>
<div class="dashed-line dashed-line-16"></div>
<div class="dashed-line dashed-line-17"></div>
<div class="dashed-line dashed-line-18"></div>
<div class="dashed-line dashed-line-19"></div>
<div class="dashed-line dashed-line-20"></div>
<div class="dashed-line dashed-line-21"></div>
<div class="dashed-line dashed-line-22"></div>
<div class="dashed-line dashed-line-23"></div>
<div class="dashed-line dashed-line-24"></div>
<div class="dashed-line dashed-line-25"></div>
<div class="dashed-line dashed-line-26"></div>
<div class="dashed-line dashed-line-27"></div>
<div class="dashed-line dashed-line-28"></div>
<div class="dashed-line dashed-line-29"></div>
<div class="dashed-line dashed-line-30"></div>
</div>
</div>
<!-- 标记点冒泡 -->
<!-- 标记点弹窗 -->
<div class="marker-popup" v-if="showMarkerPopup" :style="{ left: markerPopupPosition.x + 'px', top: markerPopupPosition.y + 'px' }" @click.stop>
<div class="popup-arrow"></div>
<div class="popup-close" @click="closeMarkerPopup">×</div>
<div class="popup-content">
<div class="popup-title">{{ markerPopupData.name }}</div>
<div class="popup-info">
<span class="popup-label">设备编号</span>
<span class="popup-value">{{ markerPopupData.id }}</span>
</div>
<div class="popup-info">
<span class="popup-label">设备状态</span>
<span class="status-badge" :class="getStatusClass(markerPopupData.status)">
{{ markerPopupData.statusText }}
</span>
<div v-for="(field, index) in markerPopupData.fields" :key="index" class="popup-row">
<span class="popup-label">{{ field.label }}</span>
<span class="popup-value">{{ field.value }}</span>
</div>
</div>
</div>
@@ -415,41 +439,131 @@ export default {
}
},
// 鼠标进入标记点
handleMarkerMouseEnter(markerId, event) {
const device = this.devices.find((d) => d.id === markerId);
handleMarkerMouseEnter(markerId, event) {},
// 鼠标离开标记点
handleMarkerMouseLeave() {},
// 点击标记点
handleMarkerClick(markerId, deviceId, event) {
const device = this.devices.find((d) => d.deviceId === deviceId);
let popupData;
this.markerPopupData = {
id: markerId,
name: device ? device.deviceName : `设备 ${markerId}`,
status: device ? device.status : 'unknown',
statusText: device ? this.getStatusText(device.status) : '未知',
};
if ([1, 2, 3, 4].includes(markerId)) {
const plateLayerBottleCount = device?.logs?.find((log) => log.identity === 'A01')?.logValue || 0;
const plateLayerRowCount = device?.logs?.find((log) => log.identity === 'A02')?.logValue || 0;
const bottleDiameter = device?.logs?.find((log) => log.identity === 'A03')?.logValue || 0;
const bottleDistance = device?.logs?.find((log) => log.identity === 'A04')?.logValue || 0;
const pushSpeedWithBottle = device?.logs?.find((log) => log.identity === 'A05')?.logValue || 0;
const pushSpeedWithoutBottle = device?.logs?.find((log) => log.identity === 'A06')?.logValue || 0;
const wrongBottlePosition = device?.logs?.find((log) => log.identity === 'A07')?.logValue || 0;
const firstRowExtraBottles = device?.logs?.find((log) => log.identity === 'A08')?.logValue || 0;
popupData = {
id: markerId,
name: device ? device.deviceName : `进料系统 ${markerId}`,
type: 'feeding',
fields: [
{ label: '板层每行瓶数', value: plateLayerBottleCount },
{ label: '板层西林瓶行数', value: plateLayerRowCount },
{ label: '西林瓶直径', value: bottleDiameter },
{ label: '理瓶距离', value: bottleDistance },
{ label: '理瓶推杆有瓶速度', value: pushSpeedWithBottle },
{ label: '理瓶推杆无瓶速度', value: pushSpeedWithoutBottle },
{ label: '错瓶位置', value: wrongBottlePosition },
{ label: '首行多瓶数', value: firstRowExtraBottles },
],
};
} else if ([5, 6, 10, 11].includes(markerId)) {
const freezeTemp1 = device?.logs?.find((log) => log.identity === 'A01')?.logValue || 0;
const freezeTemp2 = device?.logs?.find((log) => log.identity === 'A02')?.logValue || 0;
const freezeTemp3 = device?.logs?.find((log) => log.identity === 'A03')?.logValue || 0;
const freezeTemp4 = device?.logs?.find((log) => log.identity === 'A04')?.logValue || 0;
const freezeTemp5 = device?.logs?.find((log) => log.identity === 'A05')?.logValue || 0;
const freezeTemp6 = device?.logs?.find((log) => log.identity === 'A06')?.logValue || 0;
const freezeTemp7 = device?.logs?.find((log) => log.identity === 'A07')?.logValue || 0;
const freezeTemp8 = device?.logs?.find((log) => log.identity === 'A08')?.logValue || 0;
popupData = {
id: markerId,
name: device ? device.deviceName : `冻干机 ${markerId}`,
type: 'freeze2',
fields: [
{ label: '导热油进口温度', value: freezeTemp1 + ' °C' },
{ label: '后箱导热油进口温度', value: freezeTemp2 + ' °C' },
{ label: '后箱导热油出口温度', value: freezeTemp3 + ' °C' },
{ label: '导热油出口温度', value: freezeTemp4 + ' °C' },
{ label: '冷凝器温度1', value: freezeTemp5 + ' °C' },
{ label: '冷凝器温度2', value: freezeTemp6 + ' °C' },
{ label: '冷凝器出口温度1', value: freezeTemp7 + ' °C' },
{ label: '冷凝器出口温度2', value: freezeTemp8 + ' °C' },
],
};
} else if (markerId === 12) {
popupData = {
id: markerId,
name: device ? device.deviceName : '出料系统',
type: 'discharge',
fields: [
{ label: '电源运行信号', value: 0 },
{ label: '装载门关按钮信号', value: 0 },
{ label: '装载门开按钮信号', value: 0 },
{ label: '装载门关限位信号', value: 0 },
{ label: '装载门开到位限位信号', value: 0 },
{ label: '装载门关到位限位信号', value: 0 },
{ label: '装载门电机过载信号', value: 0 },
{ label: '装载门急停信号', value: 0 },
],
};
} else if ([7, 8, 9].includes(markerId)) {
const inspectorSpeed = device?.logs?.find((log) => log.identity === 'A01')?.logValue || 0;
const inspectorFeed = device?.logs?.find((log) => log.identity === 'A62')?.logValue || 0;
const inspectorQualified = device?.logs?.find((log) => log.identity === 'A63')?.logValue || 0;
const inspectorReject = device?.logs?.find((log) => log.identity === 'A64')?.logValue || 0;
const inspectorClawSpeed = device?.logs?.find((log) => log.identity === 'A07')?.logValue || 0;
popupData = {
id: markerId,
name: device ? device.deviceName : `灯检机 ${markerId - 4}`,
type: 'inspector',
fields: [
{ label: '运动参数-生产速度', value: inspectorSpeed },
{ label: '生产数据-进料产品', value: inspectorFeed },
{ label: '生产数据-合格品', value: inspectorQualified },
{ label: '生产数据-剔除总数', value: inspectorReject },
{ label: '夹爪-进料输送带速度', value: inspectorClawSpeed },
],
};
}
this.markerPopupData = popupData;
const markerElement = event.currentTarget;
if (markerElement) {
const rect = markerElement.getBoundingClientRect();
const popupWidth = 340;
const popupHeight = 280;
const taskbarHeight = 100;
let popupX = rect.right + 20;
let popupY = rect.top - popupHeight;
if (popupX + popupWidth > window.innerWidth) {
popupX = rect.left - popupWidth - 20;
}
if (popupX < 10) {
popupX = 10;
}
if (popupY < 10) {
popupY = rect.bottom + 20;
}
if (popupY + popupHeight > window.innerHeight - taskbarHeight) {
popupY = window.innerHeight - taskbarHeight - popupHeight - 15;
}
this.markerPopupPosition = {
x: rect.left + rect.width / 2,
y: rect.top - 100,
x: popupX,
y: popupY,
};
}
this.showMarkerPopup = true;
},
// 鼠标离开标记点
handleMarkerMouseLeave() {
if (!this.markerPopupLocked) {
this.showMarkerPopup = false;
this.markerPopupData = {};
}
},
// 点击标记点
handleMarkerClick(markerId, event) {
if (!this.markerPopupLocked) {
this.markerPopupLocked = true;
document.addEventListener('click', this.handleDocumentClick);
}
},
handleDocumentClick(event) {
const popup = document.querySelector('.marker-popup');
const markers = document.querySelectorAll('.marker');
@@ -761,8 +875,9 @@ export default {
.layout-container {
position: relative;
width: 90%;
height: 90%;
width: 100%;
max-width: 1600px;
aspect-ratio: 2560 / 1024;
display: flex;
align-items: center;
justify-content: center;
@@ -770,222 +885,85 @@ export default {
.marker {
position: absolute;
width: 30px;
height: 30px;
width: 2.5%;
height: 6%;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
transform: translate(-50%, -50%);
cursor: pointer;
transition: transform 0.3s ease;
}
.marker:hover {
transform: translate(-50%, -50%) scale(1.2);
}
.marker-1 {
transform: scale(1.5);
top: 45%; /* 相对于父元素高度的百分比 */
left: 16%; /* 相对于父元素宽度的百分比 */
top: 51%;
left: 19%;
background-image: url('../../../assets/picture/371b06b22391dea6aa6adf7fb36c7d2b.png');
position: absolute; /* 确保使用绝对定位,父元素需设置相对定位 */
/* 可选:防止标记点变形 */
background-size: contain;
background-repeat: no-repeat;
background-position: center;
/* 可选:使用视口单位作为备选 */
/* top: 10vh;
left: 64vw; */
}
.marker-2 {
transform: scale(1.5);
top: 45%; /* 相对于父元素高度的百分比 */
left: 24.6%; /* 相对于父元素宽度的百分比 */
top: 51%;
left: 25.7%;
background-image: url('../../../assets/picture/371b06b22391dea6aa6adf7fb36c7d2b.png');
position: absolute; /* 确保使用绝对定位,父元素需设置相对定位 */
/* 可选:防止标记点变形 */
background-size: contain;
background-repeat: no-repeat;
background-position: center;
/* 可选:使用视口单位作为备选 */
/* top: 10vh;
left: 64vw; */
}
.marker-3 {
transform: scale(1.5);
top: 45%; /* 相对于父元素高度的百分比 */
left: 33.5%; /* 相对于父元素宽度的百分比 */
top: 51%;
left: 34.7%;
background-image: url('../../../assets/picture/371b06b22391dea6aa6adf7fb36c7d2b.png');
position: absolute; /* 确保使用绝对定位,父元素需设置相对定位 */
/* 可选:防止标记点变形 */
background-size: contain;
background-repeat: no-repeat;
background-position: center;
/* 可选:使用视口单位作为备选 */
/* top: 10vh;
left: 64vw; */
}
.marker-4 {
transform: scale(1.5);
top: 42%; /* 相对于父元素高度的百分比 */
left: 42.6%; /* 相对于父元素宽度的百分比 */
top: 48%;
left: 43.6%;
background-image: url('../../../assets/picture/371b06b22391dea6aa6adf7fb36c7d2b.png');
position: absolute; /* 确保使用绝对定位,父元素需设置相对定位 */
/* 可选:防止标记点变形 */
background-size: contain;
background-repeat: no-repeat;
background-position: center;
/* 可选:使用视口单位作为备选 */
/* top: 10vh;
left: 64vw; */
}
.marker-5 {
transform: scale(1.5);
top: 55%; /* 相对于父元素高度的百分比 */
left: 26.6%; /* 相对于父元素宽度的百分比 */
top: 55%;
left: 27.5%;
background-image: url('../../../assets/picture/633bec62b4c6d35098f06c189591135d.png');
position: absolute; /* 确保使用绝对定位,父元素需设置相对定位 */
/* 可选:防止标记点变形 */
background-size: contain;
background-repeat: no-repeat;
background-position: center;
/* 可选:使用视口单位作为备选 */
/* top: 10vh;
left: 64vw; */
}
.marker-6 {
transform: scale(1.5);
top: 55%; /* 相对于父元素高度的百分比 */
left: 35.6%; /* 相对于父元素宽度的百分比 */
top: 55%;
left: 36.5%;
background-image: url('../../../assets/picture/633bec62b4c6d35098f06c189591135d.png');
position: absolute; /* 确保使用绝对定位,父元素需设置相对定位 */
/* 可选:防止标记点变形 */
background-size: contain;
background-repeat: no-repeat;
background-position: center;
/* 可选:使用视口单位作为备选 */
/* top: 10vh;
left: 64vw; */
}
.marker-15 {
transform: scale(1.5);
top: 55%; /* 相对于父元素高度的百分比 */
left: 44.6%; /* 相对于父元素宽度的百分比 */
top: 55%;
left: 45.5%;
background-image: url('../../../assets/picture/633bec62b4c6d35098f06c189591135d.png');
position: absolute; /* 确保使用绝对定位,父元素需设置相对定位 */
/* 可选:防止标记点变形 */
background-size: contain;
background-repeat: no-repeat;
background-position: center;
/* 可选:使用视口单位作为备选 */
/* top: 10vh;
left: 64vw; */
}
.marker-16 {
transform: scale(1.5);
top: 55%; /* 相对于父元素高度的百分比 */
left: 17.6%; /* 相对于父元素宽度的百分比 */
top: 55%;
left: 16.6%;
background-image: url('../../../assets/picture/633bec62b4c6d35098f06c189591135d.png');
position: absolute; /* 确保使用绝对定位,父元素需设置相对定位 */
/* 可选:防止标记点变形 */
background-size: contain;
background-repeat: no-repeat;
background-position: center;
/* 可选:使用视口单位作为备选 */
/* top: 10vh;
left: 64vw; */
}
.marker-7 {
transform: scale(1.5);
top: 10%; /* 相对于父元素高度的百分比 */
left: 64%; /* 相对于父元素宽度的百分比 */
top: 30%;
left: 65.2%;
background-image: url('../../../assets/picture/b257f08f180fba833e8302c54f815ba8.png');
position: absolute; /* 确保使用绝对定位,父元素需设置相对定位 */
/* 可选:防止标记点变形 */
background-size: contain;
background-repeat: no-repeat;
background-position: center;
/* 可选:使用视口单位作为备选 */
/* top: 10vh;
left: 64vw; */
}
.marker-8 {
transform: scale(1.5);
top: 24%; /* 相对于父元素高度的百分比 */
left: 64.7%; /* 相对于父元素宽度的百分比 */
top: 38%;
left: 65.7%;
background-image: url('../../../assets/picture/b257f08f180fba833e8302c54f815ba8.png');
position: absolute; /* 确保使用绝对定位,父元素需设置相对定位 */
/* 可选:防止标记点变形 */
background-size: contain;
background-repeat: no-repeat;
background-position: center;
/* 可选:使用视口单位作为备选 */
/* top: 10vh;
left: 64vw; */
}
.marker-9 {
transform: scale(1.5);
top: 39%; /* 相对于父元素高度的百分比 */
left: 65.3%; /* 相对于父元素宽度的百分比 */
top: 47%;
left: 66.2%;
background-image: url('../../../assets/picture/b257f08f180fba833e8302c54f815ba8.png');
position: absolute; /* 确保使用绝对定位,父元素需设置相对定位 */
/* 可选:防止标记点变形 */
background-size: contain;
background-repeat: no-repeat;
background-position: center;
/* 可选:使用视口单位作为备选 */
/* top: 10vh;
left: 64vw; */
}
.marker-17 {
transform: scale(1.5);
top: 68%; /* 相对于父元素高度的百分比 */
left: 15%; /* 相对于父元素宽度的百分比 */
top: 64%;
left: 16%;
background-image: url('../../../assets/picture/2729bbc4b984dec97dbb2d97ceb39ae6.png');
position: absolute; /* 确保使用绝对定位,父元素需设置相对定位 */
/* 可选:防止标记点变形 */
background-size: contain;
background-repeat: no-repeat;
background-position: center;
/* 可选:使用视口单位作为备选 */
/* top: 10vh;
left: 64vw; */
}
.chart-container {
@@ -1032,6 +1010,27 @@ export default {
transform: rotate(0deg);
}
/* 虚线样式 */
.dashed-line {
position: absolute;
z-index: 4;
height: 6px;
background: repeating-linear-gradient(90deg, #0ea5e9 0px, #0ea5e9 12px, #0f172a 12px, #0f172a 20px);
background-size: 20px 6px;
border-radius: 3px;
animation: dashFlow 0.6s linear infinite;
box-shadow: 0 0 8px rgba(14, 165, 233, 0.6);
}
@keyframes dashFlow {
0% {
background-position: 0 0;
}
100% {
background-position: 20px 0;
}
}
@keyframes flow {
0% {
transform: rotate(var(--flow-rotation, 0deg)) translateX(-100%);
@@ -1122,64 +1121,267 @@ export default {
animation-delay: 1.5s;
--flow-rotation: 0deg;
}
.dashed-line-1 {
top: 48.2%;
left: 15.2%;
width: 11%;
transform: rotate(181deg);
}
.dashed-line-2 {
top: 36%;
left: 22.4%;
width: 10%;
transform: rotate(105deg);
}
.dashed-line-3 {
top: 50%;
left: 14%;
width: 2%;
transform: rotate(-250deg);
}
.dashed-line-4 {
top: 53%;
left: 14.5%;
width: 12.7%;
transform: rotate(1deg);
}
.dashed-line-5 {
top: 68%;
left: 17%;
width: 34.7%;
transform: rotate(0deg);
}
.dashed-line-6 {
top: 36.2%;
left: 36.2%;
width: 10%;
transform: rotate(95deg);
}
.dashed-line-7 {
top: 61%;
left: 16.5%;
width: 26.7%;
transform: rotate(180deg);
}
.dashed-line-8 {
top: 55%;
left: 41%;
width: 5%;
transform: rotate(95deg);
}
.dashed-line-9 {
top: 57%;
left: 34%;
width: 3%;
transform: rotate(99deg);
}
.dashed-line-10 {
top: 57%;
left: 25.3%;
width: 3%;
transform: rotate(101deg);
}
.dashed-line-11 {
top: 59%;
left: 14%;
width: 5%;
transform: rotate(103deg);
}
.dashed-line-12 {
top: 49%;
left: 40.6%;
width: 3.2%;
transform: rotate(3deg);
}
.dashed-line-13 {
top: 53%;
left: 35.6%;
width: 8%;
transform: rotate(-180deg);
}
.dashed-line-14 {
top: 60.5%;
left: 56.5%;
width: 4%;
transform: rotate(0deg);
}
.dashed-line-15 {
top: 47.2%;
left: 54.4%;
width: 10.8%;
transform: rotate(262deg);
}
.dashed-line-16 {
top: 33.8%;
left: 57.7%;
width: 1.5%;
transform: rotate(180deg);
}
.dashed-line-17 {
top: 40.2%;
left: 58%;
width: 1.5%;
transform: rotate(180deg);
}
.dashed-line-18 {
top: 47.2%;
left: 58.2%;
width: 1.5%;
transform: rotate(180deg);
}
.dashed-line-19 {
top: 36.8%;
left: 59.2%;
width: 3.9%;
transform: rotate(-2deg);
}
.dashed-line-20 {
top: 45.2%;
left: 59.7%;
width: 3.9%;
transform: rotate(-2deg);
}
.dashed-line-21 {
top: 55.2%;
left: 60.2%;
width: 3.9%;
transform: rotate(-2deg);
}
.dashed-line-22 {
top: 37.8%;
left: 67.5%;
width: 11.5%;
transform: rotate(0deg);
}
.dashed-line-23 {
top: 45.8%;
left: 68.5%;
width: 11.5%;
transform: rotate(0deg);
}
.dashed-line-24 {
top: 55.8%;
left: 69.3%;
width: 11.5%;
transform: rotate(0deg);
}
.dashed-line-25 {
top: 46.9%;
left: 67.7%;
width: 7.1%;
transform: rotate(256deg);
}
.dashed-line-26 {
top: 44%;
left: 74.7%;
width: 10%;
transform: rotate(251deg);
}
.dashed-line-27 {
top: 32.5%;
left: 78.3%;
width: 0.5%;
transform: rotate(0deg);
}
.dashed-line-28 {
top: 32.3%;
left: 82%;
width: 4%;
transform: rotate(0deg);
}
.dashed-line-29 {
top: 40.3%;
left: 83.3%;
width: 4.1%;
transform: rotate(0deg);
}
.dashed-line-30 {
top: 38.7%;
left: 84.1%;
width: 6.1%;
transform: rotate(66deg);
}
/* 标记点冒泡样式 */
.marker-popup {
position: fixed;
z-index: 1000;
transform: translateX(-50%);
pointer-events: none;
}
.popup-content {
background: linear-gradient(135deg, rgba(10, 22, 40, 0.85) 0%, rgba(26, 42, 74, 0.85) 100%);
border: 1px solid rgba(0, 255, 255, 0.5);
border-radius: 8px;
padding: 15px 20px;
min-width: 200px;
box-shadow: 0 0 20px rgba(0, 255, 255, 0.2);
background: linear-gradient(135deg, rgba(5, 15, 30, 0.95) 0%, rgba(15, 30, 60, 0.95) 100%);
border: 2px solid rgba(0, 153, 255, 0.8);
border-radius: 12px;
padding: 20px 25px;
min-width: 320px;
box-shadow: 0 0 30px rgba(0, 153, 255, 0.5), inset 0 0 30px rgba(0, 153, 255, 0.1);
pointer-events: auto;
backdrop-filter: blur(10px);
backdrop-filter: blur(15px);
}
.popup-arrow {
.popup-close {
position: absolute;
bottom: -8px;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-top: 8px solid #00ffff;
top: -12px;
right: -12px;
width: 28px;
height: 28px;
background: rgba(0, 153, 255, 0.9);
border: 2px solid #00ffff;
border-radius: 50%;
color: #ffffff;
font-size: 20px;
font-weight: bold;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 0 10px rgba(0, 255, 255, 0.8);
z-index: 10;
pointer-events: auto;
}
.popup-close:hover {
background: rgba(255, 0, 0, 0.8);
border-color: #ff0000;
}
.popup-title {
font-size: 16px;
font-size: 18px;
font-weight: bold;
color: #00ffff;
margin-bottom: 10px;
margin-bottom: 15px;
text-align: center;
padding-bottom: 10px;
border-bottom: 1px solid rgba(0, 255, 255, 0.3);
}
.popup-info {
.popup-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
padding: 8px 0;
border-bottom: 1px solid rgba(0, 255, 255, 0.1);
}
.popup-info:last-child {
margin-bottom: 0;
.popup-row:last-child {
border-bottom: none;
}
.popup-label {
color: #888888;
font-size: 12px;
margin-right: 8px;
color: #00d4ff;
font-size: 13px;
}
.popup-value {
color: #ffffff;
font-size: 12px;
font-size: 14px;
font-weight: bold;
}
</style>

File diff suppressed because it is too large Load Diff