From cff14a165299ee803a7fcf8b7b161ddb7f6ed891 Mon Sep 17 00:00:00 2001 From: LiuJiaNan <15703339975@163.com> Date: Mon, 27 Jul 2026 15:00:32 +0800 Subject: [PATCH] =?UTF-8?q?feat(map):=20=E9=9B=86=E6=88=90=E5=AE=9E?= =?UTF-8?q?=E6=97=B6=E4=BA=BA=E5=91=98=E5=AE=9A=E4=BD=8D=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../images/map_bi/point/ico_people_blue.png | Bin 0 -> 2730 bytes .../images/map_bi/point/ico_people_orange.png | Bin 0 -> 3096 bytes .../images/map_bi/point/ico_people_red.png | Bin 0 -> 3025 bytes .../images/map_bi/point/ico_people_yellow.png | Bin 0 -> 3130 bytes .../Map/components/BottomUtils/index.js | 120 +++++++++++++----- src/pages/Container/Map/index.js | 2 +- ...ectoryPolylineTrailLinkMaterialProperty.js | 0 .../WallPolylineTrailLinkMaterialProperty.js | 0 .../Map/js/{initMap.js => useInitMap.js} | 4 +- .../js/{mapMethods.js => useMapMethods.js} | 91 ++++++++++++- .../Container/Map/js/usePeoplePosition.js | 63 +++++++++ ...intClickEvent.js => usePointClickEvent.js} | 0 src/pages/Container/Map/js/utils.js | 49 ++++++- 13 files changed, 289 insertions(+), 40 deletions(-) create mode 100644 src/assets/images/map_bi/point/ico_people_blue.png create mode 100644 src/assets/images/map_bi/point/ico_people_orange.png create mode 100644 src/assets/images/map_bi/point/ico_people_red.png create mode 100644 src/assets/images/map_bi/point/ico_people_yellow.png rename src/pages/Container/Map/js/{ => material}/TrajectoryPolylineTrailLinkMaterialProperty.js (100%) rename src/pages/Container/Map/js/{ => material}/WallPolylineTrailLinkMaterialProperty.js (100%) rename src/pages/Container/Map/js/{initMap.js => useInitMap.js} (98%) rename src/pages/Container/Map/js/{mapMethods.js => useMapMethods.js} (83%) create mode 100644 src/pages/Container/Map/js/usePeoplePosition.js rename src/pages/Container/Map/js/{pointClickEvent.js => usePointClickEvent.js} (100%) diff --git a/src/assets/images/map_bi/point/ico_people_blue.png b/src/assets/images/map_bi/point/ico_people_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..3dd97d53550f769d67039c27757638a330b73bed GIT binary patch literal 2730 zcmaJ@XH-+!7LI^a=_rVbF`$AP(nAsqB_tqdFhY=sBBb0vfFzIvh%^BO9hL>gLJ^cY zO0NzeB8U_f>1Al@Fd!mNWY9qraOMR^=Di=Txoh2f_Bm&N-|lPOA85`F>Z*pSAP`91 z@c`LHwi?M^6J5#o-a!l{9F zfG_Vrm@Bs-EEae9X!~`i3@|Bk$lUI*n5b#$Oi9ZqY zw^Ix%4QwYA0bq?HLRmREMW@Rz?yBI%=R}d`d_gGI}yN?2t{|5|t3x#1?z@az} z7Y@a9(M%`~fnh-b91`Fn*%&4q1BZOWbH0;5JPwPpvp|zE2(ra${CEl+N20*dXgfF# zPlDS*U^0hbtBvx1jk9(n>&8{_pD~ba{uv}dAe$bMY)n3WvG4+c6gwTswsh%8v%7x) zoucUl`JpnCSfoV4@Z*t@bAm&UWy&d!Wl)Q5~kd@{`` z?)JQH-0g*Mg&!!j?~=FXbu_rXNx+&J84jE>9SCljn-QLKo+()<-nf@*R(5&Ct5KQ+ zxz%vQIJ9j)=)g525SeDM;Ca>X9Vpnv@BZeM_OjQnSwk?Q89a98kA|CtN#VaSYxQk5 zXO?WSNdk5Ms@SdJM4h$i$ojeH@`F^+>&e~a2xTX$YP{F170#39-t8&VCg@VOsN zyQKF;dM{u=zbwFzDw^NXYxruRwA5{5J*qrY1bPfIPB%u$u@ktj_QAp?zNq#OPJnU> zilWYm-w>1iK~441kZOlKIh9V2mHp42X*L;jXiR5ed%XA1(Pry+WhJs=%kbkS&WS}= zn@%exTDQzRikUa>>wR?lMgQy9mo*=nWQ&9;)(L1c%~%&~_GH))JI%eeXdy$hq2beK z4b8U+m)r*K9lKF|ZDUtqSc^(BW0-YvcXI+=8=q6KOJ!$JW9o^Vp8f3E)?)bG zv92eRN^!J_2hW*jFm)l_eV*@B6yDb--AOG#r*5rL-dc{bG}T5-A!i~(ZhX0JsIiS5 z@^Qz@#c1!Xx}@Hi%II$U4>31`1!MO!UwUJkPLj~HG}S_FMOqx0UMciilo*v*s`pje zBu5jXW7*|F7w{CzMCSW;;V&mD^oJ(o^qtZ!_BA+r)5H(FlI%q?WkF7wp-QgLl8WZJM&&JmPULfwHM^ z-b9P*@ia~g36Xbq1uHA1mDHwsF2}@gU!Q^ucKChf_=1v0yN!@7Aywj0`vKAJR%u?={^(m;c42^DNWQwhpZ`aNu5$=$#6oKgf8KHHqPJBb14do#X_22K9jl6AAwK)WWQBcv9V{$8`H z8r}GoK+_lRS*mH2YPn*jMsKi~`Nyk9DA06!Kg6X}ytZP(j_GaG4mSVeox2qT?u&3% zQr^e62g!)@5!6BCb!5)dRJU*-FL?P+xv4EV)!0SH)HfG4Uq7+Us@LYCnwjvpM!HD+ z?7#=(dP`07&gXbT`Nb;?bi}=`^i%kihyA+S_LdD9#Gc`vEM}!OLz16xGSA;`Usw4y zHs|5o`;t)|< znsEi?^tAoAiYN>M7@QhViYns|30}`jy@&4>M(r{SpE6Clsv>2QdpqJ5vb~SH(zR=b zcIF@TF{!E|X=uLK>ofVb1x8oflUd6|-2tbZe}++goil>K>5k7`UB zbMGK9+_rus?U4@Ee+K7$a)A+1e=(V!RTiP)RZF&O{c(8oWA;dSw6?lIooySvuGndJ z?vm-WPjgXR*R`eNHzEi-uI1S;6;-`Zduir(sD5-zEBo^mC$t#MP6em+3B1frDhqSh z*$wE5)bx&=JiDNI6ewn=V@u1b$4S;rI^mGo6S?H;8s)a2cTW39=-Jbj-QBrwCYHvEFRm{iugSG=RMgUS5A`J9=3vq0VI!ElKk!QD#$)AMg_J1{w>3J$ zaW_h3Vyp#GlD8w^a%)O6(ZPVWy|1~f_4m_q8$h=V_En812drEDdvv5YlS@e6vHt}| Cz=LG~ literal 0 HcmV?d00001 diff --git a/src/assets/images/map_bi/point/ico_people_orange.png b/src/assets/images/map_bi/point/ico_people_orange.png new file mode 100644 index 0000000000000000000000000000000000000000..a2fa564c6acb70664a162f1eb53cf59246bdc372 GIT binary patch literal 3096 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 literal 0 HcmV?d00001 diff --git a/src/assets/images/map_bi/point/ico_people_red.png b/src/assets/images/map_bi/point/ico_people_red.png new file mode 100644 index 0000000000000000000000000000000000000000..afbb83c749fdf37d8166fa45e86e6140512d8025 GIT binary patch literal 3025 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 { - const check = !list[index].list[index1].check; - if (check) { - if (item1.request) { - let pointData = []; - const requestParams = { portArea, corpinfoId: currentBranchOffice, pageIndex: 1, pageSize: 9999 }; - if (dangerWorkTypes.includes(item1.type)) { - requestParams.workType = item1.type; - } - if (gateTypes.includes(item1.type)) { - requestParams.gateType = item1.type; - } - const { data } = await props[item1.request](requestParams); - pointData = [...(data || [])]; - if (dangerWorkTypes.includes(item1.type)) { - for (let i = 0; i < pointData.length; i++) { - pointData[i].latitude = pointData[i].info.latitude; - pointData[i].longitude = pointData[i].info.longitude; - } - } - mapMethods.current.addMarkPoint(pointData, { - markType: item1.type, - markIcon: item1.markIcon, - subLabel: item1.label, - titleKey: item1.titleKey, - isShowModal: item1.isShowModal, - }); - } - } - else { - mapMethods.current.removeMarkPoint(item1.type); - } + // 统一维护子菜单勾选状态,避免各业务分支直接修改列表数据。 + const updateOptionCheck = (index, index1, check) => { setList(produce((draft) => { draft[index].list[index1].check = check; })); }; + // 人员轨迹依赖实时定位数据;取消定位时需要同步取消同组轨迹。 + const resetPeopleTrajectory = (index) => { + setList(produce((draft) => { + draft[index].list.forEach((option) => { + if (option.type === "peopleTrajectory") + option.check = false; + }); + })); + }; + + // 根据菜单类型补充接口参数转换坐标。 + const getMarkPointData = async (item) => { + const requestParams = { portArea, corpinfoId: currentBranchOffice, pageIndex: 1, pageSize: 9999 }; + if (dangerWorkTypes.includes(item.type)) + requestParams.workType = item.type; + if (gateTypes.includes(item.type)) + requestParams.gateType = item.type; + + const { data } = await props[item.request](requestParams); + const pointData = data || []; + if (dangerWorkTypes.includes(item.type)) { + return pointData.map(point => ({ + ...point, + latitude: point.info.latitude, + longitude: point.info.longitude, + })); + } + return pointData; + }; + + // 查询并渲染带请求配置的菜单点位;无请求配置的菜单无需执行地图操作。 + const addMarkPoint = async (item) => { + if (!item.request) + return; + + const pointData = await getMarkPointData(item); + mapMethods.current.addMarkPoint(pointData, { + markType: item.type, + markIcon: item.markIcon, + subLabel: item.label, + titleKey: item.titleKey, + isShowModal: item.isShowModal, + }); + }; + + const optionsItemsClick = async (index, index1, item) => { + const check = !list[index].list[index1].check; + updateOptionCheck(index, index1, check); + + if (!check) { + if (item.type === "peoplePosition") { + resetPeopleTrajectory(index); + peoplePositionDisconnect(); + return; + } + mapMethods.current.removeMarkPoint(item.type); + return; + } + + if (item.type === "peoplePosition" && currentPort === "00003") { + peoplePositionConnect(); + return; + } + + if (item.type === "peopleTrajectory") { + const isPeoplePositionChecked = list[index].list.some( + option => option.type === "peoplePosition" && option.check, + ); + if (!isPeoplePositionChecked) { + message.warning("请先选择人员定位!!!"); + updateOptionCheck(index, index1, false); + return; + } + } + + await addMarkPoint(item); + }; + const renderPortUtils = () => { if (bottomUtilsMode === "port" && listMode === bottomUtilsMode) { return list.map((item, index) => { @@ -194,7 +246,7 @@ function BottomUtils(props) { transition={{ delay: index1 * portUtilsAnimationConfig.staggerDelay }} onClick={(e) => { e.stopPropagation(); - optionsItemsClick(index, index1, item, item1); + optionsItemsClick(index, index1, item1); }} > @@ -239,7 +291,7 @@ function BottomUtils(props) { className={`item ${item1.check ? "active" : ""}`} onClick={(e) => { e.stopPropagation(); - optionsItemsClick(index, index1, item, item1); + optionsItemsClick(index, index1, item1); }} variants={branchOfficeItemAnimation} > diff --git a/src/pages/Container/Map/index.js b/src/pages/Container/Map/index.js index 7f71a52..d9e6a1f 100644 --- a/src/pages/Container/Map/index.js +++ b/src/pages/Container/Map/index.js @@ -12,7 +12,6 @@ import CustomModal from "./components/Content/modal"; import Header from "./components/Header"; import RightUtils from "./components/RightUtils"; import { Context, initialMapState, MAP_ACTION, mapReducer } from "./js/context"; -import useInitMap from "./js/initMap"; import mitt from "./js/mitt"; import { changeCoverMaskVisibleMittKey, @@ -21,6 +20,7 @@ import { clickPortPointMittKey, resetBottomUtilsMittKey, } from "./js/mittKey"; +import useInitMap from "./js/useInitMap"; import "./index.less"; function Map(props) { diff --git a/src/pages/Container/Map/js/TrajectoryPolylineTrailLinkMaterialProperty.js b/src/pages/Container/Map/js/material/TrajectoryPolylineTrailLinkMaterialProperty.js similarity index 100% rename from src/pages/Container/Map/js/TrajectoryPolylineTrailLinkMaterialProperty.js rename to src/pages/Container/Map/js/material/TrajectoryPolylineTrailLinkMaterialProperty.js diff --git a/src/pages/Container/Map/js/WallPolylineTrailLinkMaterialProperty.js b/src/pages/Container/Map/js/material/WallPolylineTrailLinkMaterialProperty.js similarity index 100% rename from src/pages/Container/Map/js/WallPolylineTrailLinkMaterialProperty.js rename to src/pages/Container/Map/js/material/WallPolylineTrailLinkMaterialProperty.js diff --git a/src/pages/Container/Map/js/initMap.js b/src/pages/Container/Map/js/useInitMap.js similarity index 98% rename from src/pages/Container/Map/js/initMap.js rename to src/pages/Container/Map/js/useInitMap.js index 29ddde4..1c4606b 100644 --- a/src/pages/Container/Map/js/initMap.js +++ b/src/pages/Container/Map/js/useInitMap.js @@ -1,7 +1,7 @@ import { useRef } from "react"; import { createObliquePhotography } from "~/pages/Container/Map/js/mapUtils"; -import useMapMethods from "./mapMethods"; -import usePointClickEvent from "./pointClickEvent"; +import useMapMethods from "./useMapMethods"; +import usePointClickEvent from "./usePointClickEvent"; const Cesium = window.Cesium; diff --git a/src/pages/Container/Map/js/mapMethods.js b/src/pages/Container/Map/js/useMapMethods.js similarity index 83% rename from src/pages/Container/Map/js/mapMethods.js rename to src/pages/Container/Map/js/useMapMethods.js index 970766e..ae51883 100644 --- a/src/pages/Container/Map/js/mapMethods.js +++ b/src/pages/Container/Map/js/useMapMethods.js @@ -1,6 +1,10 @@ import { useRef } from "react"; import portEntityBillboardImage from "~/assets/images/map_bi/point/dianwei.png"; import branchOfficeEntityBillboardImage from "~/assets/images/map_bi/point/gongsidianwei.png"; +import people_blue from "~/assets/images/map_bi/point/ico_people_blue.png"; +import people_orange from "~/assets/images/map_bi/point/ico_people_orange.png"; +import people_red from "~/assets/images/map_bi/point/ico_people_red.png"; +import people_yellow from "~/assets/images/map_bi/point/ico_people_yellow.png"; import edgeCMT from "./edge/cmt.js"; import edgeCSY from "./edge/csy.js"; import edgeCZKS from "./edge/czks.js"; @@ -16,8 +20,8 @@ import { import mitt from "./mitt"; import { changeCoverMaskVisibleMittKey } from "./mittKey"; import { chunkedLoad, filterNull, formatPolygon } from "./utils"; -import "./TrajectoryPolylineTrailLinkMaterialProperty.js"; -import "./WallPolylineTrailLinkMaterialProperty"; +import "./material/TrajectoryPolylineTrailLinkMaterialProperty.js"; +import "./material/WallPolylineTrailLinkMaterialProperty"; const portPoint = [ { @@ -53,6 +57,13 @@ const portPoint = [ }, ]; +const peopleImg = { + blue: people_blue, + orange: people_orange, + red: people_red, + yellow: people_yellow, +}; // 人员定位颜色图片 + const Cesium = window.Cesium; export default function useMapMethods(viewerRef, request) { @@ -80,6 +91,8 @@ export default function useMapMethods(viewerRef, request) { height: 900000, }); + const peopleId = useRef([]); // 人员定位 ID 列表 + // 设置中心点 const flyTo = ({ longitude, latitude, height } = defineCenterPoint) => { getViewer().camera.flyTo({ destination: getPosition(longitude, latitude, height), duration: 2 }); @@ -392,6 +405,76 @@ export default function useMapMethods(viewerRef, request) { removeEntityCollection(getViewer(), `markEntityCollectionMerged${markType ? `_${markType}` : ""}`); }; + const addPeoplePoint = async (point, options) => { + const image = peopleImg[point.icon_type]; + if (!image) + return; + if (!options.markType) + throw new Error("请传入markType(扎点类型)"); + const clonePoint = { ...point }; + point.property = new Cesium.SampledPositionProperty(); + const start = Cesium.JulianDate.now(); + const position = Cesium.Cartesian3.fromDegrees(point.x, point.y, 0); + point.property.addSample(start, position); + point.lastTime = start; + point.lastIconType = point.icon_type; + peopleId.current.push(point.id); + getViewer().entities.add({ + id: point.id, + name: point.name, + position: point.property, + billboard: await getBillboard({ + image, + name: point.name || point.id, + }), + monitorItems: { + data: { ...clonePoint, markType: `标记点_${options.markType}`, isShowModal: options.isShowModal ?? true }, + }, + }); + getViewer().clock.startTime = start.clone(); + getViewer().clock.currentTime = start.clone(); + getViewer().clock.clockRange = Cesium.ClockRange.CLAMPED; + getViewer().clock.shouldAnimate = false; + }; + + const updatePeoplePoint = async (point) => { + if (getViewer().clock.shouldAnimate === false) { + getViewer().clock.shouldAnimate = true; + } + if (point.icon_type !== point.lastIconType) { + const entity = getViewer().entities.getById(point.id); + if (!entity) + return; + entity.billboard.image = ( + await getBillboard({ + image: peopleImg[point.icon_type], + name: point.name || point.id, + }) + ).image; + point.lastIconType = point.icon_type; + } + const position = Cesium.Cartesian3.fromDegrees(point.x, point.y, 0); + const nextTime = Cesium.JulianDate.addSeconds( + point.lastTime, + 10, + new Cesium.JulianDate(), + ); + point.property.addSample(nextTime, position); + point.lastTime = nextTime; + }; + + const removePeoplePoint = (id) => { + getViewer().entities.removeById(id); + peopleId.current = peopleId.current.filter(item => item !== id); + }; + + const removePeoplePointAll = () => { + peopleId.current.forEach((id) => { + getViewer().entities.removeById(id); + }); + peopleId.current = []; + }; + return { flyTo, returnCurrentCenterPoint, @@ -407,5 +490,9 @@ export default function useMapMethods(viewerRef, request) { removeWall, addMarkPoint, removeMarkPoint, + addPeoplePoint, + updatePeoplePoint, + removePeoplePoint, + removePeoplePointAll, }; } diff --git a/src/pages/Container/Map/js/usePeoplePosition.js b/src/pages/Container/Map/js/usePeoplePosition.js new file mode 100644 index 0000000..31de788 --- /dev/null +++ b/src/pages/Container/Map/js/usePeoplePosition.js @@ -0,0 +1,63 @@ +import { useWebSocket } from "ahooks"; +import { useRef } from "react"; +import edgeQHD from "./edge/qhd.js"; +import { filterNull, isPointWithinTheArea } from "./utils"; + +export default function usePeoplePosition(mapMethods, currentBranchOffice) { + const markType = "peoplePosition"; + const points = useRef([]); + + // const wsProtocol = window.location.protocol === "https:" ? "wss:" : "ws:"; + // const wsUrl = `${wsProtocol}//${process.env.app.API_HOST.replace(/^https?:\/\//, "")}/personnelPosition/ws/location?corpinfoId=${currentBranchOffice}`; + const wsUrl = `ws://192.168.10.14/personnelPosition/ws/location?corpinfoId=${currentBranchOffice}`; + + const onMessage = async (message) => { + const data = JSON.parse(message.data); + const peopleList = filterNull([data]); + for (let i = 0; i < peopleList.length; i++) { + const item = peopleList[i]; + if (!item) + continue; + const index = points.current.findIndex( + item1 => item1.id.toString() === (item.terminalNo || item.staffNo).toString(), + ); + const x = item.lon; + const y = item.lat; + const pointColor = isPointWithinTheArea(edgeQHD(), x, y); + if (index !== -1) { + points.current[index].x = x; + points.current[index].y = y; + points.current[index].icon_type = pointColor; + mapMethods.current && (await mapMethods.current.updatePeoplePoint(points.current[index])); + } + else { + const perLoc = { + ...item, + id: item.terminalNo || item.staffNo, + name: item.staffName, + x, + y, + icon_type: pointColor, + }; + points.current.push(perLoc); + mapMethods.current && (await mapMethods.current.addPeoplePoint(perLoc, { markType, isShowModal: false })); + } + } + }; + + const { connect, disconnect } = useWebSocket( + wsUrl, + { + manual: true, + onClose: () => { + mapMethods.current && mapMethods.current.removePeoplePointAll(); + points.current = []; + }, + onMessage: (message) => { + onMessage(message); + }, + }, + ); + + return { connect, disconnect }; +} diff --git a/src/pages/Container/Map/js/pointClickEvent.js b/src/pages/Container/Map/js/usePointClickEvent.js similarity index 100% rename from src/pages/Container/Map/js/pointClickEvent.js rename to src/pages/Container/Map/js/usePointClickEvent.js diff --git a/src/pages/Container/Map/js/utils.js b/src/pages/Container/Map/js/utils.js index 0d10164..0653a00 100644 --- a/src/pages/Container/Map/js/utils.js +++ b/src/pages/Container/Map/js/utils.js @@ -1,6 +1,6 @@ // 过滤掉无经纬度的数据 export const filterNull = (arr = []) => { - return arr.filter(item => (item.longitude || item.lng) && (item.latitude || item.lat)); + return arr.filter(item => (item.longitude || item.lng || item.lon) && (item.latitude || item.lat)); }; // 格式化多边形 @@ -245,3 +245,50 @@ export function textFormatter(value, maxLength = 4) { return value; } } + +const isPointInPolygon = (polygon, lng, lat) => { + const numberOfPoints = polygon.length; + const polygonLats = []; + const polygonLngs = []; + for (let i = 0; i < numberOfPoints; i++) { + polygonLats.push(polygon[i].y); + polygonLngs.push(polygon[i].x); + } + let polygonContainsPoint = false; + for ( + let node = 0, altNode = numberOfPoints - 1; + node < numberOfPoints; + altNode = node++ + ) { + if ( + (polygonLngs[node] > lng) !== (polygonLngs[altNode] > lng) + && lat + < ((polygonLats[altNode] - polygonLats[node]) + * (lng - polygonLngs[node])) + / (polygonLngs[altNode] - polygonLngs[node]) + + polygonLats[node] + ) { + polygonContainsPoint = !polygonContainsPoint; + } + } + return polygonContainsPoint; +}; +const forEachIsPointInPolygon = (polygonList = [], lng, lat) => { + return polygonList.some((item) => { + return isPointInPolygon(item.position, lng, lat); + }); +}; +export const isPointWithinTheArea = (pointBox = {}, x, y) => { + if (forEachIsPointInPolygon(pointBox.redList, x, y)) { + return "red"; + } + else if (forEachIsPointInPolygon(pointBox.orangeList, x, y)) { + return "orange"; + } + else if (forEachIsPointInPolygon(pointBox.yellowList, x, y)) { + return "yellow"; + } + else { + return "blue"; + } +};