warehouse P0修复: http.js(lang_storage_key)+SignalR内存泄漏(LRU)+Pinia store合并(7文件import同步)+Camera type导入修复
This commit is contained in:
@@ -38,6 +38,8 @@ if (!axios.defaults.baseURL.endsWith('/')) {
|
|||||||
axios.defaults.baseURL += '/'
|
axios.defaults.baseURL += '/'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const lang_storage_key = 'lang'
|
||||||
|
|
||||||
let ipAddress = axios.defaults.baseURL;
|
let ipAddress = axios.defaults.baseURL;
|
||||||
if (!ipAddress || ipAddress == '/') {
|
if (!ipAddress || ipAddress == '/') {
|
||||||
ipAddress = window.location.origin + '/';
|
ipAddress = window.location.origin + '/';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { watch, computed } from "vue"
|
import { watch, computed } from "vue"
|
||||||
import { useMapStore } from "../store/useMapStore"
|
import { useMapStore } from "../stores/mapStore"
|
||||||
|
|
||||||
// 可以使用pinia等管理全局数据,这里只是方便演示, 直接注入了上层提供的数据
|
// 可以使用pinia等管理全局数据,这里只是方便演示, 直接注入了上层提供的数据
|
||||||
const store = useMapStore()
|
const store = useMapStore()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from "vue"
|
import { computed } from "vue"
|
||||||
import { useNavi } from "../hooks/useNavi"
|
import { useNavi } from "../hooks/useNavi"
|
||||||
import { useMapStore } from "../store/useMapStore"
|
import { useMapStore } from "../stores/mapStore"
|
||||||
|
|
||||||
// 可以使用pinia等管理全局数据,这里只是方便演示, 直接注入了上层提供的数据
|
// 可以使用pinia等管理全局数据,这里只是方便演示, 直接注入了上层提供的数据
|
||||||
const store = useMapStore()
|
const store = useMapStore()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { inject, onBeforeUnmount } from "vue"
|
import { inject, onBeforeUnmount } from "vue"
|
||||||
import { useFence } from "../hooks/useFence"
|
import { useFence } from "../hooks/useFence"
|
||||||
import { useMapStore } from "../store/useMapStore"
|
import { useMapStore } from "../stores/mapStore"
|
||||||
|
|
||||||
const { THREE } = VgoMap
|
const { THREE } = VgoMap
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { inject, ref, watch, onBeforeUnmount } from "vue"
|
import { inject, ref, watch, onBeforeUnmount } from "vue"
|
||||||
import { useClassPolygon } from "../hooks/useClassPolygon"
|
import { useClassPolygon } from "../hooks/useClassPolygon"
|
||||||
import { useMapStore } from "../store/useMapStore"
|
import { useMapStore } from "../stores/mapStore"
|
||||||
import http from "../api/http"
|
import http from "../api/http"
|
||||||
|
|
||||||
const { THREE } = VgoMap
|
const { THREE } = VgoMap
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch, onBeforeUnmount } from "vue"
|
import { ref, watch, onBeforeUnmount } from "vue"
|
||||||
import { useSkyLight } from "../hooks/useSkyLight"
|
import { useSkyLight } from "../hooks/useSkyLight"
|
||||||
import { useMapStore } from "../store/useMapStore"
|
import { useMapStore } from "../stores/mapStore"
|
||||||
import CustomSwitch from "./CustomSwitch.vue"
|
import CustomSwitch from "./CustomSwitch.vue"
|
||||||
|
|
||||||
const store = useMapStore()
|
const store = useMapStore()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch } from "vue"
|
import { ref, watch } from "vue"
|
||||||
import { useWeatherEffect, WeatherType } from "../hooks/useWeather"
|
import { useWeatherEffect, WeatherType } from "../hooks/useWeather"
|
||||||
import { useMapStore } from "../store/useMapStore"
|
import { useMapStore } from "../stores/mapStore"
|
||||||
import CustomSwitch from "./CustomSwitch.vue"
|
import CustomSwitch from "./CustomSwitch.vue"
|
||||||
|
|
||||||
const store = useMapStore()
|
const store = useMapStore()
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
import { ref, computed } from "vue"
|
|
||||||
import { defineStore } from "pinia"
|
|
||||||
|
|
||||||
export const useMapStore = defineStore('map', () => {
|
|
||||||
const map = ref(null)
|
|
||||||
|
|
||||||
const polygonDataAll = computed(() => {
|
|
||||||
const outDoor = map.value?.mapData?.polygonData ?? []
|
|
||||||
|
|
||||||
const inDoor = map?.mapData?.build?.reduce((result, build) => {
|
|
||||||
build.floor.forEach(fItem => {
|
|
||||||
result.push(...fItem.polygonData)
|
|
||||||
})
|
|
||||||
return result
|
|
||||||
}, []) ?? []
|
|
||||||
|
|
||||||
return [...outDoor, ...inDoor]
|
|
||||||
})
|
|
||||||
|
|
||||||
function setMap(mapInstance) {
|
|
||||||
map.value = mapInstance
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
map,
|
|
||||||
polygonDataAll,
|
|
||||||
setMap,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,48 +1,34 @@
|
|||||||
import { ref } from "vue"
|
import { ref, computed } from "vue"
|
||||||
import { defineStore } from "pinia"
|
import { defineStore } from "pinia"
|
||||||
|
|
||||||
export const useMapStore = defineStore('map', () => {
|
export const useMapStore = defineStore('map', () => {
|
||||||
const map = ref(null)
|
const map = ref(null)
|
||||||
const lastClickedPosition = ref(null) // 存储地图最后点击位置的经纬度
|
const lastClickedPosition = ref(null)
|
||||||
const editingMode = ref(false) // 编辑状态标识
|
const editingMode = ref(false)
|
||||||
|
|
||||||
function setMap(mapInstance) {
|
/** 聚合所有楼层+室外的 polygonData */
|
||||||
map.value = mapInstance
|
const polygonDataAll = computed(() => {
|
||||||
}
|
const outDoor = map.value?.mapData?.polygonData ?? []
|
||||||
|
const builds = map.value?.mapData?.build ?? []
|
||||||
|
const inDoor = builds.reduce((result, build) => {
|
||||||
|
build.floor?.forEach(f => { result.push(...(f.polygonData ?? [])) })
|
||||||
|
return result
|
||||||
|
}, [])
|
||||||
|
return [...outDoor, ...inDoor]
|
||||||
|
})
|
||||||
|
|
||||||
// 设置地图最后点击位置的经纬度
|
function setMap(mapInstance) { map.value = mapInstance }
|
||||||
function setLastClickedPosition(lng, lat) {
|
function setLastClickedPosition(lng, lat) { lastClickedPosition.value = { lng, lat } }
|
||||||
lastClickedPosition.value = { lng, lat }
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置编辑状态
|
|
||||||
function setEditingMode(mode) {
|
function setEditingMode(mode) {
|
||||||
editingMode.value = mode
|
editingMode.value = mode
|
||||||
if(mode){
|
map.value?.setViewMode(mode ? '2D' : '3D')
|
||||||
map.value.setViewMode('2D')
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
map.value.setViewMode('3D')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取编辑状态
|
|
||||||
function getEditingMode() {
|
|
||||||
if(editingMode.value){
|
|
||||||
return editingMode.value
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
function getEditingMode() { return editingMode.value }
|
||||||
|
|
||||||
return {
|
return {
|
||||||
map,
|
map, setMap,
|
||||||
setMap,
|
lastClickedPosition, setLastClickedPosition,
|
||||||
lastClickedPosition,
|
editingMode, setEditingMode, getEditingMode,
|
||||||
setLastClickedPosition,
|
polygonDataAll,
|
||||||
editingMode,
|
|
||||||
setEditingMode,
|
|
||||||
getEditingMode
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import Sky from "../components/Sky.vue"
|
|||||||
import DisplayColor from "../components/DisplayColor.vue"
|
import DisplayColor from "../components/DisplayColor.vue"
|
||||||
import DisplayRouteLine from "../components/DisplayRouteLine.vue"
|
import DisplayRouteLine from "../components/DisplayRouteLine.vue"
|
||||||
import Weather from "../components/Weather.vue"
|
import Weather from "../components/Weather.vue"
|
||||||
import { useMapStore } from "../store/useMapStore"
|
import { useMapStore } from "../stores/mapStore"
|
||||||
|
|
||||||
const { VgoMap } = window
|
const { VgoMap } = window
|
||||||
let mapId = /#\/(\d+)/.exec(location.hash)[1]
|
let mapId = /#\/(\d+)/.exec(location.hash)[1]
|
||||||
|
|||||||
@@ -2,89 +2,60 @@ import * as signalR from "@microsoft/signalr";
|
|||||||
import { ElNotification } from "element-plus";
|
import { ElNotification } from "element-plus";
|
||||||
import { ElMessageBox } from "element-plus";
|
import { ElMessageBox } from "element-plus";
|
||||||
import store from "@/store/index";
|
import store from "@/store/index";
|
||||||
|
|
||||||
export default function (http, receive) {
|
export default function (http, receive) {
|
||||||
let connection;
|
let connection
|
||||||
|
|
||||||
let messageQueue = [];
|
// LRU: 最近 500 条 ID,防内存无限增长
|
||||||
let isProcessingQueue = false;
|
const MAX_IDS = 500
|
||||||
let displayedMessageIds = new Set(); // 用于存储已显示的消息ID,避免重复显示
|
const displayedIds = new Set()
|
||||||
|
const idList = []
|
||||||
|
|
||||||
// 消息队列处理函数 - 移到闭包内部,确保可以访问所有必要的变量
|
function addId(id) {
|
||||||
function processMessageQueue() {
|
if (displayedIds.has(id)) return
|
||||||
if (messageQueue.length === 0) {
|
displayedIds.add(id)
|
||||||
isProcessingQueue = false;
|
idList.push(id)
|
||||||
return;
|
if (idList.length > MAX_IDS) {
|
||||||
|
displayedIds.delete(idList.shift())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
function hasId(id) { return displayedIds.has(id) }
|
||||||
|
|
||||||
isProcessingQueue = true;
|
// 重试启动: 最多 5 次, 间隔 2s
|
||||||
const currentMessage = messageQueue.shift();
|
async function startWithRetry(conn, retries = 5) {
|
||||||
|
for (let i = 1; i <= retries; i++) {
|
||||||
// 直接调用receive回调处理消息显示
|
try { await conn.start(); return }
|
||||||
if (receive) {
|
catch (e) { if (i < retries) await new Promise(r => setTimeout(r, 2000)) }
|
||||||
try {
|
|
||||||
receive(currentMessage);
|
|
||||||
console.log('成功调用receive回调处理消息:', currentMessage);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('调用receive回调时出错:', error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
console.error('SignalR 连接失败 (5次重试后放弃)')
|
||||||
// 可以设置一定的延迟,避免消息显示过于密集
|
|
||||||
setTimeout(() => {
|
|
||||||
processMessageQueue();
|
|
||||||
}, 3000); // 3秒后处理下一条消息
|
|
||||||
}
|
}
|
||||||
|
|
||||||
http.post("api/user/GetCurrentUserInfo").then((result) => {
|
http.post("api/user/GetCurrentUserInfo").then(async (result) => {
|
||||||
console.log(result,'result');
|
if (!result?.data?.userName) {
|
||||||
|
console.error('获取用户信息失败: 缺少 userName')
|
||||||
|
return
|
||||||
|
}
|
||||||
connection = new signalR.HubConnectionBuilder()
|
connection = new signalR.HubConnectionBuilder()
|
||||||
.withAutomaticReconnect()
|
.withAutomaticReconnect()
|
||||||
.withUrl(
|
.withUrl('/hub/message?userName=' + result.data.userName)
|
||||||
`/hub/message?userName=${result.data.userName}`,
|
.build()
|
||||||
{
|
|
||||||
//withCredentials: true // 启用凭证模式
|
startWithRetry(connection)
|
||||||
// accessTokenFactory: () => store.getters.getToken()
|
|
||||||
}
|
connection.onreconnected(function (id) {
|
||||||
)
|
if (import.meta.env.DEV) console.log('SignalR reconnected:', id)
|
||||||
//.withUrl(`${http.ipAddress}message`)
|
})
|
||||||
.build();
|
|
||||||
|
|
||||||
connection.start().catch((err) => console.log(err.message));
|
|
||||||
//自动重连成功后的处理
|
|
||||||
connection.onreconnected((connectionId) => {
|
|
||||||
console.log(connectionId, 'connectionId');
|
|
||||||
});
|
|
||||||
connection.on("ReceiveHomePageMessage", function (data) {
|
connection.on("ReceiveHomePageMessage", function (data) {
|
||||||
console.log('接收到新消息:', data);
|
if (data?.id && hasId(data.id)) return
|
||||||
|
if (data?.id) addId(data.id)
|
||||||
// 检查消息是否已显示过
|
|
||||||
if (data.id && displayedMessageIds.has(data.id)) {
|
|
||||||
console.log('消息已显示过,跳过:', data.id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将消息ID添加到已显示集合
|
|
||||||
if (data.id) {
|
|
||||||
displayedMessageIds.add(data.id);
|
|
||||||
console.log('添加到已显示集合:', data.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加到store
|
|
||||||
// store.getters.data().pushMessage(data);
|
|
||||||
console.log(data, 'data_after_push');
|
|
||||||
// 直接调用receive回调
|
|
||||||
if (receive) {
|
if (receive) {
|
||||||
try {
|
try { receive(data) }
|
||||||
receive(data);
|
catch (e) { console.error('receive callback error:', e) }
|
||||||
console.log('成功调用receive回调:', data);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('调用receive回调时出错:', error);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.warn('receive回调未定义,无法处理消息');
|
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}).catch(error => {
|
}).catch(function (e) {
|
||||||
console.error('获取用户信息时出错:', error);
|
console.error('getUserInfo failed:', e)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,8 @@
|
|||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
import { VideoPlay } from '@element-plus/icons-vue'
|
import { VideoPlay } from '@element-plus/icons-vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { fetchCameras, gwGet, Camera } from '@/api/gateway'
|
import { fetchCameras, gwGet } from '@/api/gateway'
|
||||||
|
import type { Camera } from '@/api/gateway'
|
||||||
|
|
||||||
const cameras = ref<Camera[]>([])
|
const cameras = ref<Camera[]>([])
|
||||||
const selectedCamera = ref<Camera | null>(null)
|
const selectedCamera = ref<Camera | null>(null)
|
||||||
|
|||||||
@@ -92,7 +92,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
import { VideoCamera } from '@element-plus/icons-vue'
|
import { VideoCamera } from '@element-plus/icons-vue'
|
||||||
import { fetchCameras, gwGet, gwPost, Camera } from '@/api/gateway'
|
import { fetchCameras, gwGet, gwPost } from '@/api/gateway'
|
||||||
|
import type { Camera } from '@/api/gateway'
|
||||||
|
|
||||||
const cameras = ref<Camera[]>([])
|
const cameras = ref<Camera[]>([])
|
||||||
const selectedCamera = ref<Camera | null>(null)
|
const selectedCamera = ref<Camera | null>(null)
|
||||||
|
|||||||
@@ -106,7 +106,8 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, onMounted, watch } from 'vue'
|
import { ref, computed, onMounted, watch } from 'vue'
|
||||||
import { fetchCameras, gwGet, gwPost, Camera } from '@/api/gateway'
|
import { fetchCameras, gwGet, gwPost } from '@/api/gateway'
|
||||||
|
import type { Camera } from '@/api/gateway'
|
||||||
|
|
||||||
const cameras = ref<Camera[]>([])
|
const cameras = ref<Camera[]>([])
|
||||||
const streamUrls = ref<Record<string, string>>({})
|
const streamUrls = ref<Record<string, string>>({})
|
||||||
|
|||||||
Reference in New Issue
Block a user