forked from integrated_whb/integrated_whb_vue
人员路径和绘制电子围栏
parent
626c1a4bb9
commit
97b43e070f
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,79 @@
|
|||
<template>
|
||||
<div id="bi_container">
|
||||
<div id="map" class="map_bg"></div>
|
||||
<el-button type="primary" @click="confrim">完成绘制</el-button>
|
||||
<el-button type="primary" @click="clear">清除绘制</el-button>
|
||||
<el-button type="primary" @click="reduction">还原建筑</el-button>
|
||||
<span>当前选中楼层id:{{ model_id }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useVModels } from "@vueuse/core";
|
||||
import { onBeforeUnmount, onMounted, ref } from "vue";
|
||||
import {
|
||||
clearEnclosure,
|
||||
handleEnclosure,
|
||||
handleMouseClick,
|
||||
initMap,
|
||||
reduction,
|
||||
showEnclosure,
|
||||
} from "./map";
|
||||
import { useUserStore } from "@/pinia/user.js";
|
||||
import { getEnterpriseInfo } from "@/request/enterprise_management.js";
|
||||
|
||||
const props = defineProps({
|
||||
positions: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => [],
|
||||
},
|
||||
modUuid: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
const userStore = useUserStore();
|
||||
const CORPINFO_ID = userStore.getUserInfo.CORPINFO_ID;
|
||||
const data = [];
|
||||
const model_id = ref(0);
|
||||
const emits = defineEmits(["update:positions", "update:modUuid"]);
|
||||
const { positions, modUuid } = useVModels(props, emits);
|
||||
|
||||
const confrim = () => {
|
||||
showEnclosure(data);
|
||||
positions.value = [...data];
|
||||
modUuid.value = model_id.value;
|
||||
};
|
||||
const clear = () => {
|
||||
clearEnclosure(data);
|
||||
data.length = 0;
|
||||
positions.value = [];
|
||||
};
|
||||
onMounted(async () => {
|
||||
const corp = await getEnterpriseInfo({ CORPINFO_ID });
|
||||
initMap(corp.pd);
|
||||
handleMouseClick(model_id);
|
||||
handleEnclosure(data);
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
window.$scene = null;
|
||||
window.$icy = null;
|
||||
window.$carmer = null;
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
#bi_container {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
color: #ffffff;
|
||||
position: relative;
|
||||
font-size: 14px;
|
||||
|
||||
.map_bg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,167 @@
|
|||
import axios from "axios";
|
||||
import { useUserStore } from "@/pinia/user";
|
||||
import pinia from "@/pinia";
|
||||
|
||||
const userStore = useUserStore(pinia);
|
||||
const pls_ip = userStore.getUserInfo.POST_URL;
|
||||
const url = pls_ip.replace("8084", "9000") + "/buildr/public/models/glb/";
|
||||
export class Loadglb {
|
||||
static modelMap = {};
|
||||
constructor(icy) {
|
||||
this.icy = icy;
|
||||
this.model_def_group = null;
|
||||
this.scene = null;
|
||||
this.idList = [];
|
||||
this.entityList = [];
|
||||
this.number = 0;
|
||||
this.building_group = null;
|
||||
this.groundHeight = 0.2; // 设置地面的高度
|
||||
}
|
||||
|
||||
async fetchData() {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
pls_ip.replace("8084", "9000") +
|
||||
"/buildr/public/models/scene_000001.json"
|
||||
);
|
||||
// 将获取的数据保存到实例的属性中
|
||||
this.scene = response.data.scene;
|
||||
this.model_def_group = response.data.scene.model_def_group;
|
||||
|
||||
const map = new Map();
|
||||
this.model_def_group.forEach((i) => {
|
||||
map.set(i.guid.split("-")[3], { name: i.name, id: i.guid });
|
||||
});
|
||||
this.scene.building_group.forEach((i) => {
|
||||
i.layer_group.forEach((a) => {
|
||||
a.modelName = map.get(a.guid[0].split("-")[3]);
|
||||
});
|
||||
});
|
||||
this.building_group = this.scene.building_group;
|
||||
// console.log(this.building_group);
|
||||
} catch (error) {
|
||||
// 处理可能错误
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async model(Model) {
|
||||
try {
|
||||
// 执行 axios 请求并等待 fetchData 函数的异步操作完成
|
||||
await this.fetchData();
|
||||
const modelList = {};
|
||||
this.scene.model_def_group.forEach((item) => {
|
||||
modelList[item.guid] = item.name;
|
||||
});
|
||||
const modelTotal = this.scene.building_group.length;
|
||||
this.createModel(Model, modelList, modelTotal);
|
||||
this.scene.ground_group.forEach((ground) => {
|
||||
const lon = ground.transform.translate.x;
|
||||
const lat = ground.transform.translate.y;
|
||||
const scale = ground.transform.scale;
|
||||
ground.model_ref_group.forEach((layer) => {
|
||||
// console.log(layer,'111');
|
||||
const height = this.groundHeight;
|
||||
const unit = {
|
||||
lon,
|
||||
lat,
|
||||
scale,
|
||||
id: layer.model_def_guid,
|
||||
};
|
||||
this.logNum([layer], height, unit, modelList, Model);
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
// 处理可能的错误
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
createModel(Model, modelList, modelTotal) {
|
||||
this.scene.building_group.forEach((building, index) => {
|
||||
if (
|
||||
Number(this.number * 2) <= index &&
|
||||
index < Number((this.number + 1) * 2)
|
||||
) {
|
||||
const lon = building.transform.translate.x;
|
||||
const lat = building.transform.translate.y;
|
||||
const scale = building.transform.scale;
|
||||
building.layer_group.forEach((layer) => {
|
||||
// console.log(layer,'111');
|
||||
const height = Number(layer.height[0] + this.groundHeight);
|
||||
const unit = {
|
||||
lon,
|
||||
lat,
|
||||
scale,
|
||||
id: layer.guid[0],
|
||||
};
|
||||
this.logNum(layer.model_ref_group, height, unit, modelList, Model);
|
||||
});
|
||||
}
|
||||
});
|
||||
if (this.number * 2 < modelTotal) {
|
||||
const throttle = setTimeout(() => {
|
||||
this.number++;
|
||||
this.createModel(Model, modelList, modelTotal);
|
||||
sessionStorage.setItem("loading", (this.number * 2) / modelTotal);
|
||||
clearTimeout(throttle);
|
||||
}, 20);
|
||||
if (
|
||||
(this.number * 2) / modelTotal >= 0.5 &&
|
||||
(this.number * 2) / modelTotal < 0.8
|
||||
) {
|
||||
sessionStorage.setItem("loadModel", "过半");
|
||||
} else if ((this.number * 2) / modelTotal >= 0.8) {
|
||||
sessionStorage.setItem("loadModel", "临底");
|
||||
}
|
||||
} else {
|
||||
console.log(
|
||||
"加载完成 ,此次加载:" +
|
||||
modelTotal +
|
||||
"栋建筑,共:" +
|
||||
this.model_def_group.length +
|
||||
"个模型"
|
||||
);
|
||||
sessionStorage.setItem("loadModel", "完成");
|
||||
}
|
||||
}
|
||||
|
||||
logNum(red, height, unit, modelList, Model) {
|
||||
red.forEach((item) => {
|
||||
if (this.idList.indexOf(item.model_def_guid) !== -1) {
|
||||
return;
|
||||
}
|
||||
this.idList.push(item.model_def_guid);
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(
|
||||
Loadglb.modelMap,
|
||||
`${unit.id.split("-")[3].slice(0, unit.id.split("-")[3].length - 2)}`
|
||||
)
|
||||
) {
|
||||
Loadglb.modelMap[
|
||||
`${unit.id.split("-")[3].slice(0, unit.id.split("-")[3].length - 2)}`
|
||||
].push(item.model_def_guid);
|
||||
} else {
|
||||
Loadglb.modelMap[
|
||||
`${unit.id.split("-")[3].slice(0, unit.id.split("-")[3].length - 2)}`
|
||||
] = [item.model_def_guid];
|
||||
}
|
||||
const m = new Model(this.icy, {
|
||||
id: item.model_def_guid,
|
||||
name: "建筑",
|
||||
url: `${url}${modelList[item.model_def_guid]}.gltf`,
|
||||
height,
|
||||
lon: unit.lon,
|
||||
lat: unit.lat,
|
||||
scale: unit.scale,
|
||||
angle: [90, 0, 0],
|
||||
// angle: [97.4843053, 0, 0]
|
||||
});
|
||||
this.entityList.push(m);
|
||||
});
|
||||
}
|
||||
|
||||
getArr() {
|
||||
return this.building_group;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,228 @@
|
|||
import { Loadglb } from "./loadglb.js";
|
||||
|
||||
const loadMap = 3;
|
||||
let $entityTransparent = [];
|
||||
const clickModel = new Map();
|
||||
|
||||
let enclosure = null;
|
||||
export const initMap = (corp) => {
|
||||
window.$scene = new window.CustomCesium.Scene(
|
||||
"map",
|
||||
corp.CORP_NAME,
|
||||
Number(loadMap)
|
||||
);
|
||||
window.$icy = window.$scene.getIcy();
|
||||
window.$carmer = new window.CustomCesium.Carmer(window.$icy);
|
||||
window.$icy.viewer.targetFrameRate = "30";
|
||||
window.$icy.viewer.scene.light = new window.Cesium.DirectionalLight({
|
||||
// 去除时间原因影响模型颜色
|
||||
direction: new window.Cesium.Cartesian3(
|
||||
0.35492591601301104,
|
||||
-0.8909182691839401,
|
||||
-0.2833588392420772
|
||||
),
|
||||
});
|
||||
const [wgsLat, wgsLon] = bd09ToWgs84(corp.LATITUDE, corp.LONGITUDE);
|
||||
console.log(corp.LATITUDE, corp.LONGITUDE);
|
||||
flyTo(wgsLon, wgsLat);
|
||||
// 亮度设置
|
||||
const stages = window.$icy.viewer.scene.postProcessStages;
|
||||
window.$icy.viewer.scene.brightness =
|
||||
window.$icy.viewer.scene.brightness ||
|
||||
stages.add(window.Cesium.PostProcessStageLibrary.createBrightnessStage());
|
||||
window.$icy.viewer.scene.brightness.enabled = true;
|
||||
window.$icy.viewer.scene.brightness.uniforms.brightness = Number(1.05); // 此处亮度值为倍数
|
||||
createGlb(); // 加载glb
|
||||
};
|
||||
|
||||
const bd09ToWgs84 = (bdLat, bdLon) => {
|
||||
const pi = Math.PI;
|
||||
const x_pi = (pi * 3000.0) / 180.0;
|
||||
const x = bdLon - 0.0065;
|
||||
const y = bdLat - 0.006;
|
||||
const z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
|
||||
const theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
|
||||
const wgsLon = z * Math.cos(theta);
|
||||
const wgsLat = z * Math.sin(theta);
|
||||
return [wgsLat, wgsLon];
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const flyTo = (lng, lat) => {
|
||||
window.$carmer.flyTo({
|
||||
// 视角飞入
|
||||
maxHeight: 1500,
|
||||
time: 1,
|
||||
position: [lng, lat, 200],
|
||||
angle: [0, -60, 0],
|
||||
});
|
||||
};
|
||||
|
||||
const createGlb = () => {
|
||||
// 加载glb(建筑模型)
|
||||
const loadGlb = new Loadglb(window.$icy);
|
||||
loadGlb.model(window.CustomCesium.Model);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
export const handleMouseClick = (model_id) => {
|
||||
// 加载鼠标拾取
|
||||
const $mouse = new window.CustomCesium.Mouse(window.$icy);
|
||||
// 隐藏逻辑
|
||||
$mouse.mouseLeft((model) => {
|
||||
if (model._name === "建筑") {
|
||||
model_id.value = model._id;
|
||||
console.log(model_id);
|
||||
clickBuilding(model);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const clickBuilding = (model) => {
|
||||
if (
|
||||
Loadglb.modelMap[
|
||||
`${model._id.split("-")[3].slice(0, model._id.split("-")[3].length - 2)}`
|
||||
]
|
||||
) {
|
||||
if (
|
||||
clickModel.get(
|
||||
`${model._id
|
||||
.split("-")[3]
|
||||
.slice(0, model._id.split("-")[3].length - 2)}`
|
||||
) === undefined
|
||||
) {
|
||||
// 如果这个模型是第一次点击
|
||||
const m =
|
||||
Loadglb.modelMap[
|
||||
`${model._id
|
||||
.split("-")[3]
|
||||
.slice(0, model._id.split("-")[3].length - 2)}`
|
||||
]; // 整栋楼的id集合
|
||||
// console.log(m, '整栋楼id');
|
||||
if (m.length > 1) {
|
||||
// 当前点击这建筑是否有多层
|
||||
m.forEach((id) => {
|
||||
const entity = window.$icy.viewer.entities.getById(id);
|
||||
if (model.id !== id) {
|
||||
// 排除当前点击楼层
|
||||
if (entity._icy.height > model._icy.height) {
|
||||
if (
|
||||
$entityTransparent.map((a) => a._id).indexOf(entity._id) === -1
|
||||
) {
|
||||
$entityTransparent.push(entity);
|
||||
}
|
||||
// console.log(this.$entityTransparent, '被隐藏的模型楼层集合');
|
||||
entity.model.show = false;
|
||||
}
|
||||
} else {
|
||||
clickModel.set(
|
||||
`${model._id
|
||||
.split("-")[3]
|
||||
.slice(0, model._id.split("-")[3].length - 2)}`,
|
||||
model._icy.height
|
||||
); // 存储这个模型数据
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// 如果点击过这个模型
|
||||
const m =
|
||||
Loadglb.modelMap[
|
||||
`${model._id
|
||||
.split("-")[3]
|
||||
.slice(0, model._id.split("-")[3].length - 2)}`
|
||||
]; // 整栋楼的id集合
|
||||
// console.log(m, '整栋楼id');
|
||||
if (m.length > 1) {
|
||||
// 当前点击这建筑是否有多层
|
||||
if (
|
||||
model._icy.height ===
|
||||
clickModel.get(
|
||||
`${model._id
|
||||
.split("-")[3]
|
||||
.slice(0, model._id.split("-")[3].length - 2)}`
|
||||
)
|
||||
) {
|
||||
m.forEach((id) => {
|
||||
const entity = window.$icy.viewer.entities.getById(id);
|
||||
entity.model.show = true;
|
||||
clickModel.delete(
|
||||
`${model._id
|
||||
.split("-")[3]
|
||||
.slice(0, model._id.split("-")[3].length - 2)}`
|
||||
);
|
||||
});
|
||||
} else {
|
||||
m.forEach((id) => {
|
||||
const entity = window.$icy.viewer.entities.getById(id);
|
||||
if (model.id !== id) {
|
||||
// 排除当前点击楼层
|
||||
if (entity._icy.height > model._icy.height) {
|
||||
if (
|
||||
$entityTransparent.map((a) => a._id).indexOf(entity._id) ===
|
||||
-1
|
||||
) {
|
||||
$entityTransparent.push(entity);
|
||||
}
|
||||
// console.log(this.$entityTransparent, '被隐藏的模型楼层集合');
|
||||
entity.model.show = false;
|
||||
}
|
||||
} else {
|
||||
clickModel.set(
|
||||
`${model._id
|
||||
.split("-")[3]
|
||||
.slice(0, model._id.split("-")[3].length - 2)}`,
|
||||
model._icy.height
|
||||
); // 存储这个模型数据
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// model.model.color = new Cesium.Color(1, 1, 1, 0.6);
|
||||
}
|
||||
};
|
||||
|
||||
// 还原建筑物
|
||||
export const reduction = () => {
|
||||
// 揭盖一键还原
|
||||
if ($entityTransparent.length !== 0) {
|
||||
$entityTransparent = $entityTransparent.forEach((item) => {
|
||||
item.model.color = new window.Cesium.Color(1, 1, 1, 1);
|
||||
item.model.show = true;
|
||||
});
|
||||
$entityTransparent = [];
|
||||
}
|
||||
};
|
||||
|
||||
export const handleEnclosure = (positions) => {
|
||||
const $mouse = new window.CustomCesium.Mouse(window.$icy);
|
||||
enclosure = new window.CustomCesium.Enclosure(window.$icy);
|
||||
// 编辑围栏使用鼠标控件参照demo.html
|
||||
enclosure.start();
|
||||
$mouse.mouseRight((e) => {
|
||||
enclosure.add(e.lng, e.lat, e.alt);
|
||||
positions.push([e.lng, e.lat, e.alt]);
|
||||
});
|
||||
};
|
||||
|
||||
export const clearEnclosure = () => {
|
||||
if (enclosure) {
|
||||
try {
|
||||
enclosure.show(false);
|
||||
} catch (e) {}
|
||||
enclosure.clear();
|
||||
enclosure = new window.CustomCesium.Enclosure(window.$icy);
|
||||
enclosure.start();
|
||||
}
|
||||
};
|
||||
|
||||
export const showEnclosure = (positions) => {
|
||||
enclosure.finish();
|
||||
enclosure.showDataSource(
|
||||
positions, // 数据
|
||||
30, // 高度
|
||||
"yellow" // 颜色默认黄色
|
||||
);
|
||||
enclosure.show(true);
|
||||
};
|
|
@ -2,7 +2,11 @@ import { post } from "./axios";
|
|||
|
||||
export const getRealTimeList = (params) => post("/map/getRealTimeList", params); // 获取在线人员列表
|
||||
export const getFenceList = (params) => post("/map/getFenceList", params); // 获取围栏列表
|
||||
export const getPersonnelTrajectories = (params) =>
|
||||
post("/map/getPersonnelTrajectories", params); // 获取拥有历史轨迹的全部角色
|
||||
|
||||
export const getCharacterTrajectories = (params) =>
|
||||
post("/map/getCharacterTrajectories", params); // 获取轨迹
|
||||
export const getUserByCardNo = (params) =>
|
||||
post("/user/getUserByCardNo", params);
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@ export const setAssignmentTicketAreaSettingsDeactivateOrEnable = (params) =>
|
|||
post("/positAlarm/otherRegion/editStatus", params); // 作业票区域设置停用启用
|
||||
export const setAssignmentTicketAreaSettingsDelete = (params) =>
|
||||
post("/positAlarm/otherRegion/regionDelete", params); // 作业票区域设置删除
|
||||
export const setPosition = (params) =>
|
||||
post("/positAlarm/otherRegion/redrawTheArea", params); // 区域选点
|
||||
// TODO 接口不对
|
||||
export const getPathPlanningList = (params) =>
|
||||
post("/positAlarm/coordinateLine/addCoordinateLine", params); // 路径规划列表
|
||||
|
|
|
@ -17,5 +17,4 @@ export const setUnbindingDeployCardData = (params) =>
|
|||
export const getNotBindTheCardData = (params) =>
|
||||
post("/deploy/card/thePersonWhoDidNotBindTheCard", params); // 批量解绑
|
||||
|
||||
|
||||
// 设备管理 ====
|
||||
|
|
|
@ -102,17 +102,17 @@ const bottomOptionsList = [
|
|||
check: false,
|
||||
action: handleTrajectory,
|
||||
},
|
||||
{
|
||||
img: new URL("/src/assets/images/map/bottom/ico2.png", import.meta.url)
|
||||
.href,
|
||||
imgSelect: new URL(
|
||||
"/src/assets/images/map/bottom/ico2_on.png",
|
||||
import.meta.url
|
||||
).href,
|
||||
title: "视频",
|
||||
type: "video",
|
||||
check: false,
|
||||
},
|
||||
// {
|
||||
// img: new URL("/src/assets/images/map/bottom/ico2.png", import.meta.url)
|
||||
// .href,
|
||||
// imgSelect: new URL(
|
||||
// "/src/assets/images/map/bottom/ico2_on.png",
|
||||
// import.meta.url
|
||||
// ).href,
|
||||
// title: "视频",
|
||||
// type: "video",
|
||||
// check: false,
|
||||
// },
|
||||
{
|
||||
img: new URL("/src/assets/images/map/bottom/ico3.png", import.meta.url)
|
||||
.href,
|
||||
|
|
|
@ -11,7 +11,12 @@
|
|||
<el-col :span="6">
|
||||
<el-form-item prop="personnel">
|
||||
<el-select v-model="data.searchForm.personnel" filterable>
|
||||
<el-option label="河北秦安" value="河北秦安" />
|
||||
<el-option
|
||||
v-for="item in data.personList"
|
||||
:key="item.id"
|
||||
:label="item.name ? `${item.name}(${item.id})` : item.id"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
@ -46,9 +51,6 @@
|
|||
<el-slider v-model="currentSchedule" :max="data.maxSchedule" />
|
||||
<div>
|
||||
<span class="time">{{ data.time }}</span>
|
||||
<span class="text-yellow ml-10">
|
||||
当前所在图层:<el-tag size="small">{{ data.position }}</el-tag>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="speed ml-20">
|
||||
|
@ -68,10 +70,21 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive } from "vue";
|
||||
import { reactive, onBeforeUnmount } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { VideoPause, VideoPlay } from "@element-plus/icons-vue";
|
||||
import {
|
||||
getPersonnelTrajectories,
|
||||
getCharacterTrajectories,
|
||||
} from "@/request/map.js";
|
||||
import dayjs from "dayjs";
|
||||
import { useInterval } from "@vueuse/core";
|
||||
import {
|
||||
addPerson,
|
||||
hadleDestroy,
|
||||
peoMovement,
|
||||
showLine,
|
||||
} from "@/views/BI/js/history_trajectory.js";
|
||||
|
||||
const data = reactive({
|
||||
searchForm: {
|
||||
|
@ -79,21 +92,62 @@ const data = reactive({
|
|||
dates: [],
|
||||
},
|
||||
isPlay: false,
|
||||
maxSchedule: 100,
|
||||
time: "2021-08-01 12:00:00",
|
||||
maxSchedule: 0,
|
||||
time: "0000-00-00 00:00:00",
|
||||
position: "图层1",
|
||||
speed: 1.0,
|
||||
personList: [],
|
||||
positions: [],
|
||||
});
|
||||
const {
|
||||
counter: currentSchedule,
|
||||
pause,
|
||||
resume,
|
||||
reset,
|
||||
} = useInterval(() => 1000 / data.speed, {
|
||||
immediate: false,
|
||||
controls: true,
|
||||
callback: () => {},
|
||||
callback: (count) => {
|
||||
if (count >= data.maxSchedule) {
|
||||
data.isPlay = false;
|
||||
pause();
|
||||
reset();
|
||||
}
|
||||
const currentData = data.positions[count].split(",");
|
||||
const previousValue = count === 0 ? undefined : data.positions[count - 1];
|
||||
const previousPosition = previousValue ? previousValue.split(",") : [];
|
||||
data.time = dayjs(Number(currentData[3])).format("YYYY-MM-DD HH:mm:ss");
|
||||
peoMovement(
|
||||
data.searchForm.personnel,
|
||||
currentData[0],
|
||||
currentData[1],
|
||||
currentData[2],
|
||||
previousValue
|
||||
? angleMath(
|
||||
previousPosition[0],
|
||||
previousPosition[1],
|
||||
currentData[0],
|
||||
currentData[1]
|
||||
)
|
||||
: undefined
|
||||
);
|
||||
},
|
||||
});
|
||||
const fnGetData = () => {
|
||||
|
||||
const angleMath = (lon, lat, lon1, lat1) => {
|
||||
// 计算人物模型朝向角度
|
||||
const radian = Math.atan2(lon - lon1, lat - lat1); // 返回来的是弧度
|
||||
const angle = Number((180 / Math.PI) * radian - 180); // 根据弧度计算角度
|
||||
return angle;
|
||||
};
|
||||
|
||||
const getPersonList = async () => {
|
||||
const res = await getPersonnelTrajectories();
|
||||
data.personList = res.data.data;
|
||||
};
|
||||
|
||||
getPersonList();
|
||||
const fnGetData = async () => {
|
||||
if (data.searchForm.personnel === "") {
|
||||
ElMessage.warning("请选择人员");
|
||||
return;
|
||||
|
@ -102,8 +156,49 @@ const fnGetData = () => {
|
|||
ElMessage.warning("请选择时间");
|
||||
return;
|
||||
}
|
||||
hadleDestroy();
|
||||
data.positions = [];
|
||||
pause();
|
||||
reset();
|
||||
await getTrajectoriesData(
|
||||
data.searchForm.personnel,
|
||||
data.searchForm.dates[0],
|
||||
data.searchForm.dates[1],
|
||||
1
|
||||
);
|
||||
data.maxSchedule = data.positions.length;
|
||||
const firstData = data.positions[0].split(",");
|
||||
data.time = dayjs(Number(firstData[3])).format("YYYY-MM-DD HH:mm:ss");
|
||||
const person = data.personList.filter(
|
||||
(item) => item.id === data.searchForm.personnel
|
||||
)[0];
|
||||
addPerson(
|
||||
data.searchForm.personnel,
|
||||
person.name ? person.name : person.id,
|
||||
firstData[0],
|
||||
firstData[1],
|
||||
firstData[2]
|
||||
);
|
||||
const positions = data.positions.map((item) => {
|
||||
const position = item.split(",");
|
||||
return [position[0], position[1], Number(position[2]) + 0.5];
|
||||
});
|
||||
showLine(positions);
|
||||
ElMessage.success("搜索成功");
|
||||
};
|
||||
const getTrajectoriesData = async (id, startTime, endTime, type) => {
|
||||
const res = await getCharacterTrajectories({
|
||||
id,
|
||||
startTime,
|
||||
endTime,
|
||||
type,
|
||||
});
|
||||
data.positions = data.positions.concat(res.data.data);
|
||||
if (res.data.msg !== "人物轨迹结束") {
|
||||
type++;
|
||||
await getTrajectoriesData(id, startTime, endTime, type);
|
||||
}
|
||||
};
|
||||
const fnPlay = () => {
|
||||
data.isPlay = true;
|
||||
resume();
|
||||
|
@ -112,6 +207,11 @@ const fnPause = () => {
|
|||
data.isPlay = false;
|
||||
pause();
|
||||
};
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
console.log("onBeforeUnmount");
|
||||
hadleDestroy();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
|
|
@ -55,6 +55,8 @@ import BottomOptions from "./components/bottom_options.vue";
|
|||
import HistoricalTrajectoryOptions from "./components/historical_trajectory_options.vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { initMap } from "./js/map";
|
||||
import { useUserStore } from "@/pinia/user.js";
|
||||
import { getEnterpriseInfo } from "@/request/enterprise_management.js";
|
||||
|
||||
const router = useRouter();
|
||||
const right_option = ref(true);
|
||||
|
@ -62,9 +64,10 @@ const transitionKey = ref(0);
|
|||
const leftCurrentComponent = ref("");
|
||||
const rightCurrentComponent = ref("");
|
||||
const isHistoricalTrajectory = ref(false);
|
||||
const corp = { CORP_NAME: "河北秦安", lng: 119.44758654, lat: 39.91845908 };
|
||||
const userStore = useUserStore();
|
||||
const CORPINFO_ID = userStore.getUserInfo.CORPINFO_ID;
|
||||
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
autofit.init({
|
||||
dh: document.querySelector(".map_bg").offsetHeight,
|
||||
dw: 1920,
|
||||
|
@ -72,9 +75,13 @@ onMounted(() => {
|
|||
resize: true,
|
||||
});
|
||||
transitionKey.value = Math.random();
|
||||
initMap(corp);
|
||||
const corp = await getEnterpriseInfo({ CORPINFO_ID });
|
||||
initMap(corp.pd);
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
window.$scene = null;
|
||||
window.$icy = null;
|
||||
window.$carmer = null;
|
||||
autofit.off();
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
let entityArr = [];
|
||||
let billboardArr = [];
|
||||
let line = [];
|
||||
export const addPerson = (id, name, lon, lat, height) => {
|
||||
entityArr = new window.CustomCesium.GroupModel("人物模型");
|
||||
billboardArr = new window.CustomCesium.GroupModel("人物姓名");
|
||||
addEntity(id, name, lon, lat, height);
|
||||
addBillboard(id, name, lon, lat, height);
|
||||
};
|
||||
const addEntity = (id, name, lon, lat, height) => {
|
||||
const obj = new window.CustomCesium.Model(window.$icy, {
|
||||
url: "/src/assets/glb/person_000002_blue.gltf",
|
||||
height: 0,
|
||||
scale: 1,
|
||||
angle: [-90, 0, 0],
|
||||
});
|
||||
let e;
|
||||
// eslint-disable-next-line prefer-const
|
||||
e = obj.clone(e);
|
||||
const enModule = new window.CustomCesium.Model(
|
||||
window.$icy,
|
||||
{
|
||||
name: "人物",
|
||||
height,
|
||||
id,
|
||||
lon,
|
||||
lat, // 位置
|
||||
scale: 1, // 大小
|
||||
angle: [-90, 0, 0],
|
||||
},
|
||||
e
|
||||
);
|
||||
// 修改模型方向 第一个参数是航向角
|
||||
// enModule.updateAngle([-90,20,20]);
|
||||
entityArr.add(enModule);
|
||||
};
|
||||
|
||||
const addBillboard = (id, name, lon, lat, height) => {
|
||||
// 创建广告牌
|
||||
const bulletinBoard = new window.CustomCesium.BulletinBoard(window.$icy);
|
||||
bulletinBoard.loadCanvas(drawCanvas(name), {
|
||||
name: "人物铭牌",
|
||||
id: id + "_name",
|
||||
lon,
|
||||
lat,
|
||||
height: Number(height) + 2.05,
|
||||
});
|
||||
billboardArr.add(bulletinBoard);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const drawCanvas = (name) => {
|
||||
const canvas = document.createElement("canvas");
|
||||
const width = 70;
|
||||
const height = 20;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
const borderRadius = 5; // 圆角半径
|
||||
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(borderRadius, 0);
|
||||
ctx.lineTo(width - borderRadius, 0);
|
||||
ctx.arcTo(width, 0, width, borderRadius, borderRadius);
|
||||
ctx.lineTo(width, height - borderRadius);
|
||||
ctx.arcTo(width, height, width - borderRadius, height, borderRadius);
|
||||
ctx.lineTo(borderRadius, height);
|
||||
ctx.arcTo(0, height, 0, height - borderRadius, borderRadius);
|
||||
ctx.lineTo(0, borderRadius);
|
||||
ctx.arcTo(0, 0, borderRadius, 0, borderRadius);
|
||||
ctx.closePath();
|
||||
|
||||
ctx.fillStyle = "rgba(42, 86, 158, 1)";
|
||||
ctx.fill();
|
||||
|
||||
ctx.fillStyle = "#fff";
|
||||
ctx.font = "normal 12px 'Microsoft YaHei'";
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fillText(name, width / 2, height / 2);
|
||||
return canvas;
|
||||
};
|
||||
|
||||
/**
|
||||
* 显示轨迹线
|
||||
*/
|
||||
export const showLine = (positions) => {
|
||||
line = new window.CustomCesium.Line(window.$icy, {
|
||||
width: 10,
|
||||
positions,
|
||||
color: "#00ff00",
|
||||
});
|
||||
line.show(true);
|
||||
// line.destroy();
|
||||
};
|
||||
|
||||
/**
|
||||
* id, lon, lat, height,alt 接收人物移动数据
|
||||
* entityArr 接收人物模型分组
|
||||
* billboardArr 接收人物铭牌分组
|
||||
*/
|
||||
export const peoMovement = (id, lon, lat, height, alt) => {
|
||||
entityArr.children.forEach((b, m) => {
|
||||
if (b.entity._id === id) {
|
||||
b.updateAngle([alt, 0, 0]); // 改变人物朝向
|
||||
b.animationMove(lon, lat, height, 1000, () => {}); // 人物平滑移动
|
||||
billboardArr.children[m].animationMove(
|
||||
lon,
|
||||
lat,
|
||||
Number(Number(height) + 2.05),
|
||||
1000
|
||||
); // 人物铭牌平滑移动
|
||||
} else {
|
||||
console.log(`人物移动数据错误`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const hadleDestroy = () => {
|
||||
if (entityArr && entityArr.children) {
|
||||
entityArr.children.forEach((e) => {
|
||||
e.destroy();
|
||||
});
|
||||
billboardArr.children.forEach((e) => {
|
||||
e.destroy();
|
||||
});
|
||||
line.destroy();
|
||||
entityArr = [];
|
||||
billboardArr = [];
|
||||
line = [];
|
||||
}
|
||||
};
|
|
@ -35,7 +35,8 @@ export const initMap = (corp) => {
|
|||
-0.2833588392420772
|
||||
),
|
||||
});
|
||||
flyTo(corp.lng, corp.lat);
|
||||
const [wgsLat, wgsLon] = bd09ToWgs84(corp.LATITUDE, corp.LONGITUDE);
|
||||
flyTo(wgsLon, wgsLat);
|
||||
// 亮度设置
|
||||
const stages = window.$icy.viewer.scene.postProcessStages;
|
||||
window.$icy.viewer.scene.brightness =
|
||||
|
@ -47,6 +48,18 @@ export const initMap = (corp) => {
|
|||
handleMouseClick(); // 加载鼠标拾取
|
||||
};
|
||||
|
||||
const bd09ToWgs84 = (bdLat, bdLon) => {
|
||||
const pi = Math.PI;
|
||||
const x_pi = (pi * 3000.0) / 180.0;
|
||||
const x = bdLon - 0.0065;
|
||||
const y = bdLat - 0.006;
|
||||
const z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
|
||||
const theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
|
||||
const wgsLon = z * Math.cos(theta);
|
||||
const wgsLat = z * Math.sin(theta);
|
||||
return [wgsLat, wgsLon];
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const flyTo = (lng, lat) => {
|
||||
window.$carmer.flyTo({
|
||||
|
|
|
@ -2,7 +2,7 @@ import pako from "pako"; // 解密gzip插件
|
|||
import { useWebSocket } from "@vueuse/core";
|
||||
import { useUserStore } from "@/pinia/user";
|
||||
import pinia from "@/pinia";
|
||||
import { getRealTimeList, getFenceList } from "@/request/map";
|
||||
import { getFenceList } from "@/request/map";
|
||||
|
||||
const userStore = useUserStore(pinia);
|
||||
const pls_ip = userStore.getUserInfo.POST_URL;
|
||||
|
@ -39,50 +39,20 @@ const { open, close } = useWebSocket(
|
|||
billboardArr.children.forEach((e) => {
|
||||
e.destroy();
|
||||
});
|
||||
entityArr = [];
|
||||
billboardArr = [];
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
export const handleTrajectory = (b) => {
|
||||
if (b) {
|
||||
getOnlineUser();
|
||||
open();
|
||||
} else {
|
||||
close();
|
||||
}
|
||||
};
|
||||
|
||||
const getOnlineUser = async () => {
|
||||
entityArr = new window.CustomCesium.GroupModel("人物模型");
|
||||
billboardArr = new window.CustomCesium.GroupModel("人物姓名");
|
||||
// await getRealTimeList();
|
||||
const { data } = await getRealTimeList();
|
||||
let userList = data.data;
|
||||
userList = [
|
||||
{
|
||||
cardNo: "8379",
|
||||
name: "大大",
|
||||
longitude: 119.44768654,
|
||||
latitude: 39.91745908,
|
||||
altitude: 0,
|
||||
},
|
||||
{
|
||||
cardNo: "9979",
|
||||
name: "小小小小",
|
||||
longitude: 119.44758754,
|
||||
latitude: 39.91745908,
|
||||
altitude: 0,
|
||||
},
|
||||
];
|
||||
|
||||
userList.forEach(({ cardNo, name, longitude, latitude, altitude }) => {
|
||||
addEntity(cardNo, name, longitude, latitude, altitude);
|
||||
addBillboard(cardNo, name, longitude, latitude, altitude + 2);
|
||||
});
|
||||
entityArr.show(true);
|
||||
billboardArr.show(true);
|
||||
};
|
||||
|
||||
const addEntity = (id, name, lon, lat, height) => {
|
||||
const obj = new window.CustomCesium.Model(window.$icy, {
|
||||
url: "/src/assets/glb/person_000002_blue.gltf",
|
||||
|
@ -119,7 +89,7 @@ const addBillboard = (id, name, lon, lat, height) => {
|
|||
id: id + "_name",
|
||||
lon,
|
||||
lat,
|
||||
height,
|
||||
height: height + 2.05,
|
||||
});
|
||||
billboardArr.add(bulletinBoard);
|
||||
};
|
||||
|
@ -190,8 +160,21 @@ function peoMovement(moveData) {
|
|||
const map = new Map();
|
||||
moveData.forEach((i, n) => {
|
||||
map.set(i.split(",")[0], n);
|
||||
});
|
||||
if (!entityArr || !entityArr.children) {
|
||||
entityArr = new window.CustomCesium.GroupModel("人物模型");
|
||||
billboardArr = new window.CustomCesium.GroupModel("人物姓名");
|
||||
const entity = i.split(",");
|
||||
addEntity(entity[0], entity[8], entity[1], entity[2], entity[4]);
|
||||
addBillboard(entity[0], entity[8], entity[1], entity[2], entity[4]);
|
||||
}
|
||||
|
||||
entityArr.children.forEach((b, m) => {
|
||||
if (!b.entity) {
|
||||
const entity = i.split(",");
|
||||
addEntity(entity[0], entity[8], entity[1], entity[2], entity[4]);
|
||||
addBillboard(entity[0], entity[8], entity[1], entity[2], entity[4]);
|
||||
return;
|
||||
}
|
||||
const index = map.get(b.entity._id);
|
||||
const item = moveData[index];
|
||||
if (index !== undefined) {
|
||||
|
@ -214,8 +197,13 @@ function peoMovement(moveData) {
|
|||
} else {
|
||||
console.log(`人物移动数据错误,错误参数:'${item}'`);
|
||||
}
|
||||
} else {
|
||||
const entity = i.split(",");
|
||||
addEntity(entity[0], entity[8], entity[1], entity[2], entity[4]);
|
||||
addBillboard(entity[0], entity[8], entity[1], entity[2], entity[4]);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export const handleFence = async (b) => {
|
||||
|
|
|
@ -13,12 +13,7 @@
|
|||
</div>
|
||||
<div class="video">
|
||||
<ali-player
|
||||
v-if="tabsIndex === 0 && ptVideoSrc"
|
||||
:source="VITE_FILE_URL + ptVideoSrc"
|
||||
height="182px"
|
||||
/>
|
||||
<ali-player
|
||||
v-if="tabsIndex === 1 && cpVideoSrc"
|
||||
v-if="tabsIndex === 0 && cpVideoSrc"
|
||||
:source="VITE_FILE_URL + cpVideoSrc"
|
||||
height="182px"
|
||||
/>
|
||||
|
@ -32,7 +27,7 @@ import { getVideo } from "@/request/large_screen_data_display.js";
|
|||
import AliPlayer from "@/components/ali-player/index.vue";
|
||||
|
||||
const VITE_FILE_URL = import.meta.env.VITE_FILE_URL;
|
||||
const tabsList = ["平台视频", "企业视频"];
|
||||
const tabsList = ["企业视频"];
|
||||
const tabsIndex = ref(0);
|
||||
const ptVideoSrc = ref("");
|
||||
const cpVideoSrc = ref("");
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<template>
|
||||
<el-dialog v-model="visible" title="选点" :on-close="fnClose">
|
||||
<map-tools v-if="visible" ref="mapToolsRef" v-model:positions="positions" />
|
||||
<template #footer>
|
||||
<el-button @click="fnClose">关闭</el-button>
|
||||
<el-button type="primary" @click="fnSubmit">保存</el-button>
|
||||
|
@ -8,9 +9,12 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { useVModels } from "@vueuse/core";
|
||||
import { debounce } from "throttle-debounce";
|
||||
import { ElMessage } from "element-plus";
|
||||
import MapTools from "@/components/map_tools";
|
||||
import { setPosition } from "@/request/map_settings.js";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
|
@ -18,15 +22,26 @@ const props = defineProps({
|
|||
required: true,
|
||||
default: false,
|
||||
},
|
||||
id: {
|
||||
type: Number,
|
||||
required: true,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
const emits = defineEmits(["update:visible", "get-data"]);
|
||||
const { visible } = useVModels(props, emits);
|
||||
const positions = ref([]);
|
||||
const fnClose = () => {
|
||||
visible.value = false;
|
||||
};
|
||||
const fnSubmit = debounce(
|
||||
1000,
|
||||
async () => {
|
||||
if (positions.value.length < 3) {
|
||||
ElMessage.warning("请选择至少3个点");
|
||||
return;
|
||||
}
|
||||
await setPosition({ id: props.id, list: JSON.stringify(positions.value) });
|
||||
ElMessage.success("保存成功");
|
||||
fnClose();
|
||||
emits("get-data");
|
||||
|
|
|
@ -104,6 +104,7 @@
|
|||
@get-data="fnResetPagination"
|
||||
/>
|
||||
<selecting-points
|
||||
:id="data.selectingPointsDialog.id"
|
||||
v-model:visible="data.selectingPointsDialog.visible"
|
||||
@get-data="fnResetPagination"
|
||||
/>
|
||||
|
|
|
@ -59,24 +59,24 @@
|
|||
<el-button type="primary" text link @click="fnQrCode(row)">
|
||||
二维码
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="buttonJurisdiction.edit"
|
||||
type="primary"
|
||||
text
|
||||
link
|
||||
@click="
|
||||
router.push({
|
||||
path: '/risk_control/identifying_parts/resources_risk',
|
||||
query: {
|
||||
IDENTIFICATIONPARTS_ID: row.IDENTIFICATIONPARTS_ID,
|
||||
PARTSNAME: row.PARTSNAME,
|
||||
RISKUNITNAME: row.RISKUNITNAME,
|
||||
},
|
||||
})
|
||||
"
|
||||
>
|
||||
匹配资源存在风险
|
||||
</el-button>
|
||||
<!-- <el-button-->
|
||||
<!-- v-if="buttonJurisdiction.edit"-->
|
||||
<!-- type="primary"-->
|
||||
<!-- text-->
|
||||
<!-- link-->
|
||||
<!-- @click="-->
|
||||
<!-- router.push({-->
|
||||
<!-- path: '/risk_control/identifying_parts/resources_risk',-->
|
||||
<!-- query: {-->
|
||||
<!-- IDENTIFICATIONPARTS_ID: row.IDENTIFICATIONPARTS_ID,-->
|
||||
<!-- PARTSNAME: row.PARTSNAME,-->
|
||||
<!-- RISKUNITNAME: row.RISKUNITNAME,-->
|
||||
<!-- },-->
|
||||
<!-- })-->
|
||||
<!-- "-->
|
||||
<!-- >-->
|
||||
<!-- 匹配资源存在风险-->
|
||||
<!-- </el-button>-->
|
||||
<el-button
|
||||
v-if="buttonJurisdiction.edit"
|
||||
type="primary"
|
||||
|
@ -148,12 +148,11 @@ import { ElMessage, ElMessageBox } from "element-plus";
|
|||
import { nextTick, reactive } from "vue";
|
||||
import LayoutImportFile from "@/components/import_file/index.vue";
|
||||
import Add from "./components/add.vue";
|
||||
import { useRouter } from "vue-router";
|
||||
// import { useRouter } from "vue-router";
|
||||
import QrCode from "./components/qr_code.vue";
|
||||
import LayoutTooltipImg from "@/components/tooltip_img/index.vue";
|
||||
import useButtonJurisdiction from "@/assets/js/useButtonJurisdiction.js";
|
||||
|
||||
const router = useRouter();
|
||||
// const router = useRouter();
|
||||
const { list, pagination, searchForm, fnGetData, fnResetPagination, tableRef } =
|
||||
useListData(getIdentifyingPartsList);
|
||||
const data = reactive({
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="风险分级">
|
||||
<el-form-item label="风险分级" prop="LEVELID">
|
||||
<el-select v-model="searchForm.LEVELID">
|
||||
<el-option
|
||||
v-for="item in riskClassificationList"
|
||||
|
@ -43,7 +43,7 @@
|
|||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="事故类型">
|
||||
<el-form-item label="事故类型" prop="BIANMA">
|
||||
<el-select v-model="searchForm.BIANMA">
|
||||
<el-option
|
||||
v-for="item in accidentTypeList"
|
||||
|
|
Loading…
Reference in New Issue