Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
J
JINRUN-PERPOSITION
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
xinzhedeai
JINRUN-PERPOSITION
Commits
232cadf0
Commit
232cadf0
authored
Nov 20, 2025
by
xinzhedeai
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add:电子围栏 init test
parent
1561d94f
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
1149 additions
and
13 deletions
+1149
-13
index.js
src/router/index.js
+13
-13
index-wl.vue
src/views/index-wl.vue
+1136
-0
No files found.
src/router/index.js
View file @
232cadf0
...
...
@@ -101,19 +101,19 @@ export const constantRoutes = [
}
]
},
//
{
// path: '/dp
',
//
component: Layout,
//
redirect: 'noredirect',
//
children: [
//
{
//
path: 'screen',
// component: () => import('@/views/index-dp
'),
//
name: 'Screen',
// meta: { title: '首页-DP
', icon: 'dashboard', affix: true }
//
}
//
]
//
},
{
path
:
'
/wl
'
,
component
:
Layout
,
redirect
:
'
noredirect
'
,
children
:
[
{
path
:
'
screen
'
,
component
:
()
=>
import
(
'
@/views/index-wl
'
),
name
:
'
Screen
'
,
meta
:
{
title
:
'
首页-WL
'
,
icon
:
'
dashboard
'
,
affix
:
true
}
}
]
},
{
path
:
'
/user
'
,
component
:
Layout
,
...
...
src/views/index-wl.vue
0 → 100644
View file @
232cadf0
<
template
>
<div
class=
"app-container home"
>
<!-- Cesium地图容器 -->
<div
id=
"cesiumContainer"
class=
"cesium-container"
></div>
<!-- 人员实时追踪控制面板 -->
<div
class=
"tracking-panel"
>
<select
v-model=
"selectedPerson"
@
change=
"onPersonSelect"
>
<option
value=
""
>
选择人员
</option>
<option
v-for=
"person in personnelList"
:key=
"person.perName"
:value=
"person.perName"
>
{{
person
.
perName
}}
</option>
</select>
</div>
<!-- 电子围栏管理面板 -->
<div
class=
"fence-panel"
>
<div
class=
"panel-header"
>
<h3>
电子围栏管理
</h3>
<div
class=
"fence-type-switch"
>
<label>
<input
type=
"radio"
v-model=
"currentFenceType"
value=
"person"
checked
/>
人员围栏
</label>
<label>
<input
type=
"radio"
v-model=
"currentFenceType"
value=
"vehicle"
/>
车辆围栏
</label>
</div>
</div>
<div
class=
"fence-controls"
>
<button
@
click=
"startCreatingFence"
:disabled=
"isCreatingFence"
>
创建围栏
</button>
<button
@
click=
"editSelectedFence"
:disabled=
"!selectedFence"
>
编辑围栏
</button>
<button
@
click=
"deleteSelectedFence"
:disabled=
"!selectedFence"
>
删除围栏
</button>
<button
@
click=
"stopCreatingFence"
:disabled=
"!isCreatingFence"
>
取消创建
</button>
</div>
<div
class=
"fence-list"
>
<h4>
围栏列表
</h4>
<ul>
<li
v-for=
"fence in getCurrentFences"
:key=
"fence.id"
:class=
"
{ active: selectedFence
&&
selectedFence.id === fence.id }"
@click="selectFence(fence)"
>
{{
fence
.
name
}}
</li>
</ul>
</div>
</div>
<!-- 告警信息面板 -->
<div
class=
"alarm-panel"
v-if=
"alarms.length > 0"
>
<h3>
越界告警
</h3>
<div
class=
"alarm-list"
>
<div
v-for=
"alarm in alarms"
:key=
"alarm.id"
class=
"alarm-item"
>
<span
class=
"alarm-time"
>
{{
alarm
.
time
}}
</span>
<span
class=
"alarm-content"
>
{{
alarm
.
content
}}
</span>
</div>
</div>
</div>
</div>
</
template
>
<
script
>
export
default
{
name
:
"
Index
"
,
data
()
{
return
{
// 版本号
version
:
"
3.8.9
"
,
// Cesium查看器实例
viewer
:
null
,
tileset
:
null
,
personnelList
:
[],
vehicleList
:
[],
// 添加车辆列表
personModelInterval
:
null
,
trackingInterval
:
null
,
bgEntities
:
{},
// 所有的key都对应一个实体对象
// 轨迹追踪相关数据
selectedPerson
:
""
,
// 选中的人员
timePoints
:
[],
// 时间点数组
currentTimeIndex
:
0
,
// 当前时间索引
personTrajectories
:
{},
// 人员轨迹数据 { 人员名称: [{time, lng, lat, height}] }
trailEntities
:
{},
// 轨迹实体
isTracking
:
false
,
// 是否正在实时追踪
currentTimeDisplay
:
""
,
// 当前显示时间
// 添加轨迹相关配置
trajectoryConfig
:
{
pointCount
:
5
,
// 每个人员的轨迹点数量
maxRange
:
0.001
,
// 约100米范围(1度约等于111公里,0.001度约等于111米)
heightOffset
:
50
,
// 轨迹点高度偏移
},
// 电子围栏相关数据
personFences
:
[],
// 人员电子围栏
vehicleFences
:
[],
// 车辆电子围栏
isCreatingFence
:
false
,
// 是否正在创建围栏
currentFencePoints
:
[],
// 当前围栏的点
selectedFence
:
null
,
// 当前选中的围栏
currentFenceType
:
"
person
"
,
// 当前围栏类型
drawingEntity
:
null
,
// 绘制中的实体
fenceEntities
:
{},
// 围栏实体映射
// 告警相关
alarms
:
[],
// 告警列表
};
},
mounted
()
{
// 组件挂载后初始化地图
this
.
initCesium
();
this
.
personCardList
(()
=>
{
console
.
log
(
"
人员数据
"
,
this
.
personnelList
);
});
this
.
vehicleCardList
();
// 初始化车辆数据
// 开始定时检查越界
this
.
startBoundaryCheckInterval
();
},
beforeDestroy
()
{
// 组件销毁前清理地图资源
if
(
this
.
viewer
)
{
this
.
viewer
.
destroy
();
this
.
viewer
=
null
;
}
if
(
this
.
personModelInterval
)
{
clearInterval
(
this
.
personModelInterval
);
}
if
(
this
.
trackingInterval
)
{
clearInterval
(
this
.
trackingInterval
);
}
if
(
this
.
boundaryCheckInterval
)
{
clearInterval
(
this
.
boundaryCheckInterval
);
}
},
computed
:
{
// 获取当前类型的围栏列表
getCurrentFences
()
{
return
this
.
currentFenceType
===
"
person
"
?
this
.
personFences
:
this
.
vehicleFences
;
},
},
methods
:
{
// 新增:清除实体
clearEntities
()
{
if
(
this
.
viewer
&&
this
.
bgEntities
)
{
for
(
let
key
in
this
.
bgEntities
)
{
this
.
viewer
.
entities
.
remove
(
this
.
bgEntities
[
key
]);
delete
this
.
bgEntities
[
key
];
}
}
},
// 为人员设置轨迹数据
initPersonTrajectories
()
{
// 将笛卡尔坐标转换为经纬度坐标作为基准点
const
cartographic
=
Cesium
.
Cartographic
.
fromCartesian
({
x
:
-
2686273.730145489
,
y
:
4293961.185794622
,
z
:
3863430.5618300107
,
});
const
baseLongitude
=
Cesium
.
Math
.
toDegrees
(
cartographic
.
longitude
);
const
baseLatitude
=
Cesium
.
Math
.
toDegrees
(
cartographic
.
latitude
);
const
baseHeight
=
cartographic
.
height
+
1
;
// 为每个人生成轨迹数据
this
.
personnelList
.
forEach
((
person
)
=>
{
const
trajectories
=
[];
// 为每个人生成一个随机的起始位置,在基准点附近
const
personBaseLng
=
baseLongitude
+
(
Math
.
random
()
-
0.5
)
*
this
.
trajectoryConfig
.
maxRange
*
0.5
;
const
personBaseLat
=
baseLatitude
+
(
Math
.
random
()
-
0.5
)
*
this
.
trajectoryConfig
.
maxRange
*
0.5
;
// 生成轨迹点,形成一个合理的移动路径
for
(
let
i
=
0
;
i
<
this
.
trajectoryConfig
.
pointCount
;
i
++
)
{
// 在人员基准位置附近生成轨迹点,确保在100米范围内
const
lngOffset
=
(
Math
.
random
()
-
0.5
)
*
this
.
trajectoryConfig
.
maxRange
;
const
latOffset
=
(
Math
.
random
()
-
0.5
)
*
this
.
trajectoryConfig
.
maxRange
;
trajectories
.
push
({
time
:
new
Date
().
getTime
()
+
i
*
60000
,
// 每分钟一个点
lng
:
personBaseLng
+
lngOffset
,
lat
:
personBaseLat
+
latOffset
,
height
:
baseHeight
,
});
}
this
.
personTrajectories
[
person
.
perName
]
=
trajectories
;
});
},
// 格式化时间显示
formatTime
(
date
=
new
Date
())
{
const
hours
=
date
.
getHours
().
toString
().
padStart
(
2
,
"
0
"
);
const
minutes
=
date
.
getMinutes
().
toString
().
padStart
(
2
,
"
0
"
);
return
`
${
hours
}
:
${
minutes
}
`
;
},
// 人员选择变化处理
onPersonSelect
()
{
this
.
clearTrails
();
if
(
this
.
selectedPerson
)
{
this
.
showFullPath
();
}
},
// 显示完整轨迹
showFullPath
()
{
if
(
!
this
.
selectedPerson
||
!
this
.
personTrajectories
[
this
.
selectedPerson
]
)
{
return
;
}
this
.
clearTrails
();
this
.
updateTrailDisplay
();
},
// 更新轨迹显示
updateTrailDisplay
()
{
const
trajectories
=
this
.
personTrajectories
[
this
.
selectedPerson
];
if
(
!
trajectories
||
trajectories
.
length
<
2
)
return
;
// 创建轨迹点数组
const
positions
=
[];
trajectories
.
forEach
((
point
)
=>
{
positions
.
push
(
Cesium
.
Cartesian3
.
fromDegrees
(
point
.
lng
,
point
.
lat
,
point
.
height
)
);
});
// 创建轨迹线,使用更明显的样式
const
trailEntity
=
this
.
viewer
.
entities
.
add
({
polyline
:
{
positions
:
positions
,
width
:
4
,
material
:
new
Cesium
.
PolylineGlowMaterialProperty
({
glowPower
:
0.6
,
color
:
Cesium
.
Color
.
YELLOW
,
}),
clampToGround
:
false
,
// 确保轨迹线在倾斜摄影上显示
heightReference
:
Cesium
.
HeightReference
.
CLAMP_TO_3D_TILE
,
},
});
this
.
trailEntities
[
this
.
selectedPerson
]
=
trailEntity
;
},
// 清除轨迹
clearTrails
()
{
for
(
let
key
in
this
.
trailEntities
)
{
this
.
viewer
.
entities
.
remove
(
this
.
trailEntities
[
key
]);
}
this
.
trailEntities
=
{};
},
// 设置人员列表
personCardList
(
fn
)
{
// 将笛卡尔坐标转换为经纬度坐标
const
cartographic
=
Cesium
.
Cartographic
.
fromCartesian
({
x
:
-
2686273.730145489
,
y
:
4293961.185794622
,
z
:
3863430.5618300107
,
});
const
baseLongitude
=
Cesium
.
Math
.
toDegrees
(
cartographic
.
longitude
);
const
baseLatitude
=
Cesium
.
Math
.
toDegrees
(
cartographic
.
latitude
);
const
baseHeight
=
cartographic
.
height
+
1
;
console
.
log
(
"
人员经纬度基准点:
"
,
{
longitude
:
baseLongitude
,
latitude
:
baseLatitude
,
height
:
baseHeight
,
});
// 清除现有的人员列表
this
.
personnelList
=
[];
// 生成10个不同的经纬度坐标,范围在100米内
for
(
let
index
=
0
;
index
<
10
;
index
++
)
{
// 生成随机偏移量,确保在100米范围内
const
lngOffset
=
(
Math
.
random
()
-
0.5
)
*
this
.
trajectoryConfig
.
maxRange
;
const
latOffset
=
(
Math
.
random
()
-
0.5
)
*
this
.
trajectoryConfig
.
maxRange
;
this
.
personnelList
.
push
({
lng
:
baseLongitude
+
lngOffset
,
lat
:
baseLatitude
+
latOffset
,
height
:
baseHeight
,
perName
:
"
人员
"
+
(
index
+
1
),
status
:
"
online
"
,
avatar
:
"
/static/images/avatars/zhangsan.png
"
,
});
}
// 重新初始化轨迹数据
this
.
initPersonTrajectories
();
fn
&&
fn
(
this
.
personnelList
);
},
// 设置车辆列表
vehicleCardList
()
{
const
cartographic
=
Cesium
.
Cartographic
.
fromCartesian
({
x
:
-
2686273.730145489
,
y
:
4293961.185794622
,
z
:
3863430.5618300107
,
});
const
baseLongitude
=
Cesium
.
Math
.
toDegrees
(
cartographic
.
longitude
);
const
baseLatitude
=
Cesium
.
Math
.
toDegrees
(
cartographic
.
latitude
);
const
baseHeight
=
cartographic
.
height
+
1
;
this
.
vehicleList
=
[];
// 生成5个车辆
for
(
let
index
=
0
;
index
<
5
;
index
++
)
{
const
lngOffset
=
(
Math
.
random
()
-
0.5
)
*
this
.
trajectoryConfig
.
maxRange
*
1.5
;
// 车辆活动范围更大
const
latOffset
=
(
Math
.
random
()
-
0.5
)
*
this
.
trajectoryConfig
.
maxRange
*
1.5
;
this
.
vehicleList
.
push
({
lng
:
baseLongitude
+
lngOffset
,
lat
:
baseLatitude
+
latOffset
,
height
:
baseHeight
,
vehicleName
:
"
车辆
"
+
(
index
+
1
),
status
:
"
online
"
,
});
}
},
// 初始化车辆轨迹
initVehicleTrajectories
()
{
const
cartographic
=
Cesium
.
Cartographic
.
fromCartesian
({
x
:
-
2686273.730145489
,
y
:
4293961.185794622
,
z
:
3863430.5618300107
,
});
const
baseLongitude
=
Cesium
.
Math
.
toDegrees
(
cartographic
.
longitude
);
const
baseLatitude
=
Cesium
.
Math
.
toDegrees
(
cartographic
.
latitude
);
const
baseHeight
=
cartographic
.
height
+
1
;
this
.
vehicleList
.
forEach
((
vehicle
)
=>
{
const
trajectories
=
[];
const
vehicleBaseLng
=
baseLongitude
+
(
Math
.
random
()
-
0.5
)
*
this
.
trajectoryConfig
.
maxRange
;
const
vehicleBaseLat
=
baseLatitude
+
(
Math
.
random
()
-
0.5
)
*
this
.
trajectoryConfig
.
maxRange
;
for
(
let
i
=
0
;
i
<
this
.
trajectoryConfig
.
pointCount
;
i
++
)
{
const
lngOffset
=
(
Math
.
random
()
-
0.5
)
*
this
.
trajectoryConfig
.
maxRange
*
1.5
;
const
latOffset
=
(
Math
.
random
()
-
0.5
)
*
this
.
trajectoryConfig
.
maxRange
*
1.5
;
trajectories
.
push
({
time
:
new
Date
().
getTime
()
+
i
*
60000
,
lng
:
vehicleBaseLng
+
lngOffset
,
lat
:
vehicleBaseLat
+
latOffset
,
height
:
baseHeight
,
});
}
// 为车辆添加轨迹属性
vehicle
.
trajectories
=
trajectories
;
});
},
/**
* 初始化Cesium地图
*/
async
initCesium
()
{
Cesium
.
Ion
.
defaultAccessToken
=
"
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0ZDAxZGFhYy02MjJlLTRiNzktODNhZi00N2VjZGY0NTk4YmIiLCJpZCI6Mjc0NDAxLCJpYXQiOjE3NjMzNDYwNTR9.ZQW2DZ4KaMGbHuwrtIbyI6EdSSvgMJUHmmD74eZW7PQ
"
;
try
{
// 创建Cesium Viewer实例
this
.
viewer
=
new
Cesium
.
Viewer
(
"
cesiumContainer
"
,
{
// 设置地图提供者,这里使用默认的Bing Maps
imageryProvider
:
new
Cesium
.
BingMapsImageryProvider
({
url
:
"
https://dev.virtualearth.net
"
,
key
:
"
AgcbDCAOb9zMfquaT4Z-MdHfx--9wUNrLRiiS7rIElFx8f-4lLulxZ0QnhqX5Lm6
"
,
mapStyle
:
Cesium
.
BingMapsStyle
.
AERIAL
,
}),
// 配置是否显示各种控件
animation
:
false
,
// 动画控件
baseLayerPicker
:
true
,
// 底图选择器
fullscreenButton
:
false
,
// 全屏按钮
geocoder
:
false
,
// 地址搜索
homeButton
:
false
,
// 主页按钮
infoBox
:
false
,
// 信息框
sceneModePicker
:
false
,
// 场景模式选择器
selectionIndicator
:
false
,
// 选择指示器
timeline
:
false
,
// 时间线
navigationHelpButton
:
false
,
// 导航帮助按钮
navigationInstructionsInitiallyVisible
:
false
,
// 设置初始视图位置
center
:
Cesium
.
Cartesian3
.
fromDegrees
(
104.06
,
30.67
,
10000000
),
});
this
.
viewer
.
scene
.
camera
.
setView
({
// 视角-环翠
duration
:
1
,
destination
:
{
x
:
-
2739843.563038797
,
y
:
4357442.794747324
,
z
:
3880768.3292693933
,
},
orientation
:
{
heading
:
6.037000745578596
,
pitch
:
-
1.2499586064720978
,
roll
:
0.000005306352659495417
,
},
});
// 隐藏Cesium logo
this
.
viewer
.
_cesiumWidget
.
_creditContainer
.
style
.
display
=
"
none
"
;
const
VUE_APP_GIS
=
"
http://192.168.2.11:8080/Apps/assets/media/gaoquyingji
"
;
try
{
const
tileset
=
await
Cesium
.
Cesium3DTileset
.
fromUrl
(
VUE_APP_GIS
+
"
/tiles/01_guanwei/tileset.json
"
);
this
.
viewer
.
scene
.
primitives
.
add
(
tileset
);
console
.
log
(
"
倾斜摄影模型加载成功tileset
"
,
tileset
);
if
(
tileset
)
{
this
.
tileset
=
tileset
;
this
.
locateToTileset
();
}
}
catch
(
error
)
{
console
.
error
(
`加载倾斜摄影模型失败:
${
error
}
`
);
}
console
.
log
(
"
Cesium地图初始化成功
"
);
}
catch
(
error
)
{
console
.
error
(
"
Cesium地图初始化失败:
"
,
error
);
}
},
/**
* 获取倾斜摄影模型的经纬度并将摄像机视角转向模型上方
*/
locateToTileset
()
{
if
(
!
this
.
tileset
||
!
this
.
viewer
)
{
console
.
error
(
"
模型或视图未准备就绪
"
);
return
;
}
try
{
// 获取模型的边界球
const
boundingSphere
=
this
.
tileset
.
boundingSphere
;
if
(
!
boundingSphere
)
{
console
.
error
(
"
无法获取模型边界
"
);
return
;
}
// 获取模型中心点的笛卡尔坐标
const
center
=
boundingSphere
.
center
;
// 将笛卡尔坐标转换为经纬度坐标
const
cartographic
=
Cesium
.
Cartographic
.
fromCartesian
(
center
);
const
longitude
=
Cesium
.
Math
.
toDegrees
(
cartographic
.
longitude
);
const
latitude
=
Cesium
.
Math
.
toDegrees
(
cartographic
.
latitude
);
const
height
=
cartographic
.
height
;
console
.
log
(
"
倾斜摄影模型中心点经纬度:
"
,
{
longitude
:
longitude
,
latitude
:
latitude
,
height
:
height
,
});
// 计算合适的观察距离 - 基于模型半径的倍数
const
distance
=
boundingSphere
.
radius
*
2.5
;
// 可以根据需要调整倍数
// 设置相机位置在模型上方
const
cameraPosition
=
Cesium
.
Cartesian3
.
fromRadians
(
cartographic
.
longitude
,
cartographic
.
latitude
,
height
+
distance
// 相机高度为模型最高点加上观察距离
);
// 计算相机看向模型中心的方向
const
heading
=
Cesium
.
Math
.
toRadians
(
0
);
// 方向角
const
pitch
=
Cesium
.
Math
.
toRadians
(
-
90
);
// 俯仰角 - 负数表示向下看
const
roll
=
Cesium
.
Math
.
toRadians
(
0
);
// 翻滚角
// 使用flyTo方法平滑过渡到目标位置
this
.
viewer
.
camera
.
flyTo
({
destination
:
cameraPosition
,
orientation
:
{
heading
:
heading
,
pitch
:
pitch
,
roll
:
roll
,
},
duration
:
2
,
// 过渡时间2秒
complete
:
()
=>
{
console
.
log
(
"
相机已成功定位到模型上方
"
);
// 初始化车辆轨迹
this
.
initVehicleTrajectories
();
// 创建默认的电子围栏示例
this
.
createDefaultFences
();
// 创建人员和车辆实体
this
.
createPersonEntities
();
this
.
createVehicleEntities
();
},
});
}
catch
(
error
)
{
console
.
error
(
"
定位到模型上方失败:
"
,
error
);
}
},
// 创建默认的电子围栏示例
createDefaultFences
()
{
const
cartographic
=
Cesium
.
Cartographic
.
fromCartesian
({
x
:
-
2686273.730145489
,
y
:
4293961.185794622
,
z
:
3863430.5618300107
,
});
const
baseLongitude
=
Cesium
.
Math
.
toDegrees
(
cartographic
.
longitude
);
const
baseLatitude
=
Cesium
.
Math
.
toDegrees
(
cartographic
.
latitude
);
// 创建一个人员电子围栏示例
const
personFencePoints
=
[
{
lng
:
baseLongitude
-
0.0002
,
lat
:
baseLatitude
-
0.0002
},
{
lng
:
baseLongitude
+
0.0002
,
lat
:
baseLatitude
-
0.0002
},
{
lng
:
baseLongitude
+
0.0002
,
lat
:
baseLatitude
+
0.0002
},
{
lng
:
baseLongitude
-
0.0002
,
lat
:
baseLatitude
+
0.0002
},
];
this
.
personFences
.
push
({
id
:
Date
.
now
(),
name
:
"
人员限制区域1
"
,
points
:
personFencePoints
,
type
:
"
person
"
,
color
:
Cesium
.
Color
.
RED
.
withAlpha
(
0.3
),
borderColor
:
Cesium
.
Color
.
RED
,
});
// 创建一个车辆电子围栏示例
const
vehicleFencePoints
=
[
{
lng
:
baseLongitude
-
0.0004
,
lat
:
baseLatitude
-
0.0004
},
{
lng
:
baseLongitude
+
0.0004
,
lat
:
baseLatitude
-
0.0004
},
{
lng
:
baseLongitude
+
0.0004
,
lat
:
baseLatitude
+
0.0004
},
{
lng
:
baseLongitude
-
0.0004
,
lat
:
baseLatitude
+
0.0004
},
];
this
.
vehicleFences
.
push
({
id
:
Date
.
now
()
+
1
,
name
:
"
车辆限制区域1
"
,
points
:
vehicleFencePoints
,
type
:
"
vehicle
"
,
color
:
Cesium
.
Color
.
BLUE
.
withAlpha
(
0.3
),
borderColor
:
Cesium
.
Color
.
BLUE
,
});
// 渲染所有围栏
this
.
renderAllFences
();
},
// 开始创建电子围栏
startCreatingFence
()
{
this
.
isCreatingFence
=
true
;
this
.
currentFencePoints
=
[];
if
(
this
.
drawingEntity
)
{
this
.
viewer
.
entities
.
remove
(
this
.
drawingEntity
);
this
.
drawingEntity
=
null
;
}
// 添加鼠标点击事件监听
this
.
viewer
.
screenSpaceEventHandler
.
setInputAction
((
click
)
=>
{
const
ray
=
this
.
viewer
.
camera
.
getPickRay
(
click
.
position
);
const
intersection
=
this
.
viewer
.
scene
.
globe
.
pick
(
ray
,
this
.
viewer
.
scene
);
if
(
intersection
)
{
const
cartographic
=
Cesium
.
Cartographic
.
fromCartesian
(
intersection
);
const
longitude
=
Cesium
.
Math
.
toDegrees
(
cartographic
.
longitude
);
const
latitude
=
Cesium
.
Math
.
toDegrees
(
cartographic
.
latitude
);
this
.
currentFencePoints
.
push
({
lng
:
longitude
,
lat
:
latitude
});
this
.
updateDrawingFence
();
}
},
Cesium
.
ScreenSpaceEventType
.
LEFT_CLICK
);
// 添加右键点击完成绘制
this
.
viewer
.
screenSpaceEventHandler
.
setInputAction
((
click
)
=>
{
if
(
this
.
currentFencePoints
.
length
>=
3
)
{
this
.
completeCreatingFence
();
}
else
{
alert
(
"
围栏至少需要3个点
"
);
}
},
Cesium
.
ScreenSpaceEventType
.
RIGHT_CLICK
);
},
// 更新绘制中的围栏
updateDrawingFence
()
{
if
(
this
.
drawingEntity
)
{
this
.
viewer
.
entities
.
remove
(
this
.
drawingEntity
);
}
if
(
this
.
currentFencePoints
.
length
<
2
)
return
;
const
positions
=
this
.
currentFencePoints
.
map
((
point
)
=>
Cesium
.
Cartesian3
.
fromDegrees
(
point
.
lng
,
point
.
lat
,
1
)
);
// 闭合多边形
if
(
this
.
currentFencePoints
.
length
>
2
)
{
positions
.
push
(
positions
[
0
]);
}
this
.
drawingEntity
=
this
.
viewer
.
entities
.
add
({
polyline
:
{
positions
:
positions
,
width
:
2
,
material
:
Cesium
.
Color
.
YELLOW
,
clampToGround
:
true
,
},
});
},
// 完成创建电子围栏
completeCreatingFence
()
{
const
fenceName
=
prompt
(
"
请输入围栏名称:
"
,
"
新建围栏
"
);
if
(
!
fenceName
)
return
;
const
newFence
=
{
id
:
Date
.
now
(),
name
:
fenceName
,
points
:
[...
this
.
currentFencePoints
],
type
:
this
.
currentFenceType
,
color
:
this
.
currentFenceType
===
"
person
"
?
Cesium
.
Color
.
RED
.
withAlpha
(
0.3
)
:
Cesium
.
Color
.
BLUE
.
withAlpha
(
0.3
),
borderColor
:
this
.
currentFenceType
===
"
person
"
?
Cesium
.
Color
.
RED
:
Cesium
.
Color
.
BLUE
,
};
if
(
this
.
currentFenceType
===
"
person
"
)
{
this
.
personFences
.
push
(
newFence
);
}
else
{
this
.
vehicleFences
.
push
(
newFence
);
}
this
.
renderFence
(
newFence
);
this
.
stopCreatingFence
();
},
// 停止创建电子围栏
stopCreatingFence
()
{
this
.
isCreatingFence
=
false
;
// 移除临时绘制的围栏
if
(
this
.
drawingEntity
)
{
this
.
viewer
.
entities
.
remove
(
this
.
drawingEntity
);
this
.
drawingEntity
=
null
;
}
// 移除事件监听
this
.
viewer
.
screenSpaceEventHandler
.
removeInputAction
(
Cesium
.
ScreenSpaceEventType
.
LEFT_CLICK
);
this
.
viewer
.
screenSpaceEventHandler
.
removeInputAction
(
Cesium
.
ScreenSpaceEventType
.
RIGHT_CLICK
);
},
// 选择围栏
selectFence
(
fence
)
{
this
.
selectedFence
=
fence
;
// 高亮显示选中的围栏
this
.
renderAllFences
();
},
// 编辑选中的围栏
editSelectedFence
()
{
// 这里可以实现围栏编辑功能,简化版暂时只允许重命名
const
newName
=
prompt
(
"
请输入新的围栏名称:
"
,
this
.
selectedFence
.
name
);
if
(
newName
)
{
this
.
selectedFence
.
name
=
newName
;
this
.
renderAllFences
();
}
},
// 删除选中的围栏
deleteSelectedFence
()
{
if
(
confirm
(
`确定要删除围栏"
${
this
.
selectedFence
.
name
}
"吗?`
))
{
// 移除围栏实体
if
(
this
.
fenceEntities
[
this
.
selectedFence
.
id
])
{
this
.
viewer
.
entities
.
remove
(
this
.
fenceEntities
[
this
.
selectedFence
.
id
]
);
delete
this
.
fenceEntities
[
this
.
selectedFence
.
id
];
}
// 从数组中移除
if
(
this
.
selectedFence
.
type
===
"
person
"
)
{
this
.
personFences
=
this
.
personFences
.
filter
(
(
f
)
=>
f
.
id
!==
this
.
selectedFence
.
id
);
}
else
{
this
.
vehicleFences
=
this
.
vehicleFences
.
filter
(
(
f
)
=>
f
.
id
!==
this
.
selectedFence
.
id
);
}
this
.
selectedFence
=
null
;
}
},
// 渲染所有围栏
renderAllFences
()
{
// 清除所有围栏实体
for
(
let
id
in
this
.
fenceEntities
)
{
this
.
viewer
.
entities
.
remove
(
this
.
fenceEntities
[
id
]);
}
this
.
fenceEntities
=
{};
// 重新渲染所有围栏
[...
this
.
personFences
,
...
this
.
vehicleFences
].
forEach
((
fence
)
=>
{
this
.
renderFence
(
fence
);
});
},
// 渲染单个围栏
renderFence
(
fence
)
{
const
positions
=
fence
.
points
.
map
(
(
point
)
=>
Cesium
.
Cartesian3
.
fromDegrees
(
point
.
lng
,
point
.
lat
,
2
)
// 稍微抬高一点,避免被地形遮挡
);
// 选择边框颜色,如果是选中的围栏则使用高亮色
const
borderColor
=
this
.
selectedFence
&&
this
.
selectedFence
.
id
===
fence
.
id
?
Cesium
.
Color
.
YELLOW
:
fence
.
borderColor
;
// 创建多边形实体
const
fenceEntity
=
this
.
viewer
.
entities
.
add
({
polygon
:
{
hierarchy
:
new
Cesium
.
PolygonHierarchy
(
positions
),
material
:
fence
.
color
,
outline
:
true
,
outlineWidth
:
2
,
outlineColor
:
borderColor
,
heightReference
:
Cesium
.
HeightReference
.
CLAMP_TO_3D_TILE
,
disableDepthTestDistance
:
Number
.
POSITIVE_INFINITY
,
// 确保始终显示在最前面
},
});
this
.
fenceEntities
[
fence
.
id
]
=
fenceEntity
;
},
// 创建人员实体
createPersonEntities
()
{
this
.
personnelList
.
forEach
((
person
)
=>
{
const
position
=
Cesium
.
Cartesian3
.
fromDegrees
(
person
.
lng
,
person
.
lat
,
person
.
height
);
const
entity
=
this
.
viewer
.
entities
.
add
({
position
:
position
,
billboard
:
{
image
:
"
/static/images/avatars/zhangsan.png
"
,
scale
:
0.5
,
heightReference
:
Cesium
.
HeightReference
.
CLAMP_TO_3D_TILE
,
},
label
:
{
text
:
person
.
perName
,
font
:
"
14px sans-serif
"
,
backgroundColor
:
Cesium
.
Color
.
BLACK
.
withAlpha
(
0.7
),
fillColor
:
Cesium
.
Color
.
WHITE
,
padding
:
new
Cesium
.
Cartesian2
(
5
,
5
),
verticalOrigin
:
Cesium
.
VerticalOrigin
.
BOTTOM
,
pixelOffset
:
new
Cesium
.
Cartesian2
(
0
,
-
10
),
disableDepthTestDistance
:
Number
.
POSITIVE_INFINITY
,
},
});
this
.
bgEntities
[
person
.
perName
]
=
entity
;
});
},
// 创建车辆实体
createVehicleEntities
()
{
this
.
vehicleList
.
forEach
((
vehicle
)
=>
{
const
position
=
Cesium
.
Cartesian3
.
fromDegrees
(
vehicle
.
lng
,
vehicle
.
lat
,
vehicle
.
height
);
const
entity
=
this
.
viewer
.
entities
.
add
({
position
:
position
,
billboard
:
{
// 使用默认图标,实际项目中可以替换为车辆图标
image
:
"
/poi-marker-vehicle.png
"
,
scale
:
0.5
,
heightReference
:
Cesium
.
HeightReference
.
CLAMP_TO_3D_TILE
,
},
label
:
{
text
:
vehicle
.
vehicleName
,
font
:
"
14px sans-serif
"
,
backgroundColor
:
Cesium
.
Color
.
BLACK
.
withAlpha
(
0.7
),
fillColor
:
Cesium
.
Color
.
CYAN
,
padding
:
new
Cesium
.
Cartesian2
(
5
,
5
),
verticalOrigin
:
Cesium
.
VerticalOrigin
.
BOTTOM
,
pixelOffset
:
new
Cesium
.
Cartesian2
(
0
,
-
10
),
disableDepthTestDistance
:
Number
.
POSITIVE_INFINITY
,
},
});
this
.
bgEntities
[
vehicle
.
vehicleName
]
=
entity
;
});
},
// 开始越界检查定时器
startBoundaryCheckInterval
()
{
this
.
boundaryCheckInterval
=
setInterval
(()
=>
{
this
.
checkBoundaryViolations
();
},
3000
);
// 每3秒检查一次
},
// 检查越界
checkBoundaryViolations
()
{
// 检查人员越界
this
.
personnelList
.
forEach
((
person
)
=>
{
this
.
personFences
.
forEach
((
fence
)
=>
{
if
(
this
.
isPointInPolygon
(
person
,
fence
.
points
))
{
this
.
addAlarm
(
`人员
${
person
.
perName
}
进入限制区域:
${
fence
.
name
}
`
);
}
});
});
// 检查车辆越界
this
.
vehicleList
.
forEach
((
vehicle
)
=>
{
this
.
vehicleFences
.
forEach
((
fence
)
=>
{
if
(
this
.
isPointInPolygon
(
vehicle
,
fence
.
points
))
{
this
.
addAlarm
(
`车辆
${
vehicle
.
vehicleName
}
进入限制区域:
${
fence
.
name
}
`
);
}
});
});
},
// 判断点是否在多边形内(射线法)
isPointInPolygon
(
point
,
polygonPoints
)
{
let
inside
=
false
;
for
(
let
i
=
0
,
j
=
polygonPoints
.
length
-
1
;
i
<
polygonPoints
.
length
;
j
=
i
++
)
{
const
xi
=
polygonPoints
[
i
].
lng
,
yi
=
polygonPoints
[
i
].
lat
;
const
xj
=
polygonPoints
[
j
].
lng
,
yj
=
polygonPoints
[
j
].
lat
;
const
intersect
=
yi
>
point
.
lat
!=
yj
>
point
.
lat
&&
point
.
lng
<
((
xj
-
xi
)
*
(
point
.
lat
-
yi
))
/
(
yj
-
yi
)
+
xi
;
if
(
intersect
)
inside
=
!
inside
;
}
return
inside
;
},
// 添加告警
addAlarm
(
content
)
{
// 检查是否已存在相同的告警(避免重复)
const
exists
=
this
.
alarms
.
some
((
alarm
)
=>
alarm
.
content
===
content
);
if
(
exists
)
return
;
const
alarm
=
{
id
:
Date
.
now
(),
content
:
content
,
time
:
this
.
formatTime
(),
};
this
.
alarms
.
unshift
(
alarm
);
// 限制告警数量
if
(
this
.
alarms
.
length
>
20
)
{
this
.
alarms
.
pop
();
}
// 可以在这里添加告警声音或其他提示
},
},
};
</
script
>
<
style
scoped
lang=
"scss"
>
.home
{
width
:
100%
;
height
:
100vh
;
position
:
relative
;
overflow
:
hidden
;
font-family
:
"open sans"
,
"Helvetica Neue"
,
Helvetica
,
Arial
,
sans-serif
;
font-size
:
13px
;
color
:
#676a6c
;
overflow-x
:
hidden
;
.update-log
{
ol
{
display
:
block
;
list-style-type
:
decimal
;
margin-block-start
:
1em
;
margin-block-end
:
1em
;
margin-inline-start
:
0
;
margin-inline-end
:
0
;
padding-inline-start
:
40px
;
}
}
// Cesium容器样式
.cesium-container
{
width
:
100vw
;
height
:
100vh
;
position
:
absolute
;
top
:
0
;
left
:
0
;
z-index
:
1
;
}
// 追踪控制面板样式
.tracking-panel
{
position
:
absolute
;
left
:
50%
;
top
:
20px
;
-webkit-transform
:
translateX
(
-50%
);
transform
:
translateX
(
-50%
);
width
:
150px
;
background
:
rgba
(
0
,
0
,
0
,
0
.8
);
border-radius
:
8px
;
padding
:
15px
;
color
:
white
;
z-index
:
100
;
select
{
padding
:
5px
10px
;
border-radius
:
4px
;
border
:
none
;
background
:
#333
;
color
:
white
;
width
:
100%
;
}
}
// 电子围栏管理面板样式
.fence-panel
{
position
:
absolute
;
left
:
20px
;
top
:
20px
;
width
:
250px
;
background
:
rgba
(
0
,
0
,
0
,
0
.8
);
border-radius
:
8px
;
padding
:
15px
;
color
:
white
;
z-index
:
100
;
.panel-header
{
margin-bottom
:
15px
;
h3
{
margin
:
0
0
10px
0
;
font-size
:
18px
;
text-align
:
center
;
}
.fence-type-switch
{
display
:
flex
;
justify-content
:
space-around
;
label
{
cursor
:
pointer
;
display
:
flex
;
align-items
:
center
;
input
{
margin-right
:
5px
;
}
}
}
}
.fence-controls
{
display
:
flex
;
flex-wrap
:
wrap
;
gap
:
5px
;
margin-bottom
:
15px
;
button
{
flex
:
1
;
min-width
:
calc
(
50%
-
5px
);
padding
:
8px
5px
;
border
:
none
;
border-radius
:
4px
;
background
:
#173349
;
color
:
white
;
cursor
:
pointer
;
&
:hover:not
(
:disabled
)
{
background
:
#1e4763
;
}
&
:disabled
{
background
:
#555
;
cursor
:
not
-
allowed
;
}
}
}
.fence-list
{
max-height
:
200px
;
overflow-y
:
auto
;
h4
{
margin
:
0
0
10px
0
;
font-size
:
14px
;
}
ul
{
list-style
:
none
;
padding
:
0
;
margin
:
0
;
li
{
padding
:
8px
;
margin-bottom
:
5px
;
background
:
#333
;
border-radius
:
4px
;
cursor
:
pointer
;
transition
:
background
0
.3s
;
&
:hover
{
background
:
#444
;
}
&
.active
{
background
:
#1e4763
;
border
:
1px
solid
#fff
;
}
}
}
}
}
// 告警面板样式
.alarm-panel
{
position
:
absolute
;
right
:
20px
;
bottom
:
20px
;
width
:
300px
;
max-height
:
400px
;
background
:
rgba
(
0
,
0
,
0
,
0
.9
);
border-radius
:
8px
;
padding
:
15px
;
color
:
white
;
z-index
:
100
;
h3
{
margin
:
0
0
15px
0
;
font-size
:
18px
;
color
:
#ff4444
;
text-align
:
center
;
}
.alarm-list
{
max-height
:
320px
;
overflow-y
:
auto
;
}
.alarm-item
{
padding
:
10px
;
margin-bottom
:
10px
;
background
:
rgba
(
255
,
68
,
68
,
0
.2
);
border-left
:
3px
solid
#ff4444
;
border-radius
:
4px
;
.alarm-time
{
display
:
block
;
font-size
:
12px
;
color
:
#aaa
;
margin-bottom
:
5px
;
}
.alarm-content
{
font-size
:
14px
;
}
}
}
}
</
style
>
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment