diff --git a/src/view/largeScreen2/index.vue b/src/view/largeScreen2/index.vue
index 5159d2a..d75e54e 100644
--- a/src/view/largeScreen2/index.vue
+++ b/src/view/largeScreen2/index.vue
@@ -102,6 +102,7 @@
+
全国设备态势
REAL-TIME DISTRIBUTION
@@ -233,6 +234,10 @@
let resizeObserver = null
const mapInstance = ref(null)
const markers = ref([])
+ let buildingsLayer = null
+
+ const default3DCenter = [120.153576, 30.287459]
+ const default3DZoom = 17.6
const tableData = ref([])
@@ -391,12 +396,38 @@
}))
console.log('devices', devices.value)
nextTick(() => {
+ if (mapInstance.value) {
+ mapInstance.value.setZoomAndCenter(default3DZoom, getValidDeviceCenter())
+ }
addMarkers()
})
}
})
}
+ const getValidDeviceCenter = () => {
+ const firstValidDevice = devices.value.find((device) => {
+ const longitude = Number(device.gatewayLong)
+ const latitude = Number(device.gatewayLat)
+ return Number.isFinite(longitude) && Number.isFinite(latitude)
+ })
+
+ if (!firstValidDevice) return default3DCenter
+ return [Number(firstValidDevice.gatewayLong), Number(firstValidDevice.gatewayLat)]
+ }
+
+ const add3DBuildingLayer = () => {
+ if (!mapInstance.value || typeof AMap === 'undefined' || !AMap.Buildings) return
+
+ buildingsLayer = new AMap.Buildings({
+ zooms: [3, 20],
+ heightFactor: 1.6,
+ wallColor: 'rgba(42, 169, 255, 0.88)',
+ roofColor: 'rgba(139, 233, 255, 0.78)'
+ })
+ mapInstance.value.add(buildingsLayer)
+ }
+
const initMap = () => {
if (typeof AMap === 'undefined') {
console.error('高德地图API未加载')
@@ -406,21 +437,32 @@
console.log('开始初始化地图')
mapInstance.value = new AMap.Map('chinaMap', {
- zoom: 4.8,
- center: [105.6, 36.4],
- mapStyle: 'amap://styles/darkblue',
+ zoom: default3DZoom,
+ zooms: [3, 20],
+ center: getValidDeviceCenter(),
+ mapStyle: 'amap://styles/blue',
viewMode: '3D',
- pitch: 34,
- rotation: -8,
+ pitch: 68,
+ rotation: -28,
+ terrain: true,
+ pitchEnable: true,
+ rotateEnable: true,
+ dragEnable: true,
+ zoomEnable: true,
+ buildingAnimation: true,
+ showBuildingBlock: true,
features: ['bg', 'road', 'building', 'point'],
showLabel: false,
skyColor: '#020713'
})
+ add3DBuildingLayer()
+
mapInstance.value.on('complete', () => {
console.log('地图加载完成')
- // 地图加载完成后,再尝试添加标记点
if (devices.value && devices.value.length > 0) {
+ const center = getValidDeviceCenter()
+ mapInstance.value.setZoomAndCenter(default3DZoom, center)
addMarkers()
}
})
@@ -450,8 +492,12 @@
testData.forEach((device, index) => {
// console.log(`渲染第 ${index} 个点:`, device)
+ const longitude = Number(device.gatewayLong)
+ const latitude = Number(device.gatewayLat)
+ if (!Number.isFinite(longitude) || !Number.isFinite(latitude)) return
+
const marker = new AMap.Marker({
- position: [device.gatewayLong, device.gatewayLat],
+ position: [longitude, latitude],
content: createMarkerContent(device.status),
anchor: 'bottom-center',
zIndex: 120
@@ -584,53 +630,63 @@
.device-stat-content {
display: flex;
- // gap: 0.2rem;
+ align-items: center;
+ gap: 0.1rem;
flex: 1;
+ min-height: 0;
+ overflow: hidden;
}
.device-ring-chart {
- flex: 1;
- min-height: 1.5rem;
- height: 100%;
- width: 100%;
+ flex: 0 0 1.58rem;
+ width: 1.58rem;
+ height: 1.58rem;
+ min-width: 1.58rem;
+ min-height: 1.58rem;
}
.device-list {
- flex: 0.8;
+ flex: 1;
+ min-width: 0;
display: flex;
flex-direction: column;
- // gap: 0.12rem;
+ justify-content: center;
+ gap: 0.03rem;
+ overflow: visible;
}
.device-item {
display: flex;
align-items: center;
- gap: 0.12rem;
- font-size: 0.18rem;
+ gap: 0.05rem;
+ min-width: 0;
+ font-size: 0.12rem;
font-weight: bold;
white-space: nowrap;
}
.device-dot {
- width: 0.1rem;
- height: 0.1rem;
+ flex: 0 0 auto;
+ width: 0.08rem;
+ height: 0.08rem;
border-radius: 2px;
}
.device-name {
color: var(--tech-text);
- flex: 1;
+ flex: 1 1 auto;
+ min-width: 0;
font-weight: bold;
white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
+ overflow: visible;
}
.device-count {
color: var(--tech-text);
+ flex: 0 0 auto;
font-weight: bold;
- font-size: 0.14rem;
- margin-right: 0.06rem;
+ font-size: 0.12rem;
+ margin-right: 0.01rem;
white-space: nowrap;
}
@@ -1099,8 +1155,47 @@
margin: 0;
overflow: hidden;
background:
- radial-gradient(circle at 50% 48%, rgba(0, 212, 255, 0.18), transparent 38%),
- linear-gradient(180deg, rgba(2, 8, 23, 0.18), rgba(2, 8, 23, 0.55));
+ radial-gradient(ellipse at 50% 64%, rgba(0, 212, 255, 0.3), transparent 45%),
+ linear-gradient(180deg, rgba(8, 47, 73, 0.04), rgba(2, 8, 23, 0.42));
+ perspective: 8rem;
+ }
+
+ .map-container-full .amap-layer,
+ .map-container-full .amap-maps,
+ .map-container-full canvas {
+ filter: brightness(1.22) saturate(1.18) contrast(1.06);
+ }
+
+ .map-container-full::before {
+ content: '';
+ position: absolute;
+ left: 8%;
+ right: 8%;
+ bottom: 0.34rem;
+ z-index: 998;
+ height: 2.4rem;
+ pointer-events: none;
+ background:
+ repeating-linear-gradient(90deg, rgba(0, 212, 255, 0.18) 0 1px, transparent 1px 0.38rem),
+ repeating-linear-gradient(0deg, rgba(0, 212, 255, 0.16) 0 1px, transparent 1px 0.38rem),
+ radial-gradient(ellipse at 50% 50%, rgba(0, 212, 255, 0.16), transparent 68%);
+ border: 1px solid rgba(0, 212, 255, 0.2);
+ border-radius: 50%;
+ box-shadow: 0 0 0.42rem rgba(0, 212, 255, 0.1);
+ transform: rotateX(68deg) translateY(0.2rem);
+ transform-origin: center bottom;
+ mix-blend-mode: screen;
+ }
+
+ .map-container-full::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ z-index: 999;
+ pointer-events: none;
+ background:
+ linear-gradient(180deg, rgba(137, 221, 255, 0.16), transparent 16%, transparent 72%, rgba(2, 8, 23, 0.24)),
+ linear-gradient(90deg, rgba(2, 8, 23, 0.28), transparent 16%, transparent 84%, rgba(2, 8, 23, 0.28));
}
.map-control {
@@ -1204,22 +1299,39 @@
.map-radar-glow {
position: absolute;
left: 50%;
- top: 52%;
+ top: 58%;
z-index: 1000;
- width: 5.2rem;
- height: 5.2rem;
+ width: 5.6rem;
+ height: 5.6rem;
border: 1px solid rgba(0, 212, 255, 0.22);
border-radius: 50%;
background:
repeating-radial-gradient(circle, transparent 0 0.62rem, rgba(0, 212, 255, 0.08) 0.63rem 0.64rem),
conic-gradient(from 0deg, transparent 0deg, rgba(0, 212, 255, 0.2) 46deg, transparent 88deg, transparent 360deg);
box-shadow: inset 0 0 0.42rem rgba(0, 212, 255, 0.08), 0 0 0.36rem rgba(0, 212, 255, 0.08);
- transform: translate(-50%, -50%);
- animation: radarRotate 12s linear infinite;
+ transform: translate(-50%, -50%) rotateX(62deg);
+ transform-origin: center center;
+ animation: radarRotate3d 12s linear infinite;
mix-blend-mode: screen;
pointer-events: none;
}
+ .map-3d-stage {
+ position: absolute;
+ left: 50%;
+ bottom: 0.28rem;
+ z-index: 1000;
+ width: 5.8rem;
+ height: 1.55rem;
+ pointer-events: none;
+ border: 1px solid rgba(245, 158, 11, 0.24);
+ border-radius: 50%;
+ background: radial-gradient(ellipse at center, rgba(245, 158, 11, 0.14), transparent 62%);
+ box-shadow: 0 0 0.32rem rgba(245, 158, 11, 0.1), inset 0 0 0.28rem rgba(0, 212, 255, 0.08);
+ transform: translateX(-50%);
+ mix-blend-mode: screen;
+ }
+
.map-corner {
position: absolute;
z-index: 1000;
@@ -1392,50 +1504,36 @@
.container .right .module-card {
position: relative;
overflow: hidden;
- border: 1px solid rgba(0, 212, 255, 0.16);
- border-radius: 0.08rem;
+ transform: scale(0.94);
+ transform-origin: center center;
+ border: none;
+ border-radius: 0;
background:
- linear-gradient(135deg, rgba(14, 165, 233, 0.12), rgba(15, 23, 42, 0.28) 44%, rgba(245, 158, 11, 0.07)),
- linear-gradient(180deg, rgba(15, 23, 42, 0.5), rgba(2, 6, 23, 0.18));
- box-shadow:
- inset 0 0 0.22rem rgba(0, 212, 255, 0.08),
- 0 0.08rem 0.28rem rgba(0, 0, 0, 0.28);
- backdrop-filter: blur(4px);
- transition: transform 0.35s ease, border-color 0.35s ease, box-shadow 0.35s ease;
-
- &::before {
- content: '';
- position: absolute;
- inset: 0;
- border-radius: inherit;
- padding: 1px;
- background: linear-gradient(135deg, rgba(0, 212, 255, 0.78), transparent 32%, transparent 62%, rgba(245, 158, 11, 0.55));
- mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
- mask-composite: exclude;
- pointer-events: none;
- opacity: 0.75;
- }
+ radial-gradient(circle at 12% 12%, rgba(0, 212, 255, 0.08), transparent 42%),
+ linear-gradient(135deg, rgba(14, 165, 233, 0.05), rgba(15, 23, 42, 0.1) 48%, rgba(245, 158, 11, 0.035));
+ box-shadow: none;
+ backdrop-filter: none;
+ transition: background 0.35s ease, transform 0.35s ease;
&::after {
content: '';
position: absolute;
top: 0;
- left: -65%;
- width: 45%;
+ left: -70%;
+ width: 38%;
height: 100%;
- background: linear-gradient(90deg, transparent, rgba(0, 212, 255, 0.16), transparent);
+ background: linear-gradient(90deg, transparent, rgba(0, 212, 255, 0.08), transparent);
transform: skewX(-18deg);
animation: cardGlint 7s ease-in-out infinite;
pointer-events: none;
+ mix-blend-mode: screen;
}
&:hover {
- transform: translateY(-0.02rem);
- border-color: rgba(0, 212, 255, 0.42);
- box-shadow:
- inset 0 0 0.28rem rgba(0, 212, 255, 0.13),
- 0 0.12rem 0.32rem rgba(0, 0, 0, 0.34),
- 0 0 0.22rem rgba(0, 212, 255, 0.18);
+ transform: scale(0.98);
+ background:
+ radial-gradient(circle at 12% 12%, rgba(0, 212, 255, 0.11), transparent 44%),
+ linear-gradient(135deg, rgba(14, 165, 233, 0.07), rgba(15, 23, 42, 0.12) 48%, rgba(245, 158, 11, 0.04));
}
}
@@ -1447,24 +1545,26 @@
content: '';
position: absolute;
left: 0;
- right: 0;
+ right: 18%;
bottom: -0.06rem;
height: 1px;
- background: linear-gradient(90deg, rgba(0, 212, 255, 0.8), rgba(59, 130, 246, 0.2), transparent);
- box-shadow: 0 0 0.12rem rgba(0, 212, 255, 0.55);
+ background: linear-gradient(90deg, rgba(0, 212, 255, 0.34), rgba(59, 130, 246, 0.08), transparent);
+ box-shadow: 0 0 0.08rem rgba(0, 212, 255, 0.18);
+ opacity: 0.55;
}
}
.container .module-title {
color: #eefaff;
+ font-size: 0.18rem;
letter-spacing: 0.02rem;
text-shadow: 0 0 0.12rem rgba(0, 212, 255, 0.55);
}
.container .title-icon {
position: relative;
- width: 0.08rem;
- height: 0.26rem;
+ width: 0.07rem;
+ height: 0.23rem;
background: linear-gradient(180deg, #f59e0b 0%, #00e5ff 45%, #2563eb 100%);
box-shadow: 0 0 0.12rem rgba(0, 212, 255, 0.9);
animation: iconPulse 1.8s ease-in-out infinite;
@@ -1673,6 +1773,10 @@
}
}
+ .container .device-item {
+ padding: 0.04rem 0.04rem;
+ }
+
.container .device-dot,
.container .alert-dot,
.container .status-dot {
@@ -1988,6 +2092,15 @@
}
}
+ @keyframes radarRotate3d {
+ 0% {
+ transform: translate(-50%, -50%) rotateX(62deg) rotate(0deg);
+ }
+ 100% {
+ transform: translate(-50%, -50%) rotateX(62deg) rotate(360deg);
+ }
+ }
+
@keyframes controlGlint {
0%, 58% {
left: -70%;
diff --git a/src/view/largeScreen2/ttes.js b/src/view/largeScreen2/ttes.js
index db49594..58758bd 100644
--- a/src/view/largeScreen2/ttes.js
+++ b/src/view/largeScreen2/ttes.js
@@ -147,7 +147,7 @@ export const getDeviceStatOption = (deviceTypes) => {
series: [
{
type: 'pie',
- radius: ['45%', '70%'],
+ radius: ['42%', '68%'],
center: ['50%', '50%'],
avoidLabelOverlap: false,
itemStyle: pieItemStyle,
@@ -155,7 +155,7 @@ export const getDeviceStatOption = (deviceTypes) => {
show: true,
position: 'center',
formatter: `{total|${total}}\n{name|设备总数}`,
- rich: createCenterLabelRich(18, 12)
+ rich: createCenterLabelRich(16, 10)
},
labelLine: {
show: false