代码更新
This commit is contained in:
@@ -118,6 +118,44 @@ body:not(.login-light-mode) {
|
||||
color: var(--tech-text);
|
||||
}
|
||||
|
||||
.el-button:not(.el-button--primary):not(.el-button--success):not(.el-button--warning):not(.el-button--danger):not(.el-button--info):not(.is-link):not(.is-text) {
|
||||
--el-button-bg-color: rgba(2, 8, 23, 0.72);
|
||||
--el-button-border-color: rgba(0, 212, 255, 0.42);
|
||||
--el-button-text-color: #e9fbff;
|
||||
--el-button-hover-bg-color: rgba(0, 212, 255, 0.18);
|
||||
--el-button-hover-border-color: rgba(0, 212, 255, 0.72);
|
||||
--el-button-hover-text-color: #ffffff;
|
||||
--el-button-active-bg-color: rgba(0, 212, 255, 0.24);
|
||||
--el-button-active-border-color: rgba(0, 212, 255, 0.82);
|
||||
--el-button-active-text-color: #ffffff;
|
||||
--el-button-disabled-bg-color: rgba(15, 23, 42, 0.48);
|
||||
--el-button-disabled-border-color: rgba(0, 212, 255, 0.16);
|
||||
--el-button-disabled-text-color: rgba(220, 243, 255, 0.5);
|
||||
|
||||
color: var(--el-button-text-color) !important;
|
||||
font-weight: 700;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.82);
|
||||
background: var(--el-button-bg-color) !important;
|
||||
border-color: var(--el-button-border-color) !important;
|
||||
|
||||
.el-icon {
|
||||
color: currentColor;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: var(--el-button-hover-text-color) !important;
|
||||
background: var(--el-button-hover-bg-color) !important;
|
||||
border-color: var(--el-button-hover-border-color) !important;
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: var(--el-button-active-text-color) !important;
|
||||
background: var(--el-button-active-bg-color) !important;
|
||||
border-color: var(--el-button-active-border-color) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-input__inner::placeholder,
|
||||
.el-textarea__inner::placeholder {
|
||||
color: rgba(220, 243, 255, 0.56);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="scan-light"></div>
|
||||
<div class="container">
|
||||
<div class="left">
|
||||
<div class="module-card left-first-module">
|
||||
<div class="module-card left-first-module device-link-card" role="button" tabindex="0" @click="goToEquipmentOverview" @keyup.enter="goToEquipmentOverview">
|
||||
<div class="module-header">
|
||||
<div class="module-title">
|
||||
<span class="title-icon"></span>
|
||||
@@ -16,7 +16,7 @@
|
||||
<e-charts ref="deviceStatChartRef" :option="deviceStatOption" autoresize />
|
||||
</div>
|
||||
<div class="device-list">
|
||||
<div class="device-item" v-for="(item, index) in deviceTypes" :key="index">
|
||||
<div class="device-item" v-for="(item, index) in displayDeviceTypes" :key="index">
|
||||
<span class="device-dot" :style="{ backgroundColor: item.color }"></span>
|
||||
<span class="device-name">{{ item.name || item.deviceTypeName }}</span>
|
||||
<span class="device-count" :style="{ color: item.color }">{{ item.count || item.value }}</span>
|
||||
@@ -25,7 +25,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="module-card left-second-module">
|
||||
<div class="module-card left-second-module device-link-card" role="button" tabindex="0" @click="goToEquipmentOverview" @keyup.enter="goToEquipmentOverview">
|
||||
<div class="module-header">
|
||||
<div class="module-title">
|
||||
<span class="title-icon"></span>
|
||||
@@ -53,7 +53,7 @@
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="module-card left-third-module">
|
||||
<div class="module-card left-third-module device-link-card" role="button" tabindex="0" @click="goToEquipmentOverview" @keyup.enter="goToEquipmentOverview">
|
||||
<div class="module-header">
|
||||
<div class="module-title">
|
||||
<span class="title-icon"></span>
|
||||
@@ -96,7 +96,7 @@
|
||||
<div class="top2">
|
||||
<div class="card map-card">
|
||||
<div class="card-title" style="display: none">设备分布</div>
|
||||
<div class="map-container-full" id="chinaMap" ref="chinaMap">
|
||||
<div class="map-container-full" :class="`map-mode-${mapDisplayMode.toLowerCase()}`" id="chinaMap" ref="chinaMap">
|
||||
<div class="map-corner top-left"></div>
|
||||
<div class="map-corner top-right"></div>
|
||||
<div class="map-corner bottom-left"></div>
|
||||
@@ -107,6 +107,18 @@
|
||||
<span class="map-title-main">全国设备态势</span>
|
||||
<span class="map-title-sub">REAL-TIME DISTRIBUTION</span>
|
||||
</div>
|
||||
<div class="map-mode-switch">
|
||||
<button
|
||||
v-for="mode in mapModeOptions"
|
||||
:key="mode.value"
|
||||
class="map-mode-button"
|
||||
:class="{ active: mapDisplayMode === mode.value }"
|
||||
type="button"
|
||||
@click="switchMapMode(mode.value)"
|
||||
>
|
||||
{{ mode.label }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="map-control">
|
||||
<div class="control-top">
|
||||
<div class="control-title">设备总数量</div>
|
||||
@@ -163,7 +175,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="module-card alarm-pending-module">
|
||||
<div class="module-card alarm-pending-module alarm-link-card" role="button" tabindex="0" @click="goToAllAlarmPage" @keyup.enter="goToAllAlarmPage">
|
||||
<div class="module-header">
|
||||
<div class="module-title">
|
||||
<span class="title-icon"></span>
|
||||
@@ -175,7 +187,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="module-card alert-distribution-module">
|
||||
<div class="module-card alert-distribution-module alarm-link-card" role="button" tabindex="0" @click="goToAllAlarmPage" @keyup.enter="goToAllAlarmPage">
|
||||
<div class="module-header">
|
||||
<div class="module-title">
|
||||
<span class="title-icon"></span>
|
||||
@@ -198,7 +210,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="module-card alert-trend-module">
|
||||
<div class="module-card alert-trend-module alarm-link-card" role="button" tabindex="0" @click="goToAllAlarmPage" @keyup.enter="goToAllAlarmPage">
|
||||
<div class="module-header">
|
||||
<div class="module-title">
|
||||
<span class="title-icon"></span>
|
||||
@@ -215,10 +227,12 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/* global AMap */
|
||||
import * as serve from '@/api/largeScreen'
|
||||
import { useRouterStore } from '@/pinia/modules/router'
|
||||
|
||||
import { onMounted, onBeforeUnmount, ref, nextTick, computed } from 'vue'
|
||||
import * as echarts from 'echarts'
|
||||
import { useRouter } from 'vue-router'
|
||||
import ECharts from 'vue-echarts'
|
||||
import {
|
||||
getAlarmPendingOption,
|
||||
@@ -229,15 +243,26 @@
|
||||
} from './ttes.js'
|
||||
import { techChartSeriesColors } from '@/utils/techChartTheme'
|
||||
|
||||
const router = useRouter()
|
||||
const routerStore = useRouterStore()
|
||||
const ALL_ALARM_ROUTE_PATH = 'securityControl/alarmList'
|
||||
const EQUIPMENT_OVERVIEW_ROUTE_PATH = 'masterStation/equipment'
|
||||
|
||||
const bottomRef = ref(null)
|
||||
const tableHeight = ref(180)
|
||||
let resizeObserver = null
|
||||
const mapInstance = ref(null)
|
||||
const markers = ref([])
|
||||
const mapDisplayMode = ref('3D')
|
||||
const mapModeOptions = [
|
||||
{ label: '3D', value: '3D' },
|
||||
{ label: '2D', value: '2D' }
|
||||
]
|
||||
let buildingsLayer = null
|
||||
|
||||
const default3DCenter = [120.153576, 30.287459]
|
||||
const default3DZoom = 17.6
|
||||
const default2DZoom = 12
|
||||
|
||||
const tableData = ref([])
|
||||
|
||||
@@ -256,6 +281,7 @@
|
||||
]
|
||||
|
||||
const deviceTypes = ref([])
|
||||
const displayDeviceTypes = computed(() => deviceTypes.value.slice(0, 5))
|
||||
|
||||
const deviceChangeList = ref([])
|
||||
|
||||
@@ -295,6 +321,27 @@
|
||||
return type === 'device_online' ? 'status-online' : 'status-offline'
|
||||
}
|
||||
|
||||
const pushDynamicRoute = (routePath) => {
|
||||
const targetRoute = Object.values(routerStore.routeMap).find((route) => {
|
||||
return route.path === routePath || route.path?.endsWith(`/${routePath}`)
|
||||
})
|
||||
|
||||
if (targetRoute?.name) {
|
||||
router.push({ name: targetRoute.name })
|
||||
return
|
||||
}
|
||||
|
||||
router.push({ path: `/layout/${routePath}` })
|
||||
}
|
||||
|
||||
const goToAllAlarmPage = () => {
|
||||
pushDynamicRoute(ALL_ALARM_ROUTE_PATH)
|
||||
}
|
||||
|
||||
const goToEquipmentOverview = () => {
|
||||
pushDynamicRoute(EQUIPMENT_OVERVIEW_ROUTE_PATH)
|
||||
}
|
||||
|
||||
const setRem = () => {
|
||||
const designWidth = 1920
|
||||
const designHeight = 1080
|
||||
@@ -397,7 +444,7 @@
|
||||
console.log('devices', devices.value)
|
||||
nextTick(() => {
|
||||
if (mapInstance.value) {
|
||||
mapInstance.value.setZoomAndCenter(default3DZoom, getValidDeviceCenter())
|
||||
mapInstance.value.setZoomAndCenter(getCurrentMapZoom(), getValidDeviceCenter())
|
||||
}
|
||||
addMarkers()
|
||||
})
|
||||
@@ -416,8 +463,12 @@
|
||||
return [Number(firstValidDevice.gatewayLong), Number(firstValidDevice.gatewayLat)]
|
||||
}
|
||||
|
||||
const getCurrentMapZoom = () => {
|
||||
return mapDisplayMode.value === '3D' ? default3DZoom : default2DZoom
|
||||
}
|
||||
|
||||
const add3DBuildingLayer = () => {
|
||||
if (!mapInstance.value || typeof AMap === 'undefined' || !AMap.Buildings) return
|
||||
if (!mapInstance.value || typeof AMap === 'undefined' || !AMap.Buildings || buildingsLayer) return
|
||||
|
||||
buildingsLayer = new AMap.Buildings({
|
||||
zooms: [3, 20],
|
||||
@@ -428,6 +479,42 @@
|
||||
mapInstance.value.add(buildingsLayer)
|
||||
}
|
||||
|
||||
const remove3DBuildingLayer = () => {
|
||||
if (!mapInstance.value || !buildingsLayer) return
|
||||
|
||||
mapInstance.value.remove(buildingsLayer)
|
||||
buildingsLayer = null
|
||||
}
|
||||
|
||||
const applyMapMode = () => {
|
||||
if (!mapInstance.value) return
|
||||
|
||||
const is3D = mapDisplayMode.value === '3D'
|
||||
const center = getValidDeviceCenter()
|
||||
|
||||
mapInstance.value.setStatus({
|
||||
pitchEnable: is3D,
|
||||
rotateEnable: is3D
|
||||
})
|
||||
mapInstance.value.setFeatures(is3D ? ['bg', 'road', 'building', 'point'] : ['bg', 'road', 'point'])
|
||||
mapInstance.value.setZoomAndCenter(is3D ? default3DZoom : default2DZoom, center)
|
||||
mapInstance.value.setPitch(is3D ? 68 : 0)
|
||||
mapInstance.value.setRotation(is3D ? -28 : 0)
|
||||
|
||||
if (is3D) {
|
||||
add3DBuildingLayer()
|
||||
} else {
|
||||
remove3DBuildingLayer()
|
||||
}
|
||||
}
|
||||
|
||||
const switchMapMode = (mode) => {
|
||||
if (mapDisplayMode.value === mode) return
|
||||
|
||||
mapDisplayMode.value = mode
|
||||
applyMapMode()
|
||||
}
|
||||
|
||||
const initMap = () => {
|
||||
if (typeof AMap === 'undefined') {
|
||||
console.error('高德地图API未加载')
|
||||
@@ -437,16 +524,16 @@
|
||||
console.log('开始初始化地图')
|
||||
|
||||
mapInstance.value = new AMap.Map('chinaMap', {
|
||||
zoom: default3DZoom,
|
||||
zoom: getCurrentMapZoom(),
|
||||
zooms: [3, 20],
|
||||
center: getValidDeviceCenter(),
|
||||
mapStyle: 'amap://styles/blue',
|
||||
viewMode: '3D',
|
||||
pitch: 68,
|
||||
rotation: -28,
|
||||
pitch: mapDisplayMode.value === '3D' ? 68 : 0,
|
||||
rotation: mapDisplayMode.value === '3D' ? -28 : 0,
|
||||
terrain: true,
|
||||
pitchEnable: true,
|
||||
rotateEnable: true,
|
||||
pitchEnable: mapDisplayMode.value === '3D',
|
||||
rotateEnable: mapDisplayMode.value === '3D',
|
||||
dragEnable: true,
|
||||
zoomEnable: true,
|
||||
buildingAnimation: true,
|
||||
@@ -456,13 +543,13 @@
|
||||
skyColor: '#020713'
|
||||
})
|
||||
|
||||
add3DBuildingLayer()
|
||||
applyMapMode()
|
||||
|
||||
mapInstance.value.on('complete', () => {
|
||||
console.log('地图加载完成')
|
||||
if (devices.value && devices.value.length > 0) {
|
||||
const center = getValidDeviceCenter()
|
||||
mapInstance.value.setZoomAndCenter(default3DZoom, center)
|
||||
mapInstance.value.setZoomAndCenter(getCurrentMapZoom(), center)
|
||||
addMarkers()
|
||||
}
|
||||
})
|
||||
@@ -489,7 +576,7 @@
|
||||
// 先只渲染前20个点测试
|
||||
const testData = devices.value.slice(0, 20)
|
||||
|
||||
testData.forEach((device, index) => {
|
||||
testData.forEach((device) => {
|
||||
// console.log(`渲染第 ${index} 个点:`, device)
|
||||
|
||||
const longitude = Number(device.gatewayLong)
|
||||
@@ -601,6 +688,11 @@
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.device-link-card {
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.module-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -934,6 +1026,11 @@
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.alarm-link-card {
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.module-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -1296,6 +1393,75 @@
|
||||
letter-spacing: 0.04rem;
|
||||
}
|
||||
|
||||
.map-mode-switch {
|
||||
position: absolute;
|
||||
top: 0.24rem;
|
||||
right: 0.22rem;
|
||||
z-index: 1001;
|
||||
display: flex;
|
||||
gap: 0.06rem;
|
||||
padding: 0.06rem;
|
||||
border: 1px solid rgba(0, 212, 255, 0.38);
|
||||
border-radius: 0.12rem;
|
||||
background:
|
||||
linear-gradient(135deg, rgba(8, 47, 73, 0.9), rgba(15, 23, 42, 0.76)),
|
||||
repeating-linear-gradient(90deg, transparent 0 0.16rem, rgba(0, 212, 255, 0.05) 0.17rem 0.18rem);
|
||||
box-shadow:
|
||||
inset 0 0 0.18rem rgba(0, 212, 255, 0.12),
|
||||
0 0 0.24rem rgba(0, 212, 255, 0.18),
|
||||
0 0.1rem 0.24rem rgba(0, 0, 0, 0.28);
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
.map-mode-button {
|
||||
min-width: 0.6rem;
|
||||
height: 0.32rem;
|
||||
padding: 0 0.14rem;
|
||||
border: 1px solid rgba(0, 212, 255, 0.42);
|
||||
border-radius: 0.08rem;
|
||||
color: #e9fbff;
|
||||
font-family: DIN Alternate, Bahnschrift, Arial, sans-serif;
|
||||
font-size: 0.16rem;
|
||||
font-weight: 800;
|
||||
line-height: 0.32rem;
|
||||
letter-spacing: 0.03rem;
|
||||
cursor: pointer;
|
||||
background: rgba(2, 8, 23, 0.72);
|
||||
text-shadow:
|
||||
0 0 0.06rem rgba(0, 212, 255, 0.9),
|
||||
0 1px 2px rgba(0, 0, 0, 0.9);
|
||||
transition: all 0.25s ease;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
.map-mode-button:hover,
|
||||
.map-mode-button.active {
|
||||
color: #ffffff;
|
||||
border-color: rgba(245, 158, 11, 0.86);
|
||||
background: linear-gradient(135deg, rgba(245, 158, 11, 0.52), rgba(0, 212, 255, 0.28));
|
||||
box-shadow:
|
||||
inset 0 0 0.12rem rgba(255, 255, 255, 0.12),
|
||||
0 0 0.18rem rgba(0, 212, 255, 0.46);
|
||||
}
|
||||
|
||||
.map-container-full.map-mode-2d::before {
|
||||
top: 0.82rem;
|
||||
bottom: 0.24rem;
|
||||
height: auto;
|
||||
border-radius: 0.16rem;
|
||||
opacity: 0.5;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.map-container-full.map-mode-2d .map-radar-glow {
|
||||
transform: translate(-50%, -50%);
|
||||
animation-name: radarRotate;
|
||||
}
|
||||
|
||||
.map-container-full.map-mode-2d .map-3d-stage {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.map-radar-glow {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { MoreFilled } from '@element-plus/icons-vue'
|
||||
|
||||
const props = defineProps({
|
||||
defineProps({
|
||||
modelValue: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
@@ -241,6 +241,7 @@
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
|
||||
.device-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(330px, 1fr));
|
||||
|
||||
Reference in New Issue
Block a user