<template>
<div class="monitor-container">
<!-- 顶部导航栏 -->
<div class="top-bar">
<!-- 天气模块 -->
<div class="weather-module">
<i class="fas fa-sun weather-icon"></i>
<span>晴 31℃/西北风</span>
</div>
<!-- 中间平台标题 -->
<div class="platform-title">
<div class="trapezoid-bg">
<h1>株洲市"天空地水"动态监测平台</h1>
</div>
</div>
<!-- 时间模块 -->
<div class="time-module">
{{ currentTime }} {{ currentWeek }}
</div>
<!-- 网络切换控件 -->
<div class="network-switcher">
<select v-model="networkType" @change="switchNetworkType">
<option value="internal">内网地图</option>
<option value="external">外网地图</option>
</select>
</div>
<!-- 天地图切换控件 -->
<div class="map-switcher">
<select v-model="selectedMapType" @change="switchMapType">
<!-- 动态选项 -->
<option v-for="option in mapOptions" :value="option.value" :key="option.value">
{{ option.label }}
</option>
</select>
</div>
<!-- 新增投影切换控件 -->
<div class="projection-switcher">
<select v-model="projectionType" @change="switchProjectionType">
<option value="c">经纬度投影</option>
<option value="w">球面墨卡托投影</option>
</select>
</div>
</div>
<!-- Cesium地图容器 -->
<div id="cesiumContainer"></div>
</div>
</template>
<script setup>
import { ref, onMounted, watch } from 'vue';
import * as Cesium from 'cesium';
import "cesium/Build/Cesium/Widgets/widgets.css";
// 天地图服务密钥
const TIANDITU_TOKEN = '72d487f15710ca558987b9baaba13736';
// 当前时间和星期
const currentTime = ref("2025年07月03日 14:37:46");
const currentWeek = ref("星期四");
const weekMap = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
const updateTime = () => {
const now = new Date();
currentTime.value = now.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
}).replace(/\//g, '-').replace(/(\d{4})-(\d{2})-(\d{2})/, '$ 1年$ 2月$ 3日');
currentWeek.value = weekMap[now.getDay()];
};
setInterval(updateTime, 1000);
updateTime();
// 网络类型选择
const networkType = ref('external'); // 默认外网
// 地图类型选择
const selectedMapType = ref('img_c'); // 默认显示影像+注记
// 投影类型选择
const projectionType = ref('c'); // 默认经纬度投影
// 地图选项配置
const mapOptions = ref([
{ value: 'img_c', label: '影像+注记' },
{ value: 'vec_c', label: '矢量+注记' }
]);
// Cesium相关变量
let viewer = null;
let tiandituLayers = { baseLayer: null, annotationLayer: null };
// 网络类型切换
const switchNetworkType = () => {
// 重置投影类型为默认值
projectionType.value = 'c';
// 根据网络类型更新地图选项
if (networkType.value === 'internal') {
mapOptions.value = [
{ value: 'img_c', label: '内网影像地图' },
{ value: 'vec_c', label: '内网矢量地图' }
];
// 设置内网默认地图类型
selectedMapType.value = 'img_c';
} else {
mapOptions.value = [
{ value: 'img', label: '天地图影像' },
{ value: 'img_c', label: '影像+注记' },
{ value: 'vec', label: '矢量地图' },
{ value: 'vec_c', label: '矢量+注记' },
{ value: 'ter', label: '地形图' }
];
// 设置外网默认地图类型
selectedMapType.value = 'img_c';
}
// 重新加载地图
loadMapService(selectedMapType.value);
};
// 地图类型切换
const switchMapType = () => {
if (viewer) {
loadMapService(selectedMapType.value);
}
};
// 投影类型切换
const switchProjectionType = () => {
if (viewer && networkType.value === 'external') {
loadMapService(selectedMapType.value);
}
};
// 加载地图服务
const loadMapService = (type) => {
if (!viewer || !viewer.imageryLayers) return;
// 清除现有图层
if (tiandituLayers.baseLayer) viewer.imageryLayers.remove(tiandituLayers.baseLayer);
if (tiandituLayers.annotationLayer) viewer.imageryLayers.remove(tiandituLayers.annotationLayer);
if (networkType.value === 'internal') {
// 内网地图服务 - 只支持c投影
const baseUrl = "http://59.255.48.160:81";
if (type === 'img_c') {
// 内网影像地图
tiandituLayers.baseLayer = viewer.imageryLayers.addImageryProvider(
new Cesium.WebMapTileServiceImageryProvider({
url: `${baseUrl}/img_c/wmts`,
layer: "img",
style: "default",
tileMatrixSetID: "c",
format: "tiles",
credit: new Cesium.Credit("内网影像地图"),
maximumLevel: 18
})
);
} else if (type === 'vec_c') {
// 内网矢量地图
tiandituLayers.baseLayer = viewer.imageryLayers.addImageryProvider(
new Cesium.WebMapTileServiceImageryProvider({
url: `${baseUrl}/vec_c/wmts`,
layer: "vec",
style: "default",
tileMatrixSetID: "c",
format: "tiles",
credit: new Cesium.Credit("内网矢量地图"),
maximumLevel: 18
})
);
}
} else {
// 外网天地图服务 - 支持c和w投影
// 根据投影类型动态构建URL
const baseUrlTemplate = `https://t{s}.tianditu.gov.cn/{layer}_${projectionType.value}/wmts?tk=${TIANDITU_TOKEN}`;
// 图层配置映射表 - 根据投影类型调整图层名称
const layerConfigs = {
img: {
layer: "img",
credit: "天地图影像"
},
img_c: {
baseLayer: {
layer: "img",
credit: "天地图影像"
},
annotationLayer: {
layer: projectionType.value === 'c' ? "cia" : "cia_w",
credit: "天地图注记"
}
},
vec: {
layer: "vec",
credit: "天地图矢量"
},
vec_c: {
baseLayer: {
layer: "vec",
credit: "天地图矢量"
},
annotationLayer: {
layer: projectionType.value === 'c' ? "cva" : "cva_w",
credit: "天地图注记"
}
},
ter: {
layer: "ter",
credit: "天地图地形"
}
};
const config = layerConfigs[type];
if (!config) return;
// 添加基础图层
tiandituLayers.baseLayer = viewer.imageryLayers.addImageryProvider(
new Cesium.WebMapTileServiceImageryProvider({
url: baseUrlTemplate.replace('{layer}', config.layer || config.baseLayer.layer),
layer: config.layer || config.baseLayer.layer,
style: "default",
tileMatrixSetID: projectionType.value, // 使用选择的投影类型
format: "tiles",
credit: new Cesium.Credit(config.credit || config.baseLayer.credit),
subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'],
maximumLevel: 18
})
);
// 添加注记图层(如果需要)
if (config.annotationLayer) {
tiandituLayers.annotationLayer = viewer.imageryLayers.addImageryProvider(
new Cesium.WebMapTileServiceImageryProvider({
url: baseUrlTemplate.replace('{layer}', config.annotationLayer.layer),
layer: config.annotationLayer.layer,
style: "default",
tileMatrixSetID: projectionType.value, // 使用选择的投影类型
format: "tiles",
credit: new Cesium.Credit(config.annotationLayer.credit),
subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'],
maximumLevel: 18
})
);
}
}
};
// 加载株洲矢量数据
const loadZhuzhouVector = async (viewer) => {
try {
// 加载株洲市整体边界
const cityDataSource = await Cesium.GeoJsonDataSource.load(
"https://geo.datav.aliyun.com/areas_v3/bound/geojson?code=430200",
{
clampToGround: true,
stroke: Cesium.Color.GREEN.withAlpha(0.8),
strokeWidth: 2,
fill: Cesium.Color.WHITE.withAlpha(0.3)
}
);
viewer.dataSources.add(cityDataSource);
// 加载株洲各区县边界
const countyDataSource = await Cesium.GeoJsonDataSource.load(
"https://geo.datav.aliyun.com/areas_v3/bound/geojson?code=430200_full",
{
clampToGround: true,
stroke: Cesium.Color.WHITE,
strokeWidth: 1,
fill: Cesium.Color.TRANSPARENT
}
);
viewer.dataSources.add(countyDataSource);
// 添加区县标签
countyDataSource.entities.values.forEach(entity => {
if (entity.polygon && entity.properties && entity.properties.name) {
const hierarchy = entity.polygon.hierarchy.getValue(Cesium.JulianDate.now());
const center = Cesium.BoundingSphere.fromPoints(hierarchy.positions).center;
entity.label = {
text: entity.properties.name,
font: '18px 黑体',
fillColor: Cesium.Color.WHITE,
outlineColor: Cesium.Color.BLACK,
outlineWidth: 3,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
verticalOrigin: Cesium.VerticalOrigin.CENTER,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
pixelOffset: new Cesium.Cartesian2(0, 0),
disableDepthTestDistance: Number.POSITIVE_INFINITY,
scaleByDistance: new Cesium.NearFarScalar(1e3, 1.0, 1e6, 0.5)
};
entity.position = center;
}
});
// 定位到株洲范围
const rectangle = Cesium.Rectangle.fromDegrees(113.50, 24.94, 113.60, 26.84);
viewer.camera.flyTo({
destination: rectangle,
orientation: {
heading: Cesium.Math.toRadians(0),
pitch: Cesium.Math.toRadians(-70),
roll: 0
},
duration: 2
});
} catch (error) {
console.error("加载株洲数据失败:", error);
const chinaRectangle = Cesium.Rectangle.fromDegrees(73.0, 3.0, 136.0, 59.0);
viewer.camera.flyTo({
destination: chinaRectangle
});
}
};
onMounted(async () => {
try {
// 设置Cesium Ion访问令牌
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0ZTdiZDBhZS0xNzBhLTRjZGUtOTY4NC1kYzA5ZDEyNGEyNjUiLCJpZCI6MzE2OTI5LCJpYXQiOjE3NTEzMzg2Mzh9.9QHGIwaWkUOX0NOSre5369rrf1k6bGhZu7xUQia4JmE';
// 初始化Cesium Viewer
viewer = new Cesium.Viewer('cesiumContainer', {
baseLayerPicker: false,
timeline: false,
animation: false,
geocoder: false,
sceneModePicker: false,
navigationHelpButton: false,
homeButton: false,
selectionIndicator: false,
infoBox: false,
navigationInstructionsInitiallyVisible: false,
scene3DOnly: true,
terrainProvider: new Cesium.EllipsoidTerrainProvider(),
imageryProvider: new Cesium.WebMapTileServiceImageryProvider({
url: `https://t{s}.tianditu.gov.cn/img_w/wmts?tk=${TIANDITU_TOKEN}`,
layer: "img",
style: "default",
tileMatrixSetID: "w",
subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'],
maximumLevel: 18
})
});
// 强制设置中国视角
viewer.camera.setView({
destination: Cesium.Rectangle.fromDegrees(73.0, 3.0, 136.0, 59.0)
});
// 加载株洲数据
loadZhuzhouVector(viewer);
// 加载地图服务
loadMapService(selectedMapType.value);
} catch (error) {
console.error("初始化失败:", error);
}
});
</script>
<style scoped>
/* 基础样式 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Microsoft YaHei", sans-serif;
}
.monitor-container {
width: 100vw;
height: 100vh;
background: radial-gradient(circle at center, #0c2a50 0%, #0a1a35 100%);
overflow: hidden;
position: fixed;
top: 0;
left: 0;
display: flex;
flex-direction: column;
}
/* 顶部导航栏样式 */
.top-bar {
height: 70px;
background: linear-gradient(90deg, #0a1a35 0%, #1a3a6e 50%, #0a1a35 100%);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 15px;
position: relative;
z-index: 100;
border-bottom: 1px solid rgba(0, 150, 255, 0.3);
}
/* 天气模块 */
.weather-module {
display: flex;
align-items: center;
color: white;
font-size: 14px;
min-width: 120px;
justify-content: center;
}
.weather-icon {
color: #ffcc00;
margin-right: 8px;
font-size: 16px;
}
/* 梯形标题样式 */
.platform-title {
position: absolute;
left: 50%;
top: 0;
transform: translateX(-50%);
z-index: 10;
}
.trapezoid-bg {
position: relative;
padding: 0 40px;
height: 70px;
display: flex;
align-items: center;
}
.trapezoid-bg::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 60, 113, 0.6);
clip-path: polygon(0% 0%, 100% 0%, 90% 100%, 10% 100%);
z-index: -1;
}
.platform-title h1 {
font-size: 24px;
font-weight: bold;
background: linear-gradient(to bottom, #a2e7eb, #00f2fe);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
text-shadow: 0 0 8px rgba(0, 242, 254, 0.3);
white-space: nowrap;
}
/* 时间模块 */
.time-module {
color: white;
font-size: 14px;
min-width: 220px;
text-align: center;
}
/* 网络切换控件 */
.network-switcher {
margin-left: 20px;
margin-right: 10px;
}
.network-switcher select {
background: rgba(10, 26, 53, 0.8);
color: #66ffff;
border: 1px solid rgba(0, 150, 255, 0.5);
border-radius: 4px;
padding: 6px 12px;
font-size: 14px;
outline: none;
cursor: pointer;
box-shadow: 0 0 8px rgba(0, 150, 255, 0.3);
transition: all 0.3s ease;
}
.network-switcher select:hover {
background: rgba(26, 58, 110, 0.8);
border-color: #00f2fe;
box-shadow: 0 0 12px rgba(0, 242, 254, 0.5);
}
.network-switcher select:focus {
border-color: #00f2fe;
}
/* 天地图切换控件 */
.map-switcher select {
background: rgba(10, 26, 53, 0.8);
color: #66ffff;
border: 1px solid rgba(0, 150, 255, 0.5);
border-radius: 4px;
padding: 6px 12px;
font-size: 14px;
outline: none;
cursor: pointer;
box-shadow: 0 0 8px rgba(0, 150, 255, 0.3);
transition: all 0.3s ease;
}
.map-switcher select:hover {
background: rgba(26, 58, 110, 0.8);
border-color: #00f2fe;
box-shadow: 0 0 12px rgba(0, 242, 254, 0.5);
}
.map-switcher select:focus {
border-color: #00f2fe;
}
/* 新增投影切换控件 */
.projection-switcher {
margin-left: 10px;
}
.projection-switcher select {
background: rgba(10, 26, 53, 0.8);
color: #66ffff;
border: 1px solid rgba(0, 150, 255, 0.5);
border-radius: 4px;
padding: 6px 12px;
font-size: 14px;
outline: none;
cursor: pointer;
box-shadow: 0 0 8px rgba(0, 150, 255, 0.3);
transition: all 0.3s ease;
}
.projection-switcher select:hover {
background: rgba(26, 58, 110, 0.8);
border-color: #00f2fe;
box-shadow: 0 0 12px rgba(0, 242, 254, 0.5);
}
.projection-switcher select:focus {
border-color: #00f2fe;
}
/* Cesium容器 */
#cesiumContainer {
width: 100%;
height: calc(100vh - 70px);
background-color: #000;
position: relative;
}
/* 响应式调整 */
@media (max-width: 1400px) {
.platform-title h1 {
font-size: 20px;
}
.weather-module, .time-module {
font-size: 13px;
}
.network-switcher select,
.map-switcher select,
.projection-switcher select {
padding: 5px 10px;
font-size: 13px;
}
}
@media (max-width: 1200px) {
.platform-title h1 {
font-size: 18px;
}
.trapezoid-bg {
padding: 0 30px;
}
.time-module {
min-width: 180px;
}
.network-switcher,
.map-switcher,
.projection-switcher {
margin-left: 5px;
margin-right: 5px;
}
}
@media (max-width: 992px) {
.time-module {
display: none;
}
.network-switcher select,
.map-switcher select,
.projection-switcher select {
padding: 4px 8px;
font-size: 12px;
}
}
@media (max-width: 768px) {
.weather-module {
display: none;
}
.platform-title h1 {
font-size: 16px;
}
.trapezoid-bg {
padding: 0 20px;
}
}
</style>
网络切换控件被标题压盖了,你尝试旧址一下,去掉标题或者把网络切换控件移到右边好一点位置