feat(situational-awareness): 在地图上添加模拟应急资源和范围圆
- 在地图上10公里半径范围内添加10个模拟应急人员和设备点 - 实现动态范围圆可视化,可随搜索半径变化而更新 - 重构距离过滤器下拉菜单为自定义实现,并改进样式 - 更新组件样式,以提高ForceDispatch、ForcePreset、PageHeader和DataField的视觉一致性 - 替换PageHeader中的背景图片,并为UI元素添加新的素材图片
This commit is contained in:
parent
74ce102b67
commit
66ed12b4cb
Binary file not shown.
|
After Width: | Height: | Size: 132 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.0 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 1.6 KiB |
@ -150,15 +150,16 @@ const handleStartDispatch = () => {
|
|||||||
.force-dispatch__top {
|
.force-dispatch__top {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
gap: vw(12);
|
gap: vw(20);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 响应等级卡片 */
|
/* 响应等级卡片 */
|
||||||
.force-dispatch__level-card {
|
.force-dispatch__level-card {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
gap: vw(12);
|
gap: vw(12);
|
||||||
padding: vh(10) vw(16);
|
padding: vh(5) vw(16);
|
||||||
background: rgba(20, 53, 118, 0.6);
|
background: rgba(20, 53, 118, 0.6);
|
||||||
border: 1px solid rgba(28, 161, 255, 0.3);
|
border: 1px solid rgba(28, 161, 255, 0.3);
|
||||||
border-radius: vw(4);
|
border-radius: vw(4);
|
||||||
@ -166,13 +167,13 @@ const handleStartDispatch = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.force-dispatch__level-label {
|
.force-dispatch__level-label {
|
||||||
font-size: fs(13);
|
font-size: fs(18);
|
||||||
font-family: SourceHanSansCN-Regular, sans-serif;
|
font-family: SourceHanSansCN-Regular, sans-serif;
|
||||||
color: rgba(255, 255, 255, 0.8);
|
color: rgba(255, 255, 255, 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
.force-dispatch__level-value {
|
.force-dispatch__level-value {
|
||||||
font-size: fs(14);
|
font-size: fs(18);
|
||||||
font-family: SourceHanSansCN-Bold, sans-serif;
|
font-family: SourceHanSansCN-Bold, sans-serif;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: rgba(255, 255, 255, 0.95);
|
color: rgba(255, 255, 255, 0.95);
|
||||||
@ -206,7 +207,7 @@ const handleStartDispatch = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.force-dispatch__plan-text {
|
.force-dispatch__plan-text {
|
||||||
font-size: fs(13);
|
font-size: fs(18);
|
||||||
font-family: SourceHanSansCN-Medium, sans-serif;
|
font-family: SourceHanSansCN-Medium, sans-serif;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: rgba(255, 255, 255, 0.95);
|
color: rgba(255, 255, 255, 0.95);
|
||||||
|
|||||||
@ -1,22 +1,36 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="force-preset">
|
<div class="force-preset">
|
||||||
<el-dropdown
|
<!-- 自定义下拉框 -->
|
||||||
class="force-preset__filter"
|
<div class="custom-dropdown" v-click-outside="closeDropdown">
|
||||||
trigger="click"
|
<!-- 触发器 -->
|
||||||
@command="handleDistanceChange"
|
<div class="dropdown-trigger" @click="toggleDropdown">
|
||||||
>
|
<span class="trigger-text">距离灾害点{{ forcePreset.searchRadius }}km范围内</span>
|
||||||
<div class="filter-content">
|
<div class="trigger-icon" :class="{ 'is-open': isDropdownOpen }">
|
||||||
<span class="filter-text">距离灾害点{{ forcePreset.searchRadius }}km范围内</span>
|
<img src="../../assets/images/SketchPng8063f445fba047c290a9620343b62ea51d767b8cdcd86769502b5b160998aacc.png" alt="dropdown" />
|
||||||
<img src="../../assets/images/SketchPng8063f445fba047c290a9620343b62ea51d767b8cdcd86769502b5b160998aacc.png" alt="dropdown" class="filter-icon" />
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 下拉面板 -->
|
||||||
|
<transition name="dropdown-slide">
|
||||||
|
<div v-if="isDropdownOpen" class="dropdown-panel">
|
||||||
|
<div
|
||||||
|
v-for="option in distanceOptions"
|
||||||
|
:key="option.value"
|
||||||
|
class="dropdown-item"
|
||||||
|
:class="{ 'is-active': forcePreset.searchRadius === option.value }"
|
||||||
|
@click="selectOption(option.value)"
|
||||||
|
>
|
||||||
|
<span class="item-text">{{ option.label }}</span>
|
||||||
|
<div v-if="forcePreset.searchRadius === option.value" class="item-icon">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/>
|
||||||
|
<path d="M8 12L11 15L16 9" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
<template #dropdown>
|
|
||||||
<el-dropdown-menu>
|
|
||||||
<el-dropdown-item :command="10" :class="{ 'is-active': forcePreset.searchRadius === 10 }">10km</el-dropdown-item>
|
|
||||||
<el-dropdown-item :command="30" :class="{ 'is-active': forcePreset.searchRadius === 30 }">30km</el-dropdown-item>
|
|
||||||
<el-dropdown-item :command="50" :class="{ 'is-active': forcePreset.searchRadius === 50 }">50km</el-dropdown-item>
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</template>
|
|
||||||
</el-dropdown>
|
|
||||||
|
|
||||||
<div class="force-preset__summary">
|
<div class="force-preset__summary">
|
||||||
<!-- <img src="../../assets/images/SketchPnga96e6ce64e80f6d935217d64400481f3e0361d9e60a7425f6f09c8287716904d.png" alt="background" class="summary-bg" /> -->
|
<!-- <img src="../../assets/images/SketchPnga96e6ce64e80f6d935217d64400481f3e0361d9e60a7425f6f09c8287716904d.png" alt="background" class="summary-bg" /> -->
|
||||||
@ -68,18 +82,58 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { inject } from 'vue'
|
import { ref, inject } from 'vue'
|
||||||
|
|
||||||
const { forcePreset } = inject('disasterData')
|
const { forcePreset } = inject('disasterData')
|
||||||
const onDistanceChange = inject('onDistanceChange')
|
const onDistanceChange = inject('onDistanceChange')
|
||||||
|
|
||||||
|
// 下拉框状态
|
||||||
|
const isDropdownOpen = ref(false)
|
||||||
|
|
||||||
|
// 距离选项
|
||||||
|
const distanceOptions = [
|
||||||
|
{ value: 10, label: '距离灾害点10km范围内' },
|
||||||
|
{ value: 30, label: '距离灾害点30km范围内' },
|
||||||
|
{ value: 50, label: '距离灾害点50km范围内' }
|
||||||
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理距离范围选择变更
|
* 切换下拉框显示/隐藏
|
||||||
* @param {number} distance - 选中的距离范围(km)
|
|
||||||
*/
|
*/
|
||||||
const handleDistanceChange = (distance) => {
|
const toggleDropdown = () => {
|
||||||
|
isDropdownOpen.value = !isDropdownOpen.value
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭下拉框
|
||||||
|
*/
|
||||||
|
const closeDropdown = () => {
|
||||||
|
isDropdownOpen.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择选项
|
||||||
|
* @param {number} value - 选中的距离值
|
||||||
|
*/
|
||||||
|
const selectOption = (value) => {
|
||||||
if (onDistanceChange) {
|
if (onDistanceChange) {
|
||||||
onDistanceChange(distance)
|
onDistanceChange(value)
|
||||||
|
}
|
||||||
|
closeDropdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 点击外部关闭下拉框的指令
|
||||||
|
const vClickOutside = {
|
||||||
|
mounted(el, binding) {
|
||||||
|
el.clickOutsideEvent = (event) => {
|
||||||
|
if (!(el === event.target || el.contains(event.target))) {
|
||||||
|
binding.value()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.addEventListener('click', el.clickOutsideEvent)
|
||||||
|
},
|
||||||
|
unmounted(el) {
|
||||||
|
document.removeEventListener('click', el.clickOutsideEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -92,34 +146,117 @@ const handleDistanceChange = (distance) => {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
|
|
||||||
&__filter {
|
// 自定义下拉框
|
||||||
display: flex;
|
.custom-dropdown {
|
||||||
align-items: center;
|
position: relative;
|
||||||
gap: vw(8);
|
margin-bottom: vh(8);
|
||||||
padding: vh(10) vw(16);
|
|
||||||
background: rgba(20, 53, 118, 0.5);
|
|
||||||
border-radius: vw(4);
|
|
||||||
margin-bottom: vh(16);
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
.filter-content {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: vw(8);
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-text {
|
// 触发器
|
||||||
|
.dropdown-trigger {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: vh(8) vw(16);
|
||||||
|
background: rgba(28, 70, 130, 0.9);
|
||||||
|
border: 1px solid rgba(28, 161, 255, 0.3);
|
||||||
|
border-radius: vw(8);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(28, 70, 130, 1);
|
||||||
|
border-color: rgba(28, 161, 255, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-text {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
color: var(--text-white);
|
color: var(--text-white);
|
||||||
font-size: fs(14);
|
font-size: fs(15);
|
||||||
font-family: SourceHanSansCN-Medium, sans-serif;
|
font-family: SourceHanSansCN-Medium, sans-serif;
|
||||||
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-icon {
|
.trigger-icon {
|
||||||
width: vw(12);
|
width: 16px;
|
||||||
height: vh(12);
|
height: 16px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.is-open {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下拉面板
|
||||||
|
.dropdown-panel {
|
||||||
|
position: absolute;
|
||||||
|
top: calc(100% + vh(4));
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: rgba(15, 35, 75, 0.98);
|
||||||
|
border: 1px solid rgba(28, 161, 255, 0.3);
|
||||||
|
border-radius: vw(8);
|
||||||
|
overflow: hidden;
|
||||||
|
z-index: 100;
|
||||||
|
box-shadow: 0 vh(4) vh(16) rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下拉项
|
||||||
|
.dropdown-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: vh(12) vw(16);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(28, 161, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-active {
|
||||||
|
background: rgba(28, 161, 255, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-text {
|
||||||
|
flex: 1;
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
font-size: fs(15);
|
||||||
|
font-family: SourceHanSansCN-Medium, sans-serif;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-icon {
|
||||||
|
width: vw(20);
|
||||||
|
height: vh(20);
|
||||||
|
flex-shrink: 0;
|
||||||
|
color: var(--primary-color);
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下拉动画
|
||||||
|
.dropdown-slide-enter-active,
|
||||||
|
.dropdown-slide-leave-active {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-slide-enter-from,
|
||||||
|
.dropdown-slide-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(vh(-10));
|
||||||
}
|
}
|
||||||
|
|
||||||
&__summary {
|
&__summary {
|
||||||
@ -205,7 +342,7 @@ const handleDistanceChange = (distance) => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: vh(8);
|
gap: vh(8);
|
||||||
max-height: 100px;
|
max-height: vw(120);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
||||||
// 滚动条
|
// 滚动条
|
||||||
@ -259,29 +396,4 @@ const handleDistanceChange = (distance) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dropdown菜单样式覆盖
|
|
||||||
:deep(.el-dropdown-menu) {
|
|
||||||
background: rgba(20, 53, 118, 0.95);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
||||||
padding: vh(4) 0;
|
|
||||||
|
|
||||||
.el-dropdown-menu__item {
|
|
||||||
color: var(--text-white);
|
|
||||||
font-size: fs(14);
|
|
||||||
font-family: SourceHanSansCN-Medium, sans-serif;
|
|
||||||
padding: vh(8) vw(16);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: rgba(255, 255, 255, 0.1);
|
|
||||||
color: var(--text-white);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.is-active {
|
|
||||||
background: rgba(255, 255, 255, 0.15);
|
|
||||||
color: var(--el-color-primary);
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -44,7 +44,7 @@ const handleBack = () => {
|
|||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: vh(111);
|
height: vh(111);
|
||||||
background: url('../assets/images/b149e2d47f8744b5a916eb88fb4115cc_mergeImage.png') no-repeat;
|
background: url('../assets/images/一级标题栏bg.png') no-repeat;
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@ -47,13 +47,13 @@ const valueClass = computed(() => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: vw(8);
|
gap: vw(8);
|
||||||
padding: vh(8) vw(10);
|
padding: vh(4) vw(10);
|
||||||
background: url('../../assets/images/DataField/快速感知_bg.png') no-repeat center center;
|
background: url('../../assets/images/DataField/快速感知_bg.png') no-repeat center center;
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
|
|
||||||
&__icon {
|
&__icon {
|
||||||
width: vw(24);
|
width: vw(24);
|
||||||
height: vh(30);
|
height: vh(24);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -141,7 +141,7 @@ import { request } from "@shared/utils/request";
|
|||||||
|
|
||||||
// 标记点图标
|
// 标记点图标
|
||||||
import emergencyCenterIcon from "./assets/images/应急中心.png";
|
import emergencyCenterIcon from "./assets/images/应急中心.png";
|
||||||
import dangerIcon from "./assets/images/danger.png";
|
import eventIcon from "./assets/images/事件icon.png";
|
||||||
import soldierIcon from "./assets/images/SketchPngfbec927027ff9e49207749ebaafd229429315341fda199251b6dfb1723ff17fb.png";
|
import soldierIcon from "./assets/images/SketchPngfbec927027ff9e49207749ebaafd229429315341fda199251b6dfb1723ff17fb.png";
|
||||||
import deviceIcon from "./assets/images/SketchPng860d54f2a31f5f441fc6a88081224f1e98534bf6d5ca1246e420983bdf690380.png";
|
import deviceIcon from "./assets/images/SketchPng860d54f2a31f5f441fc6a88081224f1e98534bf6d5ca1246e420983bdf690380.png";
|
||||||
import emergencyBaseIcon from "./assets/images/应急基地.png";
|
import emergencyBaseIcon from "./assets/images/应急基地.png";
|
||||||
@ -156,6 +156,11 @@ const handleDistanceChange = async (newDistance) => {
|
|||||||
// 更新搜索半径
|
// 更新搜索半径
|
||||||
disasterData.updateSearchRadius(newDistance);
|
disasterData.updateSearchRadius(newDistance);
|
||||||
|
|
||||||
|
// 更新范围圈
|
||||||
|
if (mapStore.viewer) {
|
||||||
|
createOrUpdateRangeCircle(mapStore.viewer, newDistance);
|
||||||
|
}
|
||||||
|
|
||||||
// 重新加载应急资源数据并更新地图标记
|
// 重新加载应急资源数据并更新地图标记
|
||||||
await loadEmergencyResources(108.011506, 30.175827);
|
await loadEmergencyResources(108.011506, 30.175827);
|
||||||
};
|
};
|
||||||
@ -188,6 +193,9 @@ const currentTooltipEntity = ref(null);
|
|||||||
// 加载动画状态
|
// 加载动画状态
|
||||||
const showLoading = ref(false);
|
const showLoading = ref(false);
|
||||||
|
|
||||||
|
// 范围圈实体
|
||||||
|
const rangeCircleEntity = ref(null);
|
||||||
|
|
||||||
// 3D Tiles加载功能
|
// 3D Tiles加载功能
|
||||||
const { load3DTileset, waitForTilesetReady } = use3DTiles();
|
const { load3DTileset, waitForTilesetReady } = use3DTiles();
|
||||||
|
|
||||||
@ -405,7 +413,7 @@ onMounted(() => {
|
|||||||
0
|
0
|
||||||
),
|
),
|
||||||
billboard: {
|
billboard: {
|
||||||
image: dangerIcon,
|
image: eventIcon,
|
||||||
width: 36,
|
width: 36,
|
||||||
height: 36,
|
height: 36,
|
||||||
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
||||||
@ -415,6 +423,53 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
viewer.entities.add(defaultPoint);
|
viewer.entities.add(defaultPoint);
|
||||||
|
|
||||||
|
// 在默认点附近添加10个模拟点位(应急人员和应急装备),分散在10km范围内
|
||||||
|
// 1度纬度约等于111km,1度经度在30度纬度约等于96km
|
||||||
|
// 10km约等于0.09度纬度,0.104度经度
|
||||||
|
const simulatedPoints = [
|
||||||
|
// 应急人员 - 分散在不同方向
|
||||||
|
{ type: 'soldier', name: '张三', department: '应急救援队', lon: 108.051, lat: 30.205, distance: 4.2, icon: soldierIcon },
|
||||||
|
{ type: 'soldier', name: '李四', department: '消防队', lon: 107.975, lat: 30.195, distance: 5.8, icon: soldierIcon },
|
||||||
|
{ type: 'soldier', name: '王五', department: '医疗队', lon: 108.025, lat: 30.155, distance: 3.5, icon: soldierIcon },
|
||||||
|
{ type: 'soldier', name: '赵六', department: '应急救援队', lon: 108.085, lat: 30.168, distance: 7.2, icon: soldierIcon },
|
||||||
|
{ type: 'soldier', name: '刘七', department: '消防队', lon: 107.945, lat: 30.182, distance: 8.5, icon: soldierIcon },
|
||||||
|
// 应急装备 - 分散在不同方向
|
||||||
|
{ type: 'device', name: '救援车辆A', deviceType: '消防车', lon: 108.065, lat: 30.185, distance: 6.3, icon: deviceIcon },
|
||||||
|
{ type: 'device', name: '救援车辆B', deviceType: '救护车', lon: 107.960, lat: 30.165, distance: 6.8, icon: deviceIcon },
|
||||||
|
{ type: 'device', name: '无人机A', deviceType: 'DJI', lon: 108.035, lat: 30.225, distance: 5.5, icon: deviceIcon },
|
||||||
|
{ type: 'device', name: '无人机B', deviceType: 'DJI', lon: 108.095, lat: 30.195, distance: 9.2, icon: deviceIcon },
|
||||||
|
{ type: 'device', name: '通讯设备', deviceType: '卫星电话', lon: 107.930, lat: 30.175, distance: 9.8, icon: deviceIcon }
|
||||||
|
];
|
||||||
|
|
||||||
|
simulatedPoints.forEach(point => {
|
||||||
|
const entity = viewer.entities.add({
|
||||||
|
position: Cesium.Cartesian3.fromDegrees(point.lon, point.lat, 0),
|
||||||
|
billboard: {
|
||||||
|
image: point.icon,
|
||||||
|
width: 36,
|
||||||
|
height: 40,
|
||||||
|
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
||||||
|
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
||||||
|
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
||||||
|
},
|
||||||
|
properties: point.type === 'soldier'
|
||||||
|
? {
|
||||||
|
type: 'soldier',
|
||||||
|
name: point.name,
|
||||||
|
department: point.department,
|
||||||
|
location: `目前为止距离现场${point.distance}公里`
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
type: 'device',
|
||||||
|
name: point.name,
|
||||||
|
deviceType: point.deviceType,
|
||||||
|
location: `目前为止距离现场${point.distance}公里`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`[index.vue] 已添加 ${simulatedPoints.length} 个模拟点位`);
|
||||||
|
|
||||||
// camera.setView({
|
// camera.setView({
|
||||||
// ...DEFAULT_CAMERA_VIEW,
|
// ...DEFAULT_CAMERA_VIEW,
|
||||||
// });
|
// });
|
||||||
@ -514,6 +569,9 @@ onMounted(() => {
|
|||||||
// camera.setView(DEFAULT_CAMERA_VIEW)
|
// camera.setView(DEFAULT_CAMERA_VIEW)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 创建初始范围圈(使用当前搜索半径)
|
||||||
|
createOrUpdateRangeCircle(viewer, disasterData.forcePreset.value.searchRadius);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -678,6 +736,42 @@ const handleStartDispatch = (payload) => {
|
|||||||
}, 3000);
|
}, 3000);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建或更新范围圈
|
||||||
|
* @param {Cesium.Viewer} viewer - Cesium viewer 实例
|
||||||
|
* @param {number} radiusKm - 半径(公里)
|
||||||
|
*/
|
||||||
|
const createOrUpdateRangeCircle = (viewer, radiusKm) => {
|
||||||
|
if (!viewer) return;
|
||||||
|
|
||||||
|
const centerLon = 108.011506;
|
||||||
|
const centerLat = 30.175827;
|
||||||
|
const radiusMeters = radiusKm * 1000;
|
||||||
|
|
||||||
|
// 如果已存在范围圈,先移除
|
||||||
|
if (rangeCircleEntity.value) {
|
||||||
|
viewer.entities.remove(rangeCircleEntity.value);
|
||||||
|
rangeCircleEntity.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建新的范围圈
|
||||||
|
rangeCircleEntity.value = viewer.entities.add({
|
||||||
|
position: Cesium.Cartesian3.fromDegrees(centerLon, centerLat, 0),
|
||||||
|
ellipse: {
|
||||||
|
semiMinorAxis: radiusMeters,
|
||||||
|
semiMajorAxis: radiusMeters,
|
||||||
|
height: 0,
|
||||||
|
material: Cesium.Color.fromCssColorString('#1CA1FF').withAlpha(0.2),
|
||||||
|
outline: true,
|
||||||
|
outlineColor: Cesium.Color.fromCssColorString('#1CA1FF').withAlpha(0.8),
|
||||||
|
outlineWidth: 2,
|
||||||
|
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`[index.vue] 已创建/更新范围圈: ${radiusKm}km`);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在指定屏幕坐标显示地图 Tooltip
|
* 在指定屏幕坐标显示地图 Tooltip
|
||||||
*
|
*
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user