三维修改
This commit is contained in:
parent
90bd2bac1f
commit
8d17118b40
@ -32,8 +32,10 @@ import { useMapOrchestrator } from '@/modules/map/application/map-orchestrator';
|
|||||||
import { MapClass } from './map.class';
|
import { MapClass } from './map.class';
|
||||||
import { getQgcRvcd } from '@/api/map';
|
import { getQgcRvcd } from '@/api/map';
|
||||||
import { servers } from './mapurlManage';
|
import { servers } from './mapurlManage';
|
||||||
|
import { useUiStore } from '@/store/modules/ui';
|
||||||
|
|
||||||
const mapOrchestrator = useMapOrchestrator();
|
const mapOrchestrator = useMapOrchestrator();
|
||||||
|
const uiStore = useUiStore();
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const mapClass = MapClass.getInstance();
|
const mapClass = MapClass.getInstance();
|
||||||
@ -82,7 +84,11 @@ const init = async () => {
|
|||||||
const handleMapController = async (e: any, mapType: any) => {
|
const handleMapController = async (e: any, mapType: any) => {
|
||||||
switch (e) {
|
switch (e) {
|
||||||
case 'dim':
|
case 'dim':
|
||||||
await mapClass.switchView(mapType);
|
await mapOrchestrator.switchMapType(mapType, {
|
||||||
|
popupContainer: popupRef.value,
|
||||||
|
getIsHydroMenu: () => isShuiDianKaiFaMenu.value
|
||||||
|
});
|
||||||
|
uiStore.markMapSwitchCompleted();
|
||||||
break;
|
break;
|
||||||
case 4: // 梯级流域显示
|
case 4: // 梯级流域显示
|
||||||
tlyLayerVisible.value = !tlyLayerVisible.value;
|
tlyLayerVisible.value = !tlyLayerVisible.value;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -272,4 +272,8 @@ export class MapClass implements MapClassInterface {
|
|||||||
flyTopanto(position: number[], zoom: number): void {
|
flyTopanto(position: number[], zoom: number): void {
|
||||||
this.service.flyTopanto(position, zoom);
|
this.service.flyTopanto(position, zoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getCurrentZoom(): number | undefined {
|
||||||
|
return this.service.getCurrentZoom();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
6
frontend/src/components/gis/map.d.ts
vendored
6
frontend/src/components/gis/map.d.ts
vendored
@ -124,6 +124,12 @@ export interface MapInterface {
|
|||||||
fitBounds(bbox, bearing): void;
|
fitBounds(bbox, bearing): void;
|
||||||
|
|
||||||
flyTopanto(positon, zoom): void;
|
flyTopanto(positon, zoom): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前地图缩放级别语义
|
||||||
|
* 2D 直接返回原生 zoom,3D 由相机高度换算后返回
|
||||||
|
*/
|
||||||
|
getCurrentZoom(): number | undefined;
|
||||||
// /**
|
// /**
|
||||||
// * 加载倾斜摄影数据
|
// * 加载倾斜摄影数据
|
||||||
// * @param HH3DUrlArray
|
// * @param HH3DUrlArray
|
||||||
|
|||||||
@ -49,7 +49,7 @@ const MIN_ZOOM = 4.23;
|
|||||||
const MAX_ZOOM = 22;
|
const MAX_ZOOM = 22;
|
||||||
const INITIAL_ZOOM = 4.5;
|
const INITIAL_ZOOM = 4.5;
|
||||||
const BATCH_POPUP_MODE_ZOOM = 15;
|
const BATCH_POPUP_MODE_ZOOM = 15;
|
||||||
const FULL_DISPLAY_NO_COLLISION_ZOOM = 15;
|
const FULL_DISPLAY_NO_COLLISION_ZOOM = Number.POSITIVE_INFINITY;
|
||||||
|
|
||||||
// 定义边界 [minX, minY, maxX, maxY] (Web Mercator 坐标)
|
// 定义边界 [minX, minY, maxX, maxY] (Web Mercator 坐标)
|
||||||
const BOUNDS_SW = [26.5, -9.99999999999929];
|
const BOUNDS_SW = [26.5, -9.99999999999929];
|
||||||
@ -80,6 +80,8 @@ export class MapOl implements MapInterface {
|
|||||||
private regionMaskManager: RegionMaskManager;
|
private regionMaskManager: RegionMaskManager;
|
||||||
private isBatchPopupMode = false;
|
private isBatchPopupMode = false;
|
||||||
private batchPopupRefreshFrameId: number | null = null;
|
private batchPopupRefreshFrameId: number | null = null;
|
||||||
|
private batchPopupPendingRebuild = false;
|
||||||
|
private batchPopupPostRenderListenerKey: any = null;
|
||||||
private pointLayerStyleRefreshFrameId: number | null = null;
|
private pointLayerStyleRefreshFrameId: number | null = null;
|
||||||
private labelVisibilityRefreshFrameId: number | null = null;
|
private labelVisibilityRefreshFrameId: number | null = null;
|
||||||
private labelVisibilityDebounceTimerId: number | null = null;
|
private labelVisibilityDebounceTimerId: number | null = null;
|
||||||
@ -200,13 +202,14 @@ export class MapOl implements MapInterface {
|
|||||||
|
|
||||||
this.map.on('pointerdrag', () => {
|
this.map.on('pointerdrag', () => {
|
||||||
if (this.isBatchPopupMode) {
|
if (this.isBatchPopupMode) {
|
||||||
this.requestUpdateBatchPopups();
|
this.ensureBatchPopupPostRenderSync();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.map.on('moveend', () => {
|
this.map.on('moveend', () => {
|
||||||
|
this.clearBatchPopupPostRenderSync();
|
||||||
this.requestRefreshPointLabelVisibility(false, 60);
|
this.requestRefreshPointLabelVisibility(false, 60);
|
||||||
if (this.isBatchPopupMode) {
|
if (this.isBatchPopupMode) {
|
||||||
this.requestUpdateBatchPopups();
|
this.requestUpdateBatchPopups(false, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -291,8 +294,9 @@ export class MapOl implements MapInterface {
|
|||||||
*/
|
*/
|
||||||
private enableBatchPopupMode() {
|
private enableBatchPopupMode() {
|
||||||
this.isBatchPopupMode = true;
|
this.isBatchPopupMode = true;
|
||||||
|
this.clearBatchPopupPostRenderSync();
|
||||||
this.popupManager.clearBatchPopups();
|
this.popupManager.clearBatchPopups();
|
||||||
this.requestUpdateBatchPopups(true);
|
this.requestUpdateBatchPopups(true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -300,6 +304,8 @@ export class MapOl implements MapInterface {
|
|||||||
*/
|
*/
|
||||||
private disableBatchPopupMode() {
|
private disableBatchPopupMode() {
|
||||||
this.isBatchPopupMode = false;
|
this.isBatchPopupMode = false;
|
||||||
|
this.batchPopupPendingRebuild = false;
|
||||||
|
this.clearBatchPopupPostRenderSync();
|
||||||
if (this.batchPopupRefreshFrameId !== null) {
|
if (this.batchPopupRefreshFrameId !== null) {
|
||||||
cancelAnimationFrame(this.batchPopupRefreshFrameId);
|
cancelAnimationFrame(this.batchPopupRefreshFrameId);
|
||||||
this.batchPopupRefreshFrameId = null;
|
this.batchPopupRefreshFrameId = null;
|
||||||
@ -314,11 +320,40 @@ export class MapOl implements MapInterface {
|
|||||||
private updateBatchPopups() {
|
private updateBatchPopups() {
|
||||||
const features = this.pointLayerManager.getFeaturesInViewport();
|
const features = this.pointLayerManager.getFeaturesInViewport();
|
||||||
// 传入样式检查器,过滤掉 declutter/距离过滤等隐藏的锚点
|
// 传入样式检查器,过滤掉 declutter/距离过滤等隐藏的锚点
|
||||||
this.popupManager.showPopupsForFeatures(features, feature => {
|
this.popupManager.showPopupsForFeatures(
|
||||||
const style = this.createPointStyle(feature);
|
features,
|
||||||
return style !== null;
|
feature => {
|
||||||
|
const style = this.createPointStyle(feature);
|
||||||
|
return style !== null;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rebuild: this.batchPopupPendingRebuild
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ensureBatchPopupPostRenderSync() {
|
||||||
|
if (!this.map || this.batchPopupPostRenderListenerKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.batchPopupPostRenderListenerKey = this.map.on('postrender', () => {
|
||||||
|
if (!this.isBatchPopupMode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.popupManager.updateBatchPopupPositions(feature => {
|
||||||
|
const style = this.createPointStyle(feature);
|
||||||
|
return style !== null;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private clearBatchPopupPostRenderSync() {
|
||||||
|
if (this.batchPopupPostRenderListenerKey) {
|
||||||
|
unByKey(this.batchPopupPostRenderListenerKey);
|
||||||
|
this.batchPopupPostRenderListenerKey = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 创建点样式 (模拟 Leaflet 的 DivIcon 效果,支持随缩放动态调整大小)
|
* 创建点样式 (模拟 Leaflet 的 DivIcon 效果,支持随缩放动态调整大小)
|
||||||
*/
|
*/
|
||||||
@ -350,6 +385,7 @@ export class MapOl implements MapInterface {
|
|||||||
|
|
||||||
const dynamicScale = this.getDynamicPointScale(currentZoom);
|
const dynamicScale = this.getDynamicPointScale(currentZoom);
|
||||||
const fontSize = this.getPointFontSize(dynamicScale);
|
const fontSize = this.getPointFontSize(dynamicScale);
|
||||||
|
const engPriority = this.getFeatureEngRenderPriority(feature);
|
||||||
const formattedLabelText = this.formatPointLabelText(labelText);
|
const formattedLabelText = this.formatPointLabelText(labelText);
|
||||||
const labelLineCount = formattedLabelText
|
const labelLineCount = formattedLabelText
|
||||||
? formattedLabelText.split('\n').length
|
? formattedLabelText.split('\n').length
|
||||||
@ -363,7 +399,10 @@ export class MapOl implements MapInterface {
|
|||||||
feature.get('_labelCollisionVisible') === true;
|
feature.get('_labelCollisionVisible') === true;
|
||||||
const finalIconVisible = iconTargetVisible && iconCollisionVisible;
|
const finalIconVisible = iconTargetVisible && iconCollisionVisible;
|
||||||
const labelTargetVisible =
|
const labelTargetVisible =
|
||||||
finalIconVisible && !!formattedLabelText && labelCollisionVisible;
|
!this.isBatchPopupMode &&
|
||||||
|
finalIconVisible &&
|
||||||
|
!!formattedLabelText &&
|
||||||
|
labelCollisionVisible;
|
||||||
|
|
||||||
if (!finalIconVisible) {
|
if (!finalIconVisible) {
|
||||||
return null;
|
return null;
|
||||||
@ -373,6 +412,7 @@ export class MapOl implements MapInterface {
|
|||||||
iconUrl,
|
iconUrl,
|
||||||
dynamicScale.toFixed(2),
|
dynamicScale.toFixed(2),
|
||||||
fontSize,
|
fontSize,
|
||||||
|
engPriority,
|
||||||
labelOffsetY,
|
labelOffsetY,
|
||||||
labelTargetVisible ? formattedLabelText : '',
|
labelTargetVisible ? formattedLabelText : '',
|
||||||
labelTargetVisible ? 1 : 0
|
labelTargetVisible ? 1 : 0
|
||||||
@ -384,6 +424,7 @@ export class MapOl implements MapInterface {
|
|||||||
|
|
||||||
const styles: Style[] = [
|
const styles: Style[] = [
|
||||||
new Style({
|
new Style({
|
||||||
|
zIndex: engPriority,
|
||||||
image: new Icon({
|
image: new Icon({
|
||||||
src: iconUrl,
|
src: iconUrl,
|
||||||
scale: dynamicScale,
|
scale: dynamicScale,
|
||||||
@ -397,7 +438,7 @@ export class MapOl implements MapInterface {
|
|||||||
if (formattedLabelText && labelTargetVisible) {
|
if (formattedLabelText && labelTargetVisible) {
|
||||||
styles.push(
|
styles.push(
|
||||||
new Style({
|
new Style({
|
||||||
zIndex: 101,
|
zIndex: engPriority + 1,
|
||||||
text: new Text({
|
text: new Text({
|
||||||
text: formattedLabelText,
|
text: formattedLabelText,
|
||||||
offsetY: labelOffsetY,
|
offsetY: labelOffsetY,
|
||||||
@ -598,6 +639,7 @@ export class MapOl implements MapInterface {
|
|||||||
top: number;
|
top: number;
|
||||||
bottom: number;
|
bottom: number;
|
||||||
priority: number;
|
priority: number;
|
||||||
|
engPriority: number;
|
||||||
densityPriority: number;
|
densityPriority: number;
|
||||||
id: string;
|
id: string;
|
||||||
pixelX: number;
|
pixelX: number;
|
||||||
@ -616,6 +658,7 @@ export class MapOl implements MapInterface {
|
|||||||
top: number;
|
top: number;
|
||||||
bottom: number;
|
bottom: number;
|
||||||
priority: number;
|
priority: number;
|
||||||
|
engPriority: number;
|
||||||
densityPriority: number;
|
densityPriority: number;
|
||||||
id: string;
|
id: string;
|
||||||
pixelX: number;
|
pixelX: number;
|
||||||
@ -808,7 +851,7 @@ export class MapOl implements MapInterface {
|
|||||||
const dynamicScale = this.getDynamicPointScale(currentZoom);
|
const dynamicScale = this.getDynamicPointScale(currentZoom);
|
||||||
// 备注:图标碰撞盒适当小于视觉图标尺寸,允许相邻站点轻微贴近显示,
|
// 备注:图标碰撞盒适当小于视觉图标尺寸,允许相邻站点轻微贴近显示,
|
||||||
// 避免像“小浪底/三门峡”这类近点被过早裁掉成只剩一个点。
|
// 避免像“小浪底/三门峡”这类近点被过早裁掉成只剩一个点。
|
||||||
const iconCollisionSize = Math.max(12, 16 * dynamicScale);
|
const iconCollisionSize = Math.max(14, 24 * dynamicScale);
|
||||||
const iconPadding = 0;
|
const iconPadding = 0;
|
||||||
const iconLeft = entry.pixelX - iconCollisionSize / 2 - iconPadding;
|
const iconLeft = entry.pixelX - iconCollisionSize / 2 - iconPadding;
|
||||||
const iconRight = entry.pixelX + iconCollisionSize / 2 + iconPadding;
|
const iconRight = entry.pixelX + iconCollisionSize / 2 + iconPadding;
|
||||||
@ -851,6 +894,7 @@ export class MapOl implements MapInterface {
|
|||||||
top: centerY - estimatedHeight / 2,
|
top: centerY - estimatedHeight / 2,
|
||||||
bottom: centerY + estimatedHeight / 2,
|
bottom: centerY + estimatedHeight / 2,
|
||||||
priority: Number(entry.feature.get('_nearbyPriority') || 9999),
|
priority: Number(entry.feature.get('_nearbyPriority') || 9999),
|
||||||
|
engPriority: this.getFeatureEngRenderPriority(entry.feature),
|
||||||
densityPriority: entry.densityPriority,
|
densityPriority: entry.densityPriority,
|
||||||
id: candidateId,
|
id: candidateId,
|
||||||
pixelX: entry.pixelX,
|
pixelX: entry.pixelX,
|
||||||
@ -863,6 +907,9 @@ export class MapOl implements MapInterface {
|
|||||||
});
|
});
|
||||||
|
|
||||||
candidates.sort((left, right) => {
|
candidates.sort((left, right) => {
|
||||||
|
if (left.engPriority !== right.engPriority) {
|
||||||
|
return right.engPriority - left.engPriority;
|
||||||
|
}
|
||||||
if (left.priority !== right.priority) {
|
if (left.priority !== right.priority) {
|
||||||
return left.priority - right.priority;
|
return left.priority - right.priority;
|
||||||
}
|
}
|
||||||
@ -951,6 +998,9 @@ export class MapOl implements MapInterface {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const labelCandidates = [...candidates].sort((left, right) => {
|
const labelCandidates = [...candidates].sort((left, right) => {
|
||||||
|
if (left.engPriority !== right.engPriority) {
|
||||||
|
return right.engPriority - left.engPriority;
|
||||||
|
}
|
||||||
if (left.priority !== right.priority) {
|
if (left.priority !== right.priority) {
|
||||||
return left.priority - right.priority;
|
return left.priority - right.priority;
|
||||||
}
|
}
|
||||||
@ -1149,10 +1199,11 @@ export class MapOl implements MapInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private requestUpdateBatchPopups(immediate = false) {
|
private requestUpdateBatchPopups(immediate = false, rebuild = true) {
|
||||||
if (!this.isBatchPopupMode) {
|
if (!this.isBatchPopupMode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.batchPopupPendingRebuild = this.batchPopupPendingRebuild || rebuild;
|
||||||
|
|
||||||
if (immediate) {
|
if (immediate) {
|
||||||
if (this.batchPopupRefreshFrameId !== null) {
|
if (this.batchPopupRefreshFrameId !== null) {
|
||||||
@ -1160,6 +1211,7 @@ export class MapOl implements MapInterface {
|
|||||||
this.batchPopupRefreshFrameId = null;
|
this.batchPopupRefreshFrameId = null;
|
||||||
}
|
}
|
||||||
this.updateBatchPopups();
|
this.updateBatchPopups();
|
||||||
|
this.batchPopupPendingRebuild = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1173,6 +1225,7 @@ export class MapOl implements MapInterface {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.updateBatchPopups();
|
this.updateBatchPopups();
|
||||||
|
this.batchPopupPendingRebuild = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1326,6 +1379,27 @@ export class MapOl implements MapInterface {
|
|||||||
return densityDisplayRules.at(-1)?.minZoom ?? 0;
|
return densityDisplayRules.at(-1)?.minZoom ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isFeatureEng(feature: Feature): boolean {
|
||||||
|
const layerKey = String(feature.get('_layerKey') || '').toLowerCase();
|
||||||
|
const sttpMap = String(
|
||||||
|
feature.get('_sttpMap') || feature.get('sttpMap') || ''
|
||||||
|
).toUpperCase();
|
||||||
|
const sttpCode = String(
|
||||||
|
feature.get('sttpCode') || feature.get('sttp') || ''
|
||||||
|
).toUpperCase();
|
||||||
|
|
||||||
|
return (
|
||||||
|
layerKey.includes('eng_point') ||
|
||||||
|
sttpMap === 'ENG' ||
|
||||||
|
sttpMap === 'ENG2' ||
|
||||||
|
sttpCode === 'ENG'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getFeatureEngRenderPriority(feature: Feature): number {
|
||||||
|
return this.isFeatureEng(feature) ? 200 : 100;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 如果点位在当前视图中没有近邻点,则允许跳过静态密度门槛直接参与显示。
|
* 如果点位在当前视图中没有近邻点,则允许跳过静态密度门槛直接参与显示。
|
||||||
* 这样像“戈兰滩”这类 distance 档位偏密、但当前周围实际很空的点也能出现。
|
* 这样像“戈兰滩”这类 distance 档位偏密、但当前周围实际很空的点也能出现。
|
||||||
@ -1407,10 +1481,9 @@ export class MapOl implements MapInterface {
|
|||||||
const nearbyGroupId = feature.get('_nearbyGroupId');
|
const nearbyGroupId = feature.get('_nearbyGroupId');
|
||||||
const groupSize = Number(feature.get('_nearbyGroupSize'));
|
const groupSize = Number(feature.get('_nearbyGroupSize'));
|
||||||
const priority = Number(feature.get('_nearbyPriority'));
|
const priority = Number(feature.get('_nearbyPriority'));
|
||||||
const replaceAtZoom = Number(feature.get('_nearbyReplaceAtZoom'));
|
|
||||||
const expandAtZoom = Number(feature.get('_nearbyExpandAtZoom'));
|
|
||||||
const showZoomMin = feature.get('_nearbyShowZoomMin');
|
const showZoomMin = feature.get('_nearbyShowZoomMin');
|
||||||
const showZoomMax = feature.get('_nearbyShowZoomMax');
|
const showZoomMax = feature.get('_nearbyShowZoomMax');
|
||||||
|
const expandAtZoom = feature.get('_nearbyExpandAtZoom');
|
||||||
|
|
||||||
if (!nearbyGroupId || !Number.isFinite(groupSize) || groupSize < 2) {
|
if (!nearbyGroupId || !Number.isFinite(groupSize) || groupSize < 2) {
|
||||||
return true;
|
return true;
|
||||||
@ -1436,14 +1509,14 @@ export class MapOl implements MapInterface {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Number.isFinite(expandAtZoom) && currentZoom >= expandAtZoom) {
|
if (
|
||||||
|
expandAtZoom !== null &&
|
||||||
|
expandAtZoom !== undefined &&
|
||||||
|
currentZoom >= Number(expandAtZoom)
|
||||||
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Number.isFinite(replaceAtZoom) && currentZoom >= replaceAtZoom) {
|
|
||||||
return priority <= Math.min(2, groupSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
return priority === 1;
|
return priority === 1;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -2436,6 +2509,10 @@ export class MapOl implements MapInterface {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getCurrentZoom(): number | undefined {
|
||||||
|
return this.view?.getZoom();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成带完整圆边框的上半圆 Canvas
|
* 生成带完整圆边框的上半圆 Canvas
|
||||||
* @param radius 半径(像素)
|
* @param radius 半径(像素)
|
||||||
@ -2496,6 +2573,7 @@ export class MapOl implements MapInterface {
|
|||||||
window.clearTimeout(this.labelVisibilityDebounceTimerId);
|
window.clearTimeout(this.labelVisibilityDebounceTimerId);
|
||||||
this.labelVisibilityDebounceTimerId = null;
|
this.labelVisibilityDebounceTimerId = null;
|
||||||
}
|
}
|
||||||
|
this.clearBatchPopupPostRenderSync();
|
||||||
this.removeQueryLayer();
|
this.removeQueryLayer();
|
||||||
this.regionMaskManager.destroy();
|
this.regionMaskManager.destroy();
|
||||||
|
|
||||||
|
|||||||
@ -318,7 +318,7 @@ export class PointLayerManager {
|
|||||||
layerKey: string,
|
layerKey: string,
|
||||||
matchValue: string,
|
matchValue: string,
|
||||||
checked: boolean,
|
checked: boolean,
|
||||||
fieldKey: string = 'anchoPointState'
|
fieldKey = 'anchoPointState'
|
||||||
): void {
|
): void {
|
||||||
const vectorLayer = this.layerRegistry.get(layerKey);
|
const vectorLayer = this.layerRegistry.get(layerKey);
|
||||||
if (!vectorLayer) return;
|
if (!vectorLayer) return;
|
||||||
|
|||||||
@ -4,7 +4,10 @@ import OlMap from 'ol/Map';
|
|||||||
import Overlay from 'ol/Overlay';
|
import Overlay from 'ol/Overlay';
|
||||||
import VectorLayer from 'ol/layer/Vector';
|
import VectorLayer from 'ol/layer/Vector';
|
||||||
import VectorSource from 'ol/source/Vector';
|
import VectorSource from 'ol/source/Vector';
|
||||||
import { generatePopupHtml } from '@/utils/popupHtmlGenerator';
|
import {
|
||||||
|
generatePopupHtml,
|
||||||
|
shouldPreferEng2Popup
|
||||||
|
} from '@/utils/popupHtmlGenerator';
|
||||||
|
|
||||||
type PopupManagerOptions = {
|
type PopupManagerOptions = {
|
||||||
map: OlMap | null;
|
map: OlMap | null;
|
||||||
@ -27,6 +30,11 @@ export class PopupManager {
|
|||||||
private map: OlMap | null;
|
private map: OlMap | null;
|
||||||
private popupOverlay: Overlay | null = null;
|
private popupOverlay: Overlay | null = null;
|
||||||
private popupElement: HTMLElement | null = null;
|
private popupElement: HTMLElement | null = null;
|
||||||
|
private batchPopupContainer: HTMLDivElement | null = null;
|
||||||
|
private batchPopupItems: Array<{
|
||||||
|
feature: Feature;
|
||||||
|
element: HTMLDivElement;
|
||||||
|
}> = [];
|
||||||
private lastHoveredId: string | number | null = null;
|
private lastHoveredId: string | number | null = null;
|
||||||
private animationFrameId: number | null = null;
|
private animationFrameId: number | null = null;
|
||||||
private getPointLayers: () => VectorLayer<VectorSource>[];
|
private getPointLayers: () => VectorLayer<VectorSource>[];
|
||||||
@ -49,6 +57,11 @@ export class PopupManager {
|
|||||||
// 备注:初始化 Popup Overlay 并挂载到地图实例。
|
// 备注:初始化 Popup Overlay 并挂载到地图实例。
|
||||||
initPopupOverlay(container: HTMLElement) {
|
initPopupOverlay(container: HTMLElement) {
|
||||||
this.popupElement = container;
|
this.popupElement = container;
|
||||||
|
this.popupElement.style.display = 'none';
|
||||||
|
this.popupElement.style.removeProperty('position');
|
||||||
|
this.popupElement.style.removeProperty('transform');
|
||||||
|
this.popupElement.style.removeProperty('left');
|
||||||
|
this.popupElement.style.removeProperty('top');
|
||||||
this.popupElement.style.setProperty('pointer-events', 'none', 'important');
|
this.popupElement.style.setProperty('pointer-events', 'none', 'important');
|
||||||
this.popupMouseEnterHandler = () => {
|
this.popupMouseEnterHandler = () => {
|
||||||
this.forceHidePopup();
|
this.forceHidePopup();
|
||||||
@ -190,7 +203,7 @@ export class PopupManager {
|
|||||||
|
|
||||||
if (feature && coordinate) {
|
if (feature && coordinate) {
|
||||||
const props = feature.getProperties();
|
const props = feature.getProperties();
|
||||||
const popupHtml = props.popupHtml || generatePopupHtml(props);
|
const popupHtml = this.getPopupHtml(props);
|
||||||
|
|
||||||
if (popupHtml) {
|
if (popupHtml) {
|
||||||
this.popupElement.innerHTML = popupHtml;
|
this.popupElement.innerHTML = popupHtml;
|
||||||
@ -204,22 +217,37 @@ export class PopupManager {
|
|||||||
this.popupElement.style.display = 'none';
|
this.popupElement.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getPopupHtml(props: Record<string, any>) {
|
||||||
|
return props.popupHtml || generatePopupHtml(props);
|
||||||
|
}
|
||||||
|
|
||||||
// 备注:批量显示多个要素的 Popup,使用绝对定位的 div 而非 Overlay。
|
// 备注:批量显示多个要素的 Popup,使用绝对定位的 div 而非 Overlay。
|
||||||
showPopupsForFeatures(
|
showPopupsForFeatures(
|
||||||
features: Feature[],
|
features: Feature[],
|
||||||
styleChecker?: (feature: Feature) => boolean
|
styleChecker?: (feature: Feature) => boolean,
|
||||||
|
options?: {
|
||||||
|
rebuild?: boolean;
|
||||||
|
}
|
||||||
) {
|
) {
|
||||||
if (!this.map || !this.popupElement) return;
|
if (!this.map || !this.popupElement) return;
|
||||||
|
const shouldRebuild = options?.rebuild !== false;
|
||||||
// 清除之前批量显示的 popups
|
|
||||||
this.clearBatchPopups();
|
|
||||||
|
|
||||||
// 过滤:只显示图例可见的要素
|
// 过滤:只显示图例可见的要素
|
||||||
const visibleFeatures = features.filter(
|
const visibleFeatures = features.filter(
|
||||||
f => f.get('_legendVisible') !== false
|
f => f.get('_legendVisible') !== false
|
||||||
);
|
);
|
||||||
|
|
||||||
if (visibleFeatures.length === 0) return;
|
if (visibleFeatures.length === 0) {
|
||||||
|
this.clearBatchPopups();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shouldRebuild && this.batchPopupItems.length > 0) {
|
||||||
|
this.updateBatchPopupPositions(styleChecker);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.clearBatchPopups();
|
||||||
|
|
||||||
const mapElement = this.map.getTargetElement();
|
const mapElement = this.map.getTargetElement();
|
||||||
const batchContainer = document.createElement('div');
|
const batchContainer = document.createElement('div');
|
||||||
@ -234,6 +262,7 @@ export class PopupManager {
|
|||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
`;
|
`;
|
||||||
batchContainer.id = 'batch-popup-container';
|
batchContainer.id = 'batch-popup-container';
|
||||||
|
this.batchPopupContainer = batchContainer;
|
||||||
|
|
||||||
// 先添加容器到 DOM,以便后续元素能正确测量尺寸
|
// 先添加容器到 DOM,以便后续元素能正确测量尺寸
|
||||||
mapElement.appendChild(batchContainer);
|
mapElement.appendChild(batchContainer);
|
||||||
@ -245,12 +274,6 @@ export class PopupManager {
|
|||||||
top: number;
|
top: number;
|
||||||
bottom: number;
|
bottom: number;
|
||||||
}> = [];
|
}> = [];
|
||||||
let styleHiddenCount = 0;
|
|
||||||
let blockedCount = 0;
|
|
||||||
let renderedCount = 0;
|
|
||||||
const renderedIds: Array<string | number | null> = [];
|
|
||||||
const blockedIds: Array<string | number | null> = [];
|
|
||||||
|
|
||||||
visibleFeatures.forEach(feature => {
|
visibleFeatures.forEach(feature => {
|
||||||
const geom = feature.getGeometry();
|
const geom = feature.getGeometry();
|
||||||
if (!geom || geom.getType() !== 'Point') return;
|
if (!geom || geom.getType() !== 'Point') return;
|
||||||
@ -261,12 +284,15 @@ export class PopupManager {
|
|||||||
|
|
||||||
// 检查样式是否隐藏(declutter、距离过滤等)
|
// 检查样式是否隐藏(declutter、距离过滤等)
|
||||||
if (styleChecker && !styleChecker(feature)) {
|
if (styleChecker && !styleChecker(feature)) {
|
||||||
styleHiddenCount += 1;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = feature.getProperties();
|
const props = feature.getProperties();
|
||||||
const popupHtml = props.popupHtml || generatePopupHtml(props);
|
const popupHtml = shouldPreferEng2Popup(props)
|
||||||
|
? generatePopupHtml(props, { forceEng2: true }) ||
|
||||||
|
props.popupHtml ||
|
||||||
|
generatePopupHtml(props)
|
||||||
|
: this.getPopupHtml(props);
|
||||||
if (!popupHtml) return;
|
if (!popupHtml) return;
|
||||||
|
|
||||||
// 创建与原始 popupElement 完全相同的样式
|
// 创建与原始 popupElement 完全相同的样式
|
||||||
@ -314,8 +340,10 @@ export class PopupManager {
|
|||||||
popupEl.style.visibility = 'visible';
|
popupEl.style.visibility = 'visible';
|
||||||
popupEl.style.left = `${popupX}px`;
|
popupEl.style.left = `${popupX}px`;
|
||||||
popupEl.style.top = `${popupY}px`;
|
popupEl.style.top = `${popupY}px`;
|
||||||
renderedCount += 1;
|
this.batchPopupItems.push({
|
||||||
renderedIds.push((feature.getId?.() as string | number | null) ?? null);
|
feature,
|
||||||
|
element: popupEl
|
||||||
|
});
|
||||||
|
|
||||||
placedPopups.push({
|
placedPopups.push({
|
||||||
left: popupRect.left,
|
left: popupRect.left,
|
||||||
@ -325,15 +353,76 @@ export class PopupManager {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// 有碰撞,移除该 popup
|
// 有碰撞,移除该 popup
|
||||||
blockedCount += 1;
|
|
||||||
blockedIds.push((feature.getId?.() as string | number | null) ?? null);
|
|
||||||
batchContainer.removeChild(popupEl);
|
batchContainer.removeChild(popupEl);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateBatchPopupPositions(styleChecker?: (feature: Feature) => boolean) {
|
||||||
|
if (
|
||||||
|
!this.map ||
|
||||||
|
!this.batchPopupContainer ||
|
||||||
|
this.batchPopupItems.length === 0
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapSize = this.map.getSize();
|
||||||
|
const viewportWidth = mapSize?.[0] ?? 0;
|
||||||
|
const viewportHeight = mapSize?.[1] ?? 0;
|
||||||
|
const viewportPadding = 48;
|
||||||
|
|
||||||
|
this.batchPopupItems.forEach(({ feature, element }) => {
|
||||||
|
if (feature.get('_legendVisible') === false) {
|
||||||
|
element.style.display = 'none';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (styleChecker && !styleChecker(feature)) {
|
||||||
|
element.style.display = 'none';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const geom = feature.getGeometry();
|
||||||
|
if (!geom || geom.getType() !== 'Point') {
|
||||||
|
element.style.display = 'none';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const coords = (geom as Point).getCoordinates();
|
||||||
|
const pixel = this.map?.getPixelFromCoordinate(coords);
|
||||||
|
if (!pixel) {
|
||||||
|
element.style.display = 'none';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const popupX = pixel[0];
|
||||||
|
const popupY = pixel[1] - 10;
|
||||||
|
if (
|
||||||
|
popupX < -viewportPadding ||
|
||||||
|
popupY < -viewportPadding ||
|
||||||
|
popupX > viewportWidth + viewportPadding ||
|
||||||
|
popupY > viewportHeight + viewportPadding
|
||||||
|
) {
|
||||||
|
element.style.display = 'none';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
element.style.left = `${popupX}px`;
|
||||||
|
element.style.top = `${popupY}px`;
|
||||||
|
element.style.display = 'block';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 备注:清除批量显示的 popups。
|
// 备注:清除批量显示的 popups。
|
||||||
clearBatchPopups() {
|
clearBatchPopups() {
|
||||||
|
this.batchPopupItems = [];
|
||||||
|
if (this.batchPopupContainer) {
|
||||||
|
this.batchPopupContainer.remove();
|
||||||
|
this.batchPopupContainer = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const existing = document.getElementById('batch-popup-container');
|
const existing = document.getElementById('batch-popup-container');
|
||||||
if (existing) {
|
if (existing) {
|
||||||
existing.remove();
|
existing.remove();
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="map-filter-container">
|
<div
|
||||||
|
class="map-filter-container"
|
||||||
|
:style="{ left: uiStore.mapType == '2D' ? '220px' : '20px' }"
|
||||||
|
>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<a-form :model="formModel">
|
<a-form :model="formModel">
|
||||||
<a-row :gutter="10">
|
<a-row :gutter="10">
|
||||||
@ -110,7 +113,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, watch } from 'vue';
|
import { ref, computed, watch, nextTick } from 'vue';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { MapClass } from '@/components/gis/map.class';
|
import { MapClass } from '@/components/gis/map.class';
|
||||||
@ -118,6 +121,7 @@ import { useMapOrchestrator } from '@/modules/map/application/map-orchestrator';
|
|||||||
import { useMapDataStore } from '@/modules/map/stores/map-data.store';
|
import { useMapDataStore } from '@/modules/map/stores/map-data.store';
|
||||||
import { useMapViewStore } from '@/modules/map/stores/map-view.store';
|
import { useMapViewStore } from '@/modules/map/stores/map-view.store';
|
||||||
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
|
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
|
||||||
|
import { useUiStore } from '@/store/modules/ui';
|
||||||
import { useMapStore } from '@/store/modules/map';
|
import { useMapStore } from '@/store/modules/map';
|
||||||
import { DateSetting } from '@/utils/enumeration';
|
import { DateSetting } from '@/utils/enumeration';
|
||||||
import { getFishList, getFishPointList } from '@/api/map';
|
import { getFishList, getFishPointList } from '@/api/map';
|
||||||
@ -126,6 +130,7 @@ const route = useRoute();
|
|||||||
const mapOrchestrator = useMapOrchestrator();
|
const mapOrchestrator = useMapOrchestrator();
|
||||||
const mapDataStore = useMapDataStore();
|
const mapDataStore = useMapDataStore();
|
||||||
const mapViewStore = useMapViewStore();
|
const mapViewStore = useMapViewStore();
|
||||||
|
const uiStore = useUiStore();
|
||||||
const jidiSelectEventStore = useJidiSelectEventStore();
|
const jidiSelectEventStore = useJidiSelectEventStore();
|
||||||
const mapStore = useMapStore();
|
const mapStore = useMapStore();
|
||||||
const mapClass = MapClass.getInstance();
|
const mapClass = MapClass.getInstance();
|
||||||
@ -156,6 +161,7 @@ const fishPointOptions = ref<any[]>([]);
|
|||||||
const fishSpeciesOptions = ref<{ label: string; value: string }[]>([]);
|
const fishSpeciesOptions = ref<{ label: string; value: string }[]>([]);
|
||||||
const fishSpeciesLoading = ref(false);
|
const fishSpeciesLoading = ref(false);
|
||||||
const fishPointLoading = ref(false);
|
const fishPointLoading = ref(false);
|
||||||
|
const refocusTimer = ref<ReturnType<typeof setTimeout> | null>(null);
|
||||||
|
|
||||||
const searchTimeRange = ref([
|
const searchTimeRange = ref([
|
||||||
dayjs(mapViewStore.searchTimeRange[0]).format('YYYY-MM-DD HH:mm:ss'),
|
dayjs(mapViewStore.searchTimeRange[0]).format('YYYY-MM-DD HH:mm:ss'),
|
||||||
@ -623,15 +629,48 @@ const handleCapacityChange = (value: string) => {
|
|||||||
mapOrchestrator.changeEngPointCapacity(value);
|
mapOrchestrator.changeEngPointCapacity(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 备注:搜索定位只分发定位命令,不在筛选组件里直接操作地图实例。
|
const clearRefocusTimer = () => {
|
||||||
const handleAnchorPointChange = (value: string) => {
|
if (!refocusTimer.value) {
|
||||||
if (!value) return;
|
return;
|
||||||
|
}
|
||||||
|
clearTimeout(refocusTimer.value);
|
||||||
|
refocusTimer.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const focusSelectedAnchorPoint = () => {
|
||||||
|
const selectedValue = anchorPointSelectValue.value;
|
||||||
|
if (!selectedValue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mapOrchestrator.focusPoint(
|
mapOrchestrator.focusPoint(
|
||||||
value,
|
selectedValue,
|
||||||
14,
|
14,
|
||||||
isFishSurveyMode.value ? anchorPointOptions.value : undefined
|
isFishSurveyMode.value ? anchorPointOptions.value : undefined
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 备注:搜索定位只分发定位命令,不在筛选组件里直接操作地图实例。
|
||||||
|
const handleAnchorPointChange = (value: string) => {
|
||||||
|
if (!value) return;
|
||||||
|
focusSelectedAnchorPoint();
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => uiStore.mapSwitchCompletedTick,
|
||||||
|
async (newVal, oldVal) => {
|
||||||
|
if (newVal === oldVal || !anchorPointSelectValue.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await nextTick();
|
||||||
|
clearRefocusTimer();
|
||||||
|
refocusTimer.value = setTimeout(() => {
|
||||||
|
refocusTimer.value = null;
|
||||||
|
focusSelectedAnchorPoint();
|
||||||
|
}, 120);
|
||||||
|
}
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
import { useUiStore } from '@/store/modules/ui';
|
||||||
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
|
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const isOpen = ref(true);
|
const isOpen = ref(true);
|
||||||
const JidiSelectEventStore = useJidiSelectEventStore();
|
const JidiSelectEventStore = useJidiSelectEventStore();
|
||||||
|
const uiStore = useUiStore();
|
||||||
|
|
||||||
const jidiDataNum = ref(9);
|
const jidiDataNum = ref(9);
|
||||||
const itemClick = (index: any) => {
|
const itemClick = (index: any) => {
|
||||||
@ -13,7 +15,7 @@ onMounted(() => {});
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="jidiSelectorMod">
|
<div class="jidiSelectorMod" v-if="uiStore.mapType == '2D'">
|
||||||
<a-spin :spinning="JidiSelectEventStore.loading">
|
<a-spin :spinning="JidiSelectEventStore.loading">
|
||||||
<div
|
<div
|
||||||
class="qgc-dropdown-select"
|
class="qgc-dropdown-select"
|
||||||
|
|||||||
@ -43,6 +43,7 @@ const HYDRO_DYNAMIC_LAYER_KEYS = [
|
|||||||
];
|
];
|
||||||
const ENG_POINT_LAYER_KEY = 'eng_point';
|
const ENG_POINT_LAYER_KEY = 'eng_point';
|
||||||
const ENG_POINT_MEDIUM_VISIBLE_ZOOM = 7.5;
|
const ENG_POINT_MEDIUM_VISIBLE_ZOOM = 7.5;
|
||||||
|
const CESIUM_ZOOM_SYNC_DEBOUNCE_MS = 80;
|
||||||
const LARGE_ENG_LEGEND_PREFIX = 'large_eng_';
|
const LARGE_ENG_LEGEND_PREFIX = 'large_eng_';
|
||||||
const MID_ENG_LEGEND_PREFIX = 'mid_eng_';
|
const MID_ENG_LEGEND_PREFIX = 'mid_eng_';
|
||||||
|
|
||||||
@ -55,12 +56,20 @@ export const useMapOrchestrator = () => {
|
|||||||
const mapViewStore = useMapViewStore();
|
const mapViewStore = useMapViewStore();
|
||||||
const jidiSelectEventStore = useJidiSelectEventStore();
|
const jidiSelectEventStore = useJidiSelectEventStore();
|
||||||
let activePageLoadRequestId = 0;
|
let activePageLoadRequestId = 0;
|
||||||
let zoomListenerKey: any = null;
|
let removeZoomListener: (() => void) | null = null;
|
||||||
let stopBaseSelectionWatch: WatchStopHandle | null = null;
|
let stopBaseSelectionWatch: WatchStopHandle | null = null;
|
||||||
const initializedBaseLayerKeys = new Set<string>();
|
const initializedBaseLayerKeys = new Set<string>();
|
||||||
const baseSelectionDebounceTimer = ref<ReturnType<typeof setTimeout> | null>(
|
const baseSelectionDebounceTimer = ref<ReturnType<typeof setTimeout> | null>(
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
const zoomSyncDebounceTimer = ref<ReturnType<typeof setTimeout> | null>(null);
|
||||||
|
let latestHydroMenuGetter: (() => boolean) | null = null;
|
||||||
|
let currentMapType: '2D' | '3D' = '2D';
|
||||||
|
let hydroMenuDefaultCheckedKeys = new Set<string>();
|
||||||
|
let hydroDynamicLayerSyncTask: {
|
||||||
|
visible: boolean;
|
||||||
|
promise: Promise<string[] | void>;
|
||||||
|
} | null = null;
|
||||||
|
|
||||||
// 备注:统一获取当前地图视图对象,避免在多个组件里重复兼容 2D/3D view 访问方式。
|
// 备注:统一获取当前地图视图对象,避免在多个组件里重复兼容 2D/3D view 访问方式。
|
||||||
const getCurrentView = () => {
|
const getCurrentView = () => {
|
||||||
@ -69,7 +78,14 @@ export const useMapOrchestrator = () => {
|
|||||||
|
|
||||||
// 备注:统一获取当前地图缩放级别,供页面切换和缩放监听复用。
|
// 备注:统一获取当前地图缩放级别,供页面切换和缩放监听复用。
|
||||||
const getCurrentZoom = (): number | undefined => {
|
const getCurrentZoom = (): number | undefined => {
|
||||||
return getCurrentView()?.getZoom?.();
|
return mapClass.getCurrentZoom();
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearZoomSyncDebounceTimer = () => {
|
||||||
|
if (zoomSyncDebounceTimer.value) {
|
||||||
|
clearTimeout(zoomSyncDebounceTimer.value);
|
||||||
|
zoomSyncDebounceTimer.value = null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 备注:统一把当前页面中的 GIS 基础图层初始化到地图实例,避免在图层树组件里做配置解析和加层编排。
|
// 备注:统一把当前页面中的 GIS 基础图层初始化到地图实例,避免在图层树组件里做配置解析和加层编排。
|
||||||
@ -95,7 +111,20 @@ export const useMapOrchestrator = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (item.key === 'customBaseLayer') {
|
if (item.key === 'customBaseLayer') {
|
||||||
sessionStorage.setItem('customBaseLayer', JSON.stringify(item.config));
|
const serializableBaseLayerConfig = {
|
||||||
|
key: item.config?.key,
|
||||||
|
id: item.config?.id,
|
||||||
|
name: item.config?.name,
|
||||||
|
type: item.config?.type,
|
||||||
|
url: item.config?.url,
|
||||||
|
url_3d: item.config?.url_3d,
|
||||||
|
layers: item.config?.layers,
|
||||||
|
rasteropacity: item.config?.rasteropacity
|
||||||
|
};
|
||||||
|
sessionStorage.setItem(
|
||||||
|
'customBaseLayer',
|
||||||
|
JSON.stringify(serializableBaseLayerConfig)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!initializedBaseLayerKeys.has(item.key)) {
|
if (!initializedBaseLayerKeys.has(item.key)) {
|
||||||
@ -154,6 +183,9 @@ export const useMapOrchestrator = () => {
|
|||||||
|
|
||||||
// 先设置图层数据(更新 checkedLayerKeys),再设置图例数据
|
// 先设置图层数据(更新 checkedLayerKeys),再设置图例数据
|
||||||
if (layerConfig.length > 0) {
|
if (layerConfig.length > 0) {
|
||||||
|
hydroMenuDefaultCheckedKeys = new Set(
|
||||||
|
mapConfigStore.extractCheckedLayerKeys(layerConfig)
|
||||||
|
);
|
||||||
mapStore.setLayerData(layerConfig);
|
mapStore.setLayerData(layerConfig);
|
||||||
ensureBaseLayersInitialized(layerConfig);
|
ensureBaseLayersInitialized(layerConfig);
|
||||||
|
|
||||||
@ -229,10 +261,58 @@ export const useMapOrchestrator = () => {
|
|||||||
await mapClass.init(container);
|
await mapClass.init(container);
|
||||||
|
|
||||||
if (popupContainer) {
|
if (popupContainer) {
|
||||||
|
const popupHost = container.parentElement;
|
||||||
|
if (popupHost && popupContainer.parentElement !== popupHost) {
|
||||||
|
popupHost.appendChild(popupContainer);
|
||||||
|
}
|
||||||
|
popupContainer.style.display = 'none';
|
||||||
mapClass.initPopupOverlay(popupContainer);
|
mapClass.initPopupOverlay(popupContainer);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const replayCurrentMapState = async (
|
||||||
|
options: Pick<InitializeOptions, 'popupContainer'> & {
|
||||||
|
getIsHydroMenu: () => boolean;
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
initializedBaseLayerKeys.clear();
|
||||||
|
|
||||||
|
const currentZoom = getCurrentZoom();
|
||||||
|
if (currentZoom !== undefined) {
|
||||||
|
mapViewStore.setCurrentZoomLevel(currentZoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.popupContainer) {
|
||||||
|
const container = document.getElementById('mapContainer');
|
||||||
|
const popupHost = container?.parentElement || null;
|
||||||
|
if (popupHost && options.popupContainer.parentElement !== popupHost) {
|
||||||
|
popupHost.appendChild(options.popupContainer);
|
||||||
|
}
|
||||||
|
options.popupContainer.style.display = 'none';
|
||||||
|
mapClass.initPopupOverlay(options.popupContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureBaseLayersInitialized(mapStore.layerData || []);
|
||||||
|
|
||||||
|
const checkedKeys = mapViewStore.getCheckedLayerKeys();
|
||||||
|
await mapStore.updateLayerData(checkedKeys, true);
|
||||||
|
mapStore.setSelectedLegendData();
|
||||||
|
await syncZoomSensitiveState({
|
||||||
|
isHydroMenu: options.getIsHydroMenu(),
|
||||||
|
refreshEngPoint: true
|
||||||
|
});
|
||||||
|
|
||||||
|
if (currentMapType === '2D') {
|
||||||
|
const selectedBaseId = mapViewStore.selectedBaseId;
|
||||||
|
mapClass.jdPanelControlShowAndHidden(
|
||||||
|
selectedBaseId || 'all',
|
||||||
|
!!selectedBaseId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bindZoomListener(options.getIsHydroMenu);
|
||||||
|
};
|
||||||
|
|
||||||
// 备注:统一完成首屏页面配置加载,供挂载阶段和后续页面重载复用。
|
// 备注:统一完成首屏页面配置加载,供挂载阶段和后续页面重载复用。
|
||||||
const initialize = async ({
|
const initialize = async ({
|
||||||
container,
|
container,
|
||||||
@ -249,20 +329,18 @@ export const useMapOrchestrator = () => {
|
|||||||
|
|
||||||
// 备注:统一绑定地图缩放监听,让页面组件只负责触发初始化,不再直接处理缩放联动细节。
|
// 备注:统一绑定地图缩放监听,让页面组件只负责触发初始化,不再直接处理缩放联动细节。
|
||||||
const bindZoomListener = (getIsHydroMenu: () => boolean) => {
|
const bindZoomListener = (getIsHydroMenu: () => boolean) => {
|
||||||
if (zoomListenerKey) {
|
if (removeZoomListener) {
|
||||||
unByKey(zoomListenerKey);
|
removeZoomListener();
|
||||||
zoomListenerKey = null;
|
removeZoomListener = null;
|
||||||
}
|
}
|
||||||
|
clearZoomSyncDebounceTimer();
|
||||||
const view = getCurrentView();
|
|
||||||
if (!view?.on) return;
|
|
||||||
|
|
||||||
const currentZoom = getCurrentZoom();
|
const currentZoom = getCurrentZoom();
|
||||||
if (currentZoom !== undefined) {
|
if (currentZoom !== undefined) {
|
||||||
mapViewStore.setCurrentZoomLevel(currentZoom);
|
mapViewStore.setCurrentZoomLevel(currentZoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
zoomListenerKey = view.on('change:resolution', async () => {
|
const emitZoomChange = async () => {
|
||||||
const zoom = getCurrentZoom();
|
const zoom = getCurrentZoom();
|
||||||
if (zoom === undefined) return;
|
if (zoom === undefined) return;
|
||||||
|
|
||||||
@ -271,7 +349,36 @@ export const useMapOrchestrator = () => {
|
|||||||
zoom,
|
zoom,
|
||||||
getIsHydroMenu()
|
getIsHydroMenu()
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (currentMapType === '3D') {
|
||||||
|
const removeCesiumListener =
|
||||||
|
mapClass.view?.camera?.changed?.addEventListener(() => {
|
||||||
|
clearZoomSyncDebounceTimer();
|
||||||
|
zoomSyncDebounceTimer.value = setTimeout(() => {
|
||||||
|
zoomSyncDebounceTimer.value = null;
|
||||||
|
void emitZoomChange();
|
||||||
|
}, CESIUM_ZOOM_SYNC_DEBOUNCE_MS);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (typeof removeCesiumListener === 'function') {
|
||||||
|
removeZoomListener = () => {
|
||||||
|
clearZoomSyncDebounceTimer();
|
||||||
|
removeCesiumListener();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const view = getCurrentView();
|
||||||
|
if (!view?.on) return;
|
||||||
|
|
||||||
|
const zoomListenerKey = view.on('change:resolution', () => {
|
||||||
|
void emitZoomChange();
|
||||||
});
|
});
|
||||||
|
removeZoomListener = () => {
|
||||||
|
unByKey(zoomListenerKey);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// 备注:统一绑定基地切换事件,让页面组件不再直接 watch 外部基地选择源。
|
// 备注:统一绑定基地切换事件,让页面组件不再直接 watch 外部基地选择源。
|
||||||
@ -308,10 +415,34 @@ export const useMapOrchestrator = () => {
|
|||||||
getIsHydroMenu: () => boolean;
|
getIsHydroMenu: () => boolean;
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
|
currentMapType = '2D';
|
||||||
|
latestHydroMenuGetter = options.getIsHydroMenu;
|
||||||
await initializeMapShell(options);
|
await initializeMapShell(options);
|
||||||
bindBaseSelection();
|
bindBaseSelection();
|
||||||
bindZoomListener(options.getIsHydroMenu);
|
bindZoomListener(options.getIsHydroMenu);
|
||||||
await loadPage({ pageKey: options.pageKey, isInitialLoad: true });
|
await loadPage({ pageKey: options.pageKey, isInitialLoad: true });
|
||||||
|
await syncZoomSensitiveState({
|
||||||
|
isHydroMenu: options.getIsHydroMenu(),
|
||||||
|
refreshEngPoint: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const switchMapType = async (
|
||||||
|
type: '2D' | '3D',
|
||||||
|
options: Pick<InitializeOptions, 'popupContainer'> & {
|
||||||
|
getIsHydroMenu?: () => boolean;
|
||||||
|
} = {}
|
||||||
|
) => {
|
||||||
|
const hydroMenuGetter =
|
||||||
|
options.getIsHydroMenu || latestHydroMenuGetter || (() => false);
|
||||||
|
latestHydroMenuGetter = hydroMenuGetter;
|
||||||
|
currentMapType = type;
|
||||||
|
|
||||||
|
await mapClass.switchView(type);
|
||||||
|
await replayCurrentMapState({
|
||||||
|
popupContainer: options.popupContainer,
|
||||||
|
getIsHydroMenu: hydroMenuGetter
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 备注:统一处理菜单切换后的页面配置重载,供页面 watch 直接复用。
|
// 备注:统一处理菜单切换后的页面配置重载,供页面 watch 直接复用。
|
||||||
@ -361,47 +492,91 @@ export const useMapOrchestrator = () => {
|
|||||||
(layer: any) => layer?.url && !mapDataStore.hasPointLayerData(layer.key)
|
(layer: any) => layer?.url && !mapDataStore.hasPointLayerData(layer.key)
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const layer of layersToLoad) {
|
if (layersToLoad.length === 0) {
|
||||||
await mapStore.loadLayerData(layer);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await Promise.all(layersToLoad.map(layer => mapStore.loadLayerData(layer)));
|
||||||
};
|
};
|
||||||
|
|
||||||
// 备注:统一控制水电开发菜单下的动态图层增删,避免页面组件直接操作加载和勾选细节。
|
// 备注:统一控制水电开发菜单下的动态图层增删,避免页面组件直接操作加载和勾选细节。
|
||||||
const syncHydroDynamicLayers = async (visible: boolean) => {
|
const syncHydroDynamicLayers = async (visible: boolean) => {
|
||||||
const currentCheckedKeys = mapViewStore.getCheckedLayerKeys();
|
if (
|
||||||
const pageDefaultCheckedKeys = new Set(
|
hydroDynamicLayerSyncTask &&
|
||||||
mapConfigStore.extractCheckedLayerKeys(mapStore.layerData || [])
|
hydroDynamicLayerSyncTask.visible === visible
|
||||||
);
|
) {
|
||||||
|
return hydroDynamicLayerSyncTask.promise;
|
||||||
|
}
|
||||||
|
|
||||||
if (visible) {
|
const task = (async () => {
|
||||||
const layersToAdd = HYDRO_DYNAMIC_LAYER_KEYS.filter(
|
const currentCheckedKeys = mapViewStore.getCheckedLayerKeys();
|
||||||
key => !currentCheckedKeys.includes(key)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (layersToAdd.length === 0) {
|
if (visible) {
|
||||||
|
const layersToAdd = HYDRO_DYNAMIC_LAYER_KEYS.filter(
|
||||||
|
key => !currentCheckedKeys.includes(key)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (layersToAdd.length === 0) {
|
||||||
|
return currentCheckedKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
await ensureDynamicLayersLoaded(layersToAdd);
|
||||||
|
return applyLayerSelection({
|
||||||
|
checkedKeys: [...currentCheckedKeys, ...layersToAdd]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextCheckedKeys = currentCheckedKeys.filter(key => {
|
||||||
|
if (!HYDRO_DYNAMIC_LAYER_KEYS.includes(key)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return hydroMenuDefaultCheckedKeys.has(key);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (nextCheckedKeys.length === currentCheckedKeys.length) {
|
||||||
return currentCheckedKeys;
|
return currentCheckedKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
await ensureDynamicLayersLoaded(layersToAdd);
|
|
||||||
return applyLayerSelection({
|
return applyLayerSelection({
|
||||||
checkedKeys: [...currentCheckedKeys, ...layersToAdd]
|
checkedKeys: nextCheckedKeys
|
||||||
});
|
});
|
||||||
}
|
})().finally(() => {
|
||||||
|
if (hydroDynamicLayerSyncTask?.promise === task) {
|
||||||
const nextCheckedKeys = currentCheckedKeys.filter(key => {
|
hydroDynamicLayerSyncTask = null;
|
||||||
if (!HYDRO_DYNAMIC_LAYER_KEYS.includes(key)) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return pageDefaultCheckedKeys.has(key);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (nextCheckedKeys.length === currentCheckedKeys.length) {
|
hydroDynamicLayerSyncTask = {
|
||||||
return currentCheckedKeys;
|
visible,
|
||||||
|
promise: task
|
||||||
|
};
|
||||||
|
return task;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 备注:统一按当前缩放对齐首页菜单的中型站过滤和 12 级动态图层状态。
|
||||||
|
const syncZoomSensitiveState = async ({
|
||||||
|
isHydroMenu,
|
||||||
|
refreshEngPoint = false
|
||||||
|
}: {
|
||||||
|
isHydroMenu: boolean;
|
||||||
|
refreshEngPoint?: boolean;
|
||||||
|
}) => {
|
||||||
|
const currentZoom = getCurrentZoom();
|
||||||
|
if (currentZoom !== undefined) {
|
||||||
|
mapViewStore.setCurrentZoomLevel(currentZoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
return applyLayerSelection({
|
if (
|
||||||
checkedKeys: nextCheckedKeys
|
isHydroMenu &&
|
||||||
});
|
refreshEngPoint &&
|
||||||
|
mapViewStore.getCheckedLayerKeys().includes(ENG_POINT_LAYER_KEY)
|
||||||
|
) {
|
||||||
|
mapStore.refreshPointLayerDisplayData(ENG_POINT_LAYER_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
await syncHydroDynamicLayers(
|
||||||
|
!!isHydroMenu && currentZoom !== undefined && currentZoom >= 12
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 备注:统一处理地图缩放联动,收口水电开发菜单下的动态图层阈值切换逻辑。
|
// 备注:统一处理地图缩放联动,收口水电开发菜单下的动态图层阈值切换逻辑。
|
||||||
@ -419,6 +594,7 @@ export const useMapOrchestrator = () => {
|
|||||||
currentZoom <= ENG_POINT_MEDIUM_VISIBLE_ZOOM);
|
currentZoom <= ENG_POINT_MEDIUM_VISIBLE_ZOOM);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
isHydroMenu &&
|
||||||
crossedEngPointMediumThreshold &&
|
crossedEngPointMediumThreshold &&
|
||||||
mapViewStore.getCheckedLayerKeys().includes(ENG_POINT_LAYER_KEY)
|
mapViewStore.getCheckedLayerKeys().includes(ENG_POINT_LAYER_KEY)
|
||||||
) {
|
) {
|
||||||
@ -454,13 +630,10 @@ export const useMapOrchestrator = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return reloadPage(pageKey).then(async () => {
|
return reloadPage(pageKey).then(async () => {
|
||||||
const currentZoom = getCurrentZoom();
|
await syncZoomSensitiveState({
|
||||||
if (isHydroMenu && currentZoom !== undefined && currentZoom >= 12) {
|
isHydroMenu,
|
||||||
await syncHydroDynamicLayers(true);
|
refreshEngPoint: true
|
||||||
return;
|
});
|
||||||
}
|
|
||||||
|
|
||||||
await syncHydroDynamicLayers(false);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -507,10 +680,12 @@ export const useMapOrchestrator = () => {
|
|||||||
const changeBaseId = (baseId: string) => {
|
const changeBaseId = (baseId: string) => {
|
||||||
const nextBaseId = !baseId || baseId === 'all' ? '' : baseId;
|
const nextBaseId = !baseId || baseId === 'all' ? '' : baseId;
|
||||||
mapViewStore.setSelectedBaseId(nextBaseId);
|
mapViewStore.setSelectedBaseId(nextBaseId);
|
||||||
mapClass.jdPanelControlShowAndHidden(
|
if (currentMapType === '2D') {
|
||||||
baseId || 'all',
|
mapClass.jdPanelControlShowAndHidden(
|
||||||
baseId !== 'all' && !!baseId
|
baseId || 'all',
|
||||||
);
|
baseId !== 'all' && !!baseId
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 备注:统一处理时间范围变更,并触发相关图层数据重载。
|
// 备注:统一处理时间范围变更,并触发相关图层数据重载。
|
||||||
@ -570,30 +745,47 @@ export const useMapOrchestrator = () => {
|
|||||||
mapDataStore.pointData.find(pointMatcher) ||
|
mapDataStore.pointData.find(pointMatcher) ||
|
||||||
fallbackPoints.find(pointMatcher);
|
fallbackPoints.find(pointMatcher);
|
||||||
if (!targetPoint?.lgtd || !targetPoint?.lttd) return;
|
if (!targetPoint?.lgtd || !targetPoint?.lttd) return;
|
||||||
|
|
||||||
|
const legendState = String(targetPoint?.anchoPointState || '');
|
||||||
|
if (legendState && mapViewStore.getLegendChecked(legendState) !== 1) {
|
||||||
|
mapStore.updateLegendChecked(legendState, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const layerKey = String(targetPoint?.layerKey || '');
|
||||||
|
if (layerKey && mapClass.hasLayer(layerKey)) {
|
||||||
|
mapClass.mdLayerTreeShowOrHidden(layerKey, true);
|
||||||
|
}
|
||||||
|
|
||||||
mapClass.flyTopanto([targetPoint.lgtd, targetPoint.lttd], zoom);
|
mapClass.flyTopanto([targetPoint.lgtd, targetPoint.lttd], zoom);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 备注:统一释放地图页面生命周期里注册的监听,避免页面卸载后残留联动。
|
// 备注:统一释放地图页面生命周期里注册的监听,避免页面卸载后残留联动。
|
||||||
const unmountView = () => {
|
const unmountView = () => {
|
||||||
if (zoomListenerKey) {
|
if (removeZoomListener) {
|
||||||
unByKey(zoomListenerKey);
|
removeZoomListener();
|
||||||
zoomListenerKey = null;
|
removeZoomListener = null;
|
||||||
}
|
}
|
||||||
|
clearZoomSyncDebounceTimer();
|
||||||
|
|
||||||
if (stopBaseSelectionWatch) {
|
if (stopBaseSelectionWatch) {
|
||||||
stopBaseSelectionWatch();
|
stopBaseSelectionWatch();
|
||||||
stopBaseSelectionWatch = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (baseSelectionDebounceTimer.value) {
|
if (baseSelectionDebounceTimer.value) {
|
||||||
clearTimeout(baseSelectionDebounceTimer.value);
|
clearTimeout(baseSelectionDebounceTimer.value);
|
||||||
baseSelectionDebounceTimer.value = null;
|
baseSelectionDebounceTimer.value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
latestHydroMenuGetter = null;
|
||||||
|
currentMapType = '2D';
|
||||||
|
initializedBaseLayerKeys.clear();
|
||||||
|
hydroMenuDefaultCheckedKeys.clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
initialize,
|
initialize,
|
||||||
mountView,
|
mountView,
|
||||||
|
switchMapType,
|
||||||
unmountView,
|
unmountView,
|
||||||
loadPage,
|
loadPage,
|
||||||
reloadPage,
|
reloadPage,
|
||||||
|
|||||||
@ -5,6 +5,7 @@ export const useUiStore = defineStore('ui', () => {
|
|||||||
// 右侧抽屉状态
|
// 右侧抽屉状态
|
||||||
const drawerOpen = ref(true);
|
const drawerOpen = ref(true);
|
||||||
const mapType = ref('2D');
|
const mapType = ref('2D');
|
||||||
|
const mapSwitchCompletedTick = ref(0);
|
||||||
|
|
||||||
// 切换抽屉状态
|
// 切换抽屉状态
|
||||||
const toggleDrawer = () => {
|
const toggleDrawer = () => {
|
||||||
@ -16,10 +17,16 @@ export const useUiStore = defineStore('ui', () => {
|
|||||||
drawerOpen.value = open;
|
drawerOpen.value = open;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const markMapSwitchCompleted = () => {
|
||||||
|
mapSwitchCompletedTick.value += 1;
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
drawerOpen,
|
drawerOpen,
|
||||||
toggleDrawer,
|
toggleDrawer,
|
||||||
setDrawerOpen,
|
setDrawerOpen,
|
||||||
mapType
|
mapType,
|
||||||
|
mapSwitchCompletedTick,
|
||||||
|
markMapSwitchCompleted
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@ -2642,16 +2642,19 @@ const timegj = [
|
|||||||
* @param props - 锚点数据对象
|
* @param props - 锚点数据对象
|
||||||
* @returns HTML 字符串
|
* @returns HTML 字符串
|
||||||
*/
|
*/
|
||||||
export function generatePopupHtml(props: any): string {
|
export function generatePopupHtml(
|
||||||
|
props: any,
|
||||||
|
options?: {
|
||||||
|
forceEng2?: boolean;
|
||||||
|
}
|
||||||
|
): string {
|
||||||
const p = props;
|
const p = props;
|
||||||
const dzFdl = getUnitConfigByCode('Other', 'FDLYKW')?.unit;
|
const dzFdl = getUnitConfigByCode('Other', 'FDLYKW')?.unit;
|
||||||
const dzZjrl = getUnitConfigByCode('Other', 'ZJRL')?.unit;
|
const dzZjrl = getUnitConfigByCode('Other', 'ZJRL')?.unit;
|
||||||
const title = p?.ennm || p?.stnm;
|
const title = p?.ennm || p?.stnm;
|
||||||
const titleClass = getTitleClass(title);
|
const titleClass = getTitleClass(title);
|
||||||
|
|
||||||
let newsttpMap = p.sttpMap;
|
let newsttpMap = p.sttpMap;
|
||||||
console.log('newsttpMap', newsttpMap);
|
if (options?.forceEng2) {
|
||||||
if (p.qecInterval) {
|
|
||||||
newsttpMap = 'eng2';
|
newsttpMap = 'eng2';
|
||||||
}
|
}
|
||||||
let html = '';
|
let html = '';
|
||||||
@ -2714,7 +2717,7 @@ export function generatePopupHtml(props: any): string {
|
|||||||
} else {
|
} else {
|
||||||
lastTmEngEqDataVo = p.lastTmEngEqDataVo;
|
lastTmEngEqDataVo = p.lastTmEngEqDataVo;
|
||||||
}
|
}
|
||||||
if (!lastTmEngEqDataVo?.qo && !lastTmEngEqDataVo?.qi) return '';
|
// if (!lastTmEngEqDataVo?.qo && !lastTmEngEqDataVo?.qi) return '';
|
||||||
|
|
||||||
const qecLimitVal = lastTmEngEqDataVo?.qecLimit;
|
const qecLimitVal = lastTmEngEqDataVo?.qecLimit;
|
||||||
let qecLimitDisplay = '-';
|
let qecLimitDisplay = '-';
|
||||||
@ -3587,3 +3590,29 @@ export function generatePopupHtml(props: any): string {
|
|||||||
|
|
||||||
return html ? `<div>${html}</div>` : '';
|
return html ? `<div>${html}</div>` : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getNormalizedPopupSttpMap(props: any): string {
|
||||||
|
return String(props?._sttpMap || props?.sttpMap || props?.popupSttpMap || '')
|
||||||
|
.trim()
|
||||||
|
.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isEngPopupFamily(props: any): boolean {
|
||||||
|
return getNormalizedPopupSttpMap(props).startsWith('ENG');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shouldPreferEng2Popup(
|
||||||
|
props: any,
|
||||||
|
options?: {
|
||||||
|
forceEng2?: boolean;
|
||||||
|
}
|
||||||
|
): boolean {
|
||||||
|
if (options?.forceEng2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
isEngPopupFamily(props) &&
|
||||||
|
(!!props?.lastTmEngEqDataVo || !!props?.qecInterval)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -58,7 +58,6 @@ service.interceptors.response.use(
|
|||||||
message.error(response.data.msg || '请求失败');
|
message.error(response.data.msg || '请求失败');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
router.push('/login');
|
|
||||||
window.location.href = '/';
|
window.location.href = '/';
|
||||||
}, 1000);
|
}, 1000);
|
||||||
return;
|
return;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user