From 00468b053b603c0d27790cee1c9c9472458afbbd Mon Sep 17 00:00:00 2001 From: Zzc <1373857752@qq.com> Date: Tue, 25 Nov 2025 19:21:02 +0800 Subject: [PATCH] =?UTF-8?q?feat(3d-situational-awareness):=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=AF=B9=E5=88=86=E7=BA=A7=E5=BA=94=E6=80=A5=E7=82=B9?= =?UTF-8?q?=E5=92=8C=E5=A1=8C=E9=99=B7=E8=BE=B9=E7=95=8C=E7=9A=84=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 为城市、区域和其他应急点添加新图标 - 更新地图点击处理器以显示分级应急点详情 - 实现塌陷边界绘制,左右地图使用实线和虚线 - 修改标记添加功能,按级别处理应急点(城市、区域、其他) --- .../assets/images/其他应急点.png | Bin 0 -> 1604 bytes .../assets/images/区县应急点.png | Bin 0 -> 1698 bytes .../assets/images/市应急点.png | Bin 0 -> 2117 bytes .../composables/useMapClickHandler.js | 22 ++ .../composables/useMapMarkers.js | 233 +++++++++++++++++- 5 files changed, 245 insertions(+), 10 deletions(-) create mode 100644 packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/其他应急点.png create mode 100644 packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/区县应急点.png create mode 100644 packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/市应急点.png diff --git a/packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/其他应急点.png b/packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/其他应急点.png new file mode 100644 index 0000000000000000000000000000000000000000..6eb7d45d42c89bb6e339a8e12f27e6345941b50b GIT binary patch literal 1604 zcmV-K2D|x*P)Px){z*hZR7gveS9?%YWfcFNy?gIn7Dy0-KokXE_!vQ{F;W}TQpQXhN11BEe4wH^ zj)^sz`54E_UXGInqroI)MUGSEjFehhj)ta!Z&W}Lkif^H>@ItE_uenR#RYb`Jp5+% zpZk5^`JLZ6=R3c%gf1?|7y%dzU?_l|0L%dF0IC680C0(jSXaz(Lme*0SU&(u0nDhh zsS(%iYp8W-P*gw`fC!TT{ks{^D^REfup7V@A}a03XuF_{v2Xxu8(b`X_jRXOP~}2R zWBWuR0|+V6B4+fJT)`sk0I;5j>h!>MK^bGCG=@F-Uo_R^L%>Z2mwAY5n9}BAVL_$`~7Fak8S+!&brW_Qf0$V!)=P0EEbf4jKJW zu3+2cwhr@4W+RY4E=UcPD3OTHd)#J><$P75%>KU2=|h7v%pGm+6wvF$QpWA@qLGD6HIuqr|7Y{@{}Ey>osI2oAH!cpS8oykb1-h ze>?nsm`vC^A;<#YNe())?16e})=}QkS{5&weG`J3b2#mg6?YVdS9*(B5-%gbNKiG_ zCdb(&4t!Up&vxe+Gvb~Qk~nDE@71oI8;Tu1pkpEge3Zo7Yt#DAuHm+W!RBVjzuuI) z(|1&)_7$;su&MdniQ8^0KiR08{|^#OnAlUC#X(o>DpNkmD)B9XX}v{c4r?*i+KNTd zFy)ZV^C>_84o(Vg-Y$Ef!ar)>&5S`3-iVXm<)AC`N|g`&pUO*7MyyE;=n~VJu@Wv? zR8ROTts3@J=!f^w(^*oIU^Qrd%H>~7{?)-j_gA^F zab!~(eyMQcw`v!%lba$`bk~g~g-vAmBP*B~qy-u&+}j+^y#0?YvG`uwKDszw!fUaz zZZ&#AmkyTkYo!ZU>Q$6BXqenf#PCo7Mgy8b6S^C)_1VB8A{yZZU38?zy><1OMqMf6 z&mw(*43p7!+Y35xfP|c@PE^}9)HZ4u5oSbkgb`fWy-YWZ2w>wPjZ27Vn-?@tW2kuR zs4c9#9o66+B_-O3#4saz$OJ_L4%fI)d{@Pe(M{p>53e_;yeMC%YF80!mQ z^+k(1d)Wy)*;|c6+`y{gGE$ literal 0 HcmV?d00001 diff --git a/packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/区县应急点.png b/packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/区县应急点.png new file mode 100644 index 0000000000000000000000000000000000000000..a3e7adcc583edcbc721bf69338b59d98cbdb9005 GIT binary patch literal 1698 zcmV;T23`4yP)Px*TuDShR7gvemwQlDbri?H=ic4D`(Q1^SBiyYITjXVIZFAM5%X0|nUv=EB1J_^ zYwTg=q*jiZlh#NYriP7WnL18MYT#(5nW^}G;-H{{0;0jPd++YOr+$lzEbOv){=C0) z&gXZ|@BGg1TtYL2nF+wd0OA330AL4D1K=`%;{Z+)5jV%3aMYwQb7uh40i@{V#chp} zGcaym1-u@>Y=v}JTS)hGf!wO&RRHS&d_hD7O*stjK4f>*MD4G2W-UJlTzMs| zFN$stOX3h%dX4as&A9@=Tq3#_${-|^nR|kb4eFln+pD{>0r$U=5^{Up)&ff3aZsKb zc?BfBL`3@<8aIM6^ULh6TH{_n+u}R>SH$#(+l}d=UTjPGNF$qb3=#cQUoXfhGe5=d zsytWLM8zm8Y<_fMG^N&^;7D7clFiwli1q~3>Y&Vg4-EaVD|<#8{rvvWZfq@Jic0`F zTY=RY7*`8mlr~v2kRRv)$Jiy;Ajt_tR3aSLhptq2ew(W1E^7p&yV^o|W-83xl0lLj zw62$3fV%xF_)hH#n;9i}3Y321RuR!_bx>yR#;(fzs?UeXP{q}|EmCYe?4uV!azr=T1T)WwO~jzS62iXSX1V~{9rG5PyccIyKIK(fhS>9UV(AtjQ=}1 z?uI$OKUj04dhu{@Re9qhii&~r-JD7Qtp&8ZURrR#wRBXlqOAp-v$n#xdLG^rJ0P{} z2(mfBJ`Ix9307Uu4(C8>*#TTx0{f_ietXZhOlZ5;gpAgau@-W>&QA#F813+H*`A;0 z1Sy)j_JMuWXV6Q|LN6}@S6qVc{C?QSE`j&xc1SVzLfgLqQtLPvrRQKDG2d_RJGT!t z*`jMU7VGdiup|r~E1++wyT4ngZd)3pW$rNyw&&mRLwyB*LoY3W6cY<6x;@x+1IEo# z7-bhB$36`G(g|3SM#B71l3%Y;)^2%L24+C%J^F0{ou%$vJzvdT9vtaogJ4gY>vy7V z&-6zGvjS*tP;>{7;_zP+Irb5FPws@0Gy+D=O&AqL@a_|Rzp*IElcDq*|DJ$O)c)C& z<=MO-_^Pz)jHryYA&uGN0%Q}6f3Ly4?tK{L7h$^p35cdoW-CNN>P1IkR1^mn=JW5u z(&NQR0{X1??A~A8Yu;!Ca7_OZvWPH@cu((!cn}<^nIN+Q!&M2RvIM4B@$3Rx{uX#P z%&W7ujae*?;5h+}Vbyi5>f>YyY&0mQzI9a@iYuVrLt9{fwKhxI{*CY+&VeKCo7$o( zJcyc=>9wXL!TCY1L5ibIpgA0JeKR>xzmVU^w=(E;C{H)IPPeoIQ0ve)pdHu@{qiY) zFE)374)T2oAX%=1%5jNsOjw>zM2`oc>E07Nmb!nK74j()m8m380$FT9n+iacY55javTv=*MDVFeZ?nM)?`gU!?O)r zNw*fPuY3$kw*l}K9fMwY2uk0v{-@8id_0WuBG}Vbz|=ARH6mK&Ki>KdnK?(@w|=nt z>!L`U;C0yy>kIGsXCxtFa1&QaFFpq4*_lv!ru+tAXkc1w2z3J3rS4pnsOElsXJ7!L zbxQ5KLff+z@KpQjKhstPy^H6w{BaFh3VUXpv$CxGg@V>ql)u!=_T=zzTd zUTioOhMNX006ypH>yy>o<&t)23&HS3hRbGH5(cp{Al;y-mSO~%NknQx!zQOaW=;g~ zDZ6g;_a50wp1dpy897O?^h<@(bGSi{=-&anPecd9?Xp=TCNp>XzrlQ<7at$*T0M=R z)gNgH)|Y0(k~nlbfOH}Xedp@!pjps>J~LJ%G6PD|NHJOrBBI)l z5#&yxLVuZlAwSKPJ%cPgQ(zsKaTGuwBDxs~7PfjL8Q%JPTVa$Hrb?~iia?Y^MB#sO sLO8smNb99p0b%707*qoM6N<$g7=XqzyJUM literal 0 HcmV?d00001 diff --git a/packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/市应急点.png b/packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/市应急点.png new file mode 100644 index 0000000000000000000000000000000000000000..5de08c3cffc5a659bfbc5860c13d4d5014c810ef GIT binary patch literal 2117 zcmV-L2)g%)P)Px+|4BqaR9Hu~n0a(m^%cjz_q{iJh8>Qy2$6j$0mRk<$^k)(AV?2IsVt>HB(kW; zfv`jfYY_B6u{8wB4keM=g25HrUk7|ij!m0CwT_5J?^CS+7jXa!e#Y5^3b zGZ9@5y{`zgzxYoZx~qTN5jEN6U$%#(R~HEPOAYE6w)DILXvfbXkbMZ+zrU-}VytiU zXZt%N4iHg~N) zV(tY|^@&Ie0lgAD_5BWSVoF5M#H~%M1jD)xzIz{1om!@P2Gpn-(0>p`JMwU@nhzzR zRevJ-A_SCGoR%?I-Ii^dJI+s1O~VvCeIDNNbK%~-3gmQ{&KS%&4ez))QGu)jd$WD| z*sVnLIx({Z=KR9GiM6@lUL{45z^*^fDoNbyw@@@>Qh6CQ04NF|Jy?q^X$WjX2ZZH3 z6Xr%ubgEMm?p>?yfT*4TYOh_ocFI$6qEd7A>0@CX*xPtwO#|oMDF@{FLo)2iiICfh z&A()j+X-?x!_VsWy(nI|BC3~MnM)x*)hIy#y%yMaB+EDbBU1%e)-uTPVoNI-!Lzw2 zPRj^C>lc3j{j5I7VK?5%?OVbzHL;v6?b0>dA>oy+{o)|mpi zzu8bOKSWOWQa^?xb)q5fo%RuIV+KQR-Wb7u9fOv86|UtEehx15K)ZY$-Z3+yddT+f zNZ5Yg?_B|u;$QRGJby-Jm4S-WRwC~2%MJO$zKL)wd=E;;Hc+=`Be3@fY(x7S1u}T> z7`WhWRFKd|+t?wnjT)39fRg=Nb}owKp-LgkIgLs{X_KLJXbp8+HvAb`287fy9+qBR zp*))aYETzc!v(%q1pQ_nw4)~x`1%m^OV`4%Wj&Or?)i3Q@$8ZnR~%)N+Q^{@K*1v? z5ZLoAAZpXie7Fy80a+BooSuKjfVGVn2(nsA-rdSa(SWzY)7j^|4Qrq0hYAn95Ik{i zuXk+8uU&DJ{p}4y1^1wx%Y~&|=W-#Vy0yT!^1*5lzDWyFD8YboUT zMkPSE@1m&hgXDK+%oSnpDS%w;SML<|9%+H7DJH|2o(kn@^Zl!6%uF~YkAmE$nV}gx z`5$=SeBS`lf4mL-MjnDWXP{ea#lNlv~ij#lQQD(#1M?It{fCc?RH5tPy}n&nX7U=Dnf7lCTJ5w~N7k8IW_iRgCN zBg~xc->@yo|Ch}XfkGdQ2Ca8j$Q|31G-!%q{52xvf!zn7oj3>inP0%U{C$utLCd{@ z;-%~1SU3q%O*dFoA^I-;{AJiC41;a>t1F3Utgv4er~!i7*`krt>gpH59c4_oXadTM zT}3!Rc3W7CJwA9-mO?vp98&Wph+F@`Z78zng^Yt<#TIsie*W^hqA@cGe)W-HLdsIp zC*hbq0dni6MlSj0eFDCI3$WV|w`v|sEuRwSw6!65vs1^K;K7`c-YJVo6uHMTB!bkm zG4xz<><1u8a4w$0%Ja{xA)+y5=P&~j<#oHd`#|5~1?fN__*j_2Ml1^KDdR*{{t|#V z29=v2(m_!)Gi$Z)&JXq`FCo5NwGA>BIn}Odct%cW_32NyB!48L(p!oLnz7FIGxR(6 z=c*Z*lDa*cpqrmYVu652GrA$i5(wKEg(hdPDBrVby6*$QmC2$zVdJW{8#?v8%xSd+vZ}| z_K@8sJaaT=d`twY4O9vxj;z`K4cj^gKHmq|Ul# { + if (!viewer) { + console.warn('[useMapMarkers] drawCollapseBoundary: viewer 为空') + return null + } + + if (!Array.isArray(collapseBoundaryData) || collapseBoundaryData.length === 0) { + console.warn('[useMapMarkers] drawCollapseBoundary: 配置数据为空') + return null + } + + // 清除旧的边界线(如果存在) + if (collapseBoundaryEntity.value) { + viewer.entities.remove(collapseBoundaryEntity.value) + collapseBoundaryEntity.value = null + } + + // 转换坐标点 + const positions = collapseBoundaryData.map(point => + new Cesium.Cartesian3(point.x, point.y, point.z) + ) + + // 闭合线条(连接最后一个点到第一个点) + positions.push(positions[0]) + + console.log('[useMapMarkers] 右侧坍塌边界点位数量:', positions.length) + + // 创建蓝色实线边界 + const boundaryEntity = viewer.entities.add({ + polyline: { + positions: positions, + width: 4, // 增加线宽,更明显 + material: Cesium.Color.fromCssColorString('#1CA1FF').withAlpha(1.0), // 纯蓝色实线 + clampToGround: true, + classificationType: Cesium.ClassificationType.BOTH, // 同时分类到地形和3D Tiles + zIndex: 1 // 提高层级 + }, + properties: new Cesium.PropertyBag({ + type: 'collapseBoundary', + name: '坍塌边界(右侧实线)' + }), + show: true // 明确设置为显示 + }) + + collapseBoundaryEntity.value = boundaryEntity + console.log('[useMapMarkers] 右侧坍塌边界蓝色实线绘制完成, entityId:', boundaryEntity.id) + + // 强制渲染场景 + viewer.scene.requestRender() + + return boundaryEntity + } + + /** + * 绘制坍塌边界蓝色虚线(左侧地图) + * 在左侧地图上显示灾前位置的虚线轮廓 + * @param {HTMLElement} leftContainer - 左侧地图容器元素 + * @returns {Cesium.Entity | null} 返回创建的边界线实体 + */ + const drawCollapseBoundaryLeft = (leftContainer) => { + if (!leftContainer) { + console.warn('[useMapMarkers] drawCollapseBoundaryLeft: leftContainer 为空') + return null + } + + // 获取左侧 viewer(假设已经创建) + const leftViewer = leftContainer._cesiumViewer + if (!leftViewer) { + console.warn('[useMapMarkers] drawCollapseBoundaryLeft: 左侧 viewer 未创建') + return null + } + + if (!Array.isArray(collapseBoundaryData) || collapseBoundaryData.length === 0) { + console.warn('[useMapMarkers] drawCollapseBoundaryLeft: 配置数据为空') + return null + } + + // 清除旧的边界线(如果存在) + if (collapseBoundaryLeftEntity.value) { + leftViewer.entities.remove(collapseBoundaryLeftEntity.value) + collapseBoundaryLeftEntity.value = null + } + + // 转换坐标点 + const positions = collapseBoundaryData.map(point => + new Cesium.Cartesian3(point.x, point.y, point.z) + ) + + // 闭合线条(连接最后一个点到第一个点) + positions.push(positions[0]) + + console.log('[useMapMarkers] 左侧坍塌边界点位数量:', positions.length) + + // 创建蓝色虚线边界 + const boundaryEntity = leftViewer.entities.add({ + polyline: { + positions: positions, + width: 4, + material: new Cesium.PolylineDashMaterialProperty({ + color: Cesium.Color.fromCssColorString('#1CA1FF').withAlpha(1.0), // 蓝色 + dashLength: 16.0, // 虚线段长度 + dashPattern: 255.0 // 虚线模式 + }), + clampToGround: true, + classificationType: Cesium.ClassificationType.BOTH, + zIndex: 1 + }, + properties: new Cesium.PropertyBag({ + type: 'collapseBoundaryLeft', + name: '坍塌边界(左侧虚线)' + }), + show: true + }) + + collapseBoundaryLeftEntity.value = boundaryEntity + console.log('[useMapMarkers] 左侧坍塌边界蓝色虚线绘制完成, entityId:', boundaryEntity.id) + + // 强制渲染场景 + leftViewer.scene.requestRender() + + return boundaryEntity + } + + /** + * 清除坍塌边界线 + * @param {Cesium.Viewer} viewer - 右侧 viewer + * @param {HTMLElement} leftContainer - 左侧地图容器(可选) + */ + const clearCollapseBoundary = (viewer, leftContainer = null) => { + // 清除右侧边界线 + if (viewer && collapseBoundaryEntity.value) { + viewer.entities.remove(collapseBoundaryEntity.value) + collapseBoundaryEntity.value = null + console.log('[useMapMarkers] 右侧坍塌边界线已清除') + } + + // 清除左侧边界线 + if (leftContainer && collapseBoundaryLeftEntity.value) { + const leftViewer = leftContainer._cesiumViewer + if (leftViewer) { + leftViewer.entities.remove(collapseBoundaryLeftEntity.value) + collapseBoundaryLeftEntity.value = null + console.log('[useMapMarkers] 左侧坍塌边界线已清除') + } + } + } + + /** + * 显示坍塌边界线 + */ + const showCollapseBoundary = () => { + if (collapseBoundaryEntity.value) { + collapseBoundaryEntity.value.show = true + console.log('[useMapMarkers] 显示右侧坍塌边界线') + } + if (collapseBoundaryLeftEntity.value) { + collapseBoundaryLeftEntity.value.show = true + console.log('[useMapMarkers] 显示左侧坍塌边界线') + } + } + + /** + * 隐藏坍塌边界线 + */ + const hideCollapseBoundary = () => { + if (collapseBoundaryEntity.value) { + collapseBoundaryEntity.value.show = false + console.log('[useMapMarkers] 隐藏右侧坍塌边界线') + } + if (collapseBoundaryLeftEntity.value) { + collapseBoundaryLeftEntity.value.show = false + console.log('[useMapMarkers] 隐藏左侧坍塌边界线') + } + } + /** * 绘制塌陷区域多边形 * 这个函数不涉及高度采样,直接使用配置中的绝对坐标 @@ -603,7 +791,7 @@ export function useMapMarkers() { * @param {string} reserveData[].gl1Qxmc - 区县名称 * @param {string} reserveData[].gl1Rysl - 人员数量 * @param {string} reserveData[].gl1Zdmj - 占地面积 - * @param {string} reserveData[].gl1Lx - 类型 (2=储备中心, 3=预置点) + * @param {string} reserveData[].gl1Lx - 级别 (1=市级, 2=区县级, 3=其他) * @param {Object} options - 配置选项 * @param {number} [options.heightOffset=10] - 相对地面的高度偏移(米) * @returns {Promise} @@ -641,27 +829,45 @@ export function useMapMarkers() { false ) - // 根据类型选择图标和类型标识 - // gl1Lx: 2=储备中心, 3=预置点 - const itemType = String(item.gl1Lx).trim() - const isReserveCenter = itemType === '2' - const icon = isReserveCenter ? reserveCenterIcon : emergencyBaseIcon - const type = isReserveCenter ? 'reserveCenter' : 'presetPoint' + // 根据级别选择图标和类型标识 + // gl1Lx: "1市级", "2区县级", "3其他" 或者可能只是 "1", "2", "3" + const levelString = String(item.gl1Lx || '').trim() + let icon = otherEmergencyIcon // 默认使用其他应急点图标 + let type = 'other' + let levelName = '其他' + + // 判断级别(兼容 "1市级" 和 "1" 两种格式) + if (levelString.startsWith('1') || levelString === '1') { + icon = cityEmergencyIcon + type = 'city' + levelName = '市级' + } else if (levelString.startsWith('2') || levelString === '2') { + icon = districtEmergencyIcon + type = 'district' + levelName = '区县级' + } else if (levelString.startsWith('3') || levelString === '3') { + icon = otherEmergencyIcon + type = 'other' + levelName = '其他' + } + + console.log(`[useMapMarkers] 添加标记: ${item.gl1Yjllmc}, 级别: ${levelString} (${levelName})`) const entity = viewer.entities.add({ position: result.position, billboard: { image: icon, - width: 48, - height: 48, + width: 29, + height: 32, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, heightReference: resolveBillboardHeightReference(result.samplingSucceeded), disableDepthTestDistance: Number.POSITIVE_INFINITY }, properties: { type, + level: levelName, id: item.gl1Id, - name: item.gl1Yjllmc || (isReserveCenter ? '储备中心' : '预置点'), + name: item.gl1Yjllmc || `${levelName}应急点`, district: item.gl1Qxmc || '-', personnelCount: item.gl1Rysl || '0', area: item.gl1Zdmj || '-' @@ -771,12 +977,19 @@ export function useMapMarkers() { markerEntities, emergencyResourceEntities, reserveCenterEntities, + collapseBoundaryEntity, + collapseBoundaryLeftEntity, initializeMarkers, clearMarkers, setMarkersSplitDirection, hideMarkers, showMarkers, drawCollapseArea, + drawCollapseBoundary, + drawCollapseBoundaryLeft, + clearCollapseBoundary, + showCollapseBoundary, + hideCollapseBoundary, addFixedMarkers, addRandomMarkers, addEmergencyResourceMarkers,