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