修改降雨栅格图显示逻辑

This commit is contained in:
wzy-warehouse
2026-05-18 21:08:43 +08:00
parent 532648ebd8
commit 133cf6d9a7
10 changed files with 157 additions and 48 deletions
+4 -1
View File
@@ -10,4 +10,7 @@ START_PORT=81
VITE_GEOSERVER_BASE_URL=http://47.92.216.173:4019/geoserver/xian
# WebSocket地址
VITE_WEBSOCKET_URL=ws://localhost:8081
VITE_WEBSOCKET_URL=http://localhost:8081/websocket
# 文件地址
VITE_FILE_URL=http://localhost:8083
+4 -1
View File
@@ -10,4 +10,7 @@ START_PORT=80
VITE_GEOSERVER_BASE_URL=http://10.22.245.246/geoserver/xian
# WebSocket地址
VITE_WEBSOCKET_URL=ws://localhost:8080
VITE_WEBSOCKET_URL=http://localhost:8080/websocket
# 文件地址
VITE_FILE_URL=http://localhost:8083
Vendored
+1
View File
@@ -12,6 +12,7 @@ interface ImportMetaEnv {
readonly START_PORT: number;
readonly VITE_GEOSERVER_BASE_URL: string;
readonly VITE_WEBSOCKET_URL: string;
readonly VITE_FILE_URL: string;
readonly MODE: string;
readonly DEV: boolean;
readonly PROD: boolean;
@@ -3,6 +3,77 @@
<div></div>
</template>
<script lang="ts" setup></script>
<script lang="ts" setup>
import { useRainstormDeduction } from '@/hooks/rainstorm/useRainstormDeduction';
import { useStatusStore } from '@/stores/useStatusStore';
import type { ApiResponse } from '@/types/ApiResponse';
import type { RainfallGridResponse } from '@/types/rainstorm/RainfallGridResponse';
import { WebSocketService } from '@/utils/request/websocket';
import { onMounted, onUnmounted, watch } from 'vue';
let rainfallWsService: WebSocketService | null = null;
const { triggerLayerShowStatus, addGridLayer } = useRainstormDeduction();
const statusStore = useStatusStore();
// 请求降雨栅格数据
const requestRainfallData = () => {
if (!rainfallWsService) {
console.error('WebSocket 服务未初始化');
return;
}
rainfallWsService.send('/app/rainfall/grid');
};
// 初始化 WebSocket 回调
onMounted(() => {
// 创建 WebSocket 实例
rainfallWsService = new WebSocketService();
// 连接成功回调
rainfallWsService.onConnected = () => {
// 订阅降雨网格数据主题
rainfallWsService!.subscribe<ApiResponse<RainfallGridResponse>>(
'/topic/rainfall/grid/messages',
(response) => {
if (response.code === 200 && response.data) {
// 显示图层
addGridLayer(response.data);
} else {
console.warn('响应错误:', response.message);
}
}
);
// 连接成功后自动请求一次数据
setTimeout(() => {
requestRainfallData();
}, 1000);
};
// 错误回调
rainfallWsService.onError = (error) => {
console.error('WebSocket 错误:', error);
};
// 自动连接
rainfallWsService.connect();
});
onUnmounted(() => {
// 销毁 WebSocket 实例
if (rainfallWsService) {
rainfallWsService.disconnect();
rainfallWsService = null;
}
});
// 监听显示隐藏
watch(
() => statusStore.weatherLayers.showRainfallGrid.show,
(newValue: boolean) => {
triggerLayerShowStatus(newValue);
}
);
</script>
<style scoped></style>
+50 -7
View File
@@ -1,11 +1,16 @@
import { useLeftLegendStore } from '@/stores/useLeftLegendStore';
import { useStatusStore } from '@/stores/useStatusStore';
import { useStepStore } from '@/stores/useStepStore';
import type { RainfallGridResponse } from '@/types/rainstorm/RainfallGridResponse';
import { CesiumUtilsSingleton } from '@/utils/cesium/CesiumUtils';
import { ImageryLayer, Rectangle, SingleTileImageryProvider } from 'cesium';
export const useRainstormDeduction = () => {
const statusStore = useStatusStore();
const leftLegendStore = useLeftLegendStore();
const stepStore = useStepStore();
let layer: ImageryLayer | null = null;
/**
* 显示步骤
*/
@@ -23,15 +28,15 @@ export const useRainstormDeduction = () => {
list: [
{
label: '无雨/微雨; <0.1mm/12h',
color: 'rgba(200,200,200,0)',
color: 'rgba(200, 200, 200, 0)',
},
{
label: '小雨;<5mm/12h',
color: 'rgba(0,0,255,0.4)',
color: 'rgba(0, 0, 255, 0.4)',
},
{
label: '中雨; <15mm/12h',
color: 'rgba(0,255,255,0.5)',
color: 'rgba(0, 255, 255, 0.5)',
},
{
label: '大雨; <30mm/12h',
@@ -39,19 +44,57 @@ export const useRainstormDeduction = () => {
},
{
label: '暴雨; <70mm/12h',
color: 'rgba(255,255,0,0.7)',
color: 'rgba(255, 255, 0, 0.7)',
},
{
label: '大暴雨; <140mm/12h',
color: 'rgba(255,165,0,0.8)',
color: 'rgba(255, 165, 0, 0.8)',
},
{
label: '特大暴雨; >140mm/12h',
color: 'rgba(255,0,0,0.9)',
color: 'rgba(255, 0, 0, 0.9)',
},
],
};
};
return { showStep, addLegend };
/**
* 添加降雨栅格图层
* @param response - 雨量栅格响应
*/
const addGridLayer = (response: RainfallGridResponse) => {
// 删除旧图层
if (layer) {
CesiumUtilsSingleton.getViewer()!.imageryLayers.remove(layer);
}
const rectangle = Rectangle.fromDegrees(
response.cesiumConfig!.rectangle.west,
response.cesiumConfig!.rectangle.south,
response.cesiumConfig!.rectangle.east,
response.cesiumConfig!.rectangle.north
);
// 创建单张影像提供器
const provider = new SingleTileImageryProvider({
url: `${import.meta.env.VITE_FILE_URL}/${response.pngPath}`.replace(
'//',
'/'
),
rectangle: rectangle,
});
layer =
CesiumUtilsSingleton.getViewer()!.imageryLayers.addImageryProvider(
provider
);
};
/**
* 触发图层显示状态
*/
const triggerLayerShowStatus = (status: boolean) => {
layer!.show = status;
};
return { showStep, addLegend, addGridLayer, triggerLayerShowStatus };
};
+2 -2
View File
@@ -183,7 +183,7 @@ export const useStatusStore = defineStore('status', () => {
/** 显示降雨栅格 */
showRainfallGrid: {
show: false,
loading: true,
loading: false,
},
});
@@ -320,7 +320,7 @@ export const useStatusStore = defineStore('status', () => {
// 气象图层显示状态重置
weatherLayers.showRainfallGrid = {
show: false,
loading: true,
loading: false,
};
// 功能显示状态重置
@@ -1,6 +0,0 @@
export interface RainfallGridRequest {
// 时间,默认为当前时间
time?: string;
// 分辨率,默认为0.01,最小为0,最大为0.1
resolution?: number;
}
+13 -22
View File
@@ -1,26 +1,17 @@
export interface RainfallFeature {
type: 'Feature';
geometry: {
type: 'Polygon';
coordinates: number[][][];
};
properties: {
rainfall: number;
color: string;
};
}
export interface RainfallGridResponse {
type: 'FeatureCollection';
features: RainfallFeature[];
metadata: {
resolution: number;
grid_size: number[];
bounds: {
min_lon: number;
max_lon: number;
min_lat: number;
max_lat: number;
id: number;
pngPath: string;
queryTime?: string;
resolution?: number;
stationCount?: number;
cesiumConfig?: {
rectangle: {
west: number;
south: number;
east: number;
north: number;
};
width?: number;
height?: number;
};
}
+1 -1
View File
@@ -3,7 +3,7 @@
*/
export interface WebSocketConfig {
/** WebSocket路径 */
url: string;
url?: string;
/** 自动重连间隔(毫秒,默认3000) */
reconnectDelay?: number;
/** 最大重连次数(默认5,-1表示无限重连) */
+10 -7
View File
@@ -16,13 +16,14 @@ export class WebSocketService {
onDisconnected?: () => void;
onError?: (error: unknown) => void;
constructor(config: WebSocketConfig) {
constructor(config?: WebSocketConfig) {
config = config || ({} as WebSocketConfig);
this.config = {
url: config.url,
reconnectDelay: config.reconnectDelay || 3000,
maxReconnectAttempts: config.maxReconnectAttempts || 5,
heartbeatIncoming: config.heartbeatIncoming || 30000,
heartbeatOutgoing: config.heartbeatOutgoing || 30000,
url: config!.url || import.meta.env.VITE_WEBSOCKET_URL,
reconnectDelay: config!.reconnectDelay || 3000,
maxReconnectAttempts: config!.maxReconnectAttempts || 5,
heartbeatIncoming: config!.heartbeatIncoming || 30000,
heartbeatOutgoing: config!.heartbeatOutgoing || 30000,
};
}
@@ -102,7 +103,7 @@ export class WebSocketService {
/**
* 发送消息到指定目的地
*/
send(destination: string, body: unknown) {
send(destination: string, body?: unknown) {
if (!this.stompClient || !this.connected) {
console.error('WebSocket 未连接');
return;
@@ -153,3 +154,5 @@ export class WebSocketService {
}
}
}
export const socketSignalInstance = new WebSocketService();