diff --git a/src/api/worn/home.js b/src/api/worn/home.js new file mode 100644 index 0000000..4303863 --- /dev/null +++ b/src/api/worn/home.js @@ -0,0 +1,43 @@ +import request from '@/utils/request' + +export function getHomeStat() { + return request({ + url: '/home/stat', + method: 'get' + }) +} + +export function getHomeDeviceStat() { + return request({ + url: '/home/device/stat', + method: 'get' + }) +} + +export function getHomeAlarmStat() { + return request({ + url: '/home/alarm/stat', + method: 'get' + }) +} + +export function getHomeAlarmTrend() { + return request({ + url: '/home/alarm/trend', + method: 'get' + }) +} + +export function getHomeAlarmType() { + return request({ + url: '/home/alarm/type', + method: 'get' + }) +} + +export function getHomeProjectList() { + return request({ + url: '/home/warehouse/list', + method: 'get' + }) +} diff --git a/src/api/worn/socket.js b/src/api/worn/socket.js new file mode 100644 index 0000000..4dd043f --- /dev/null +++ b/src/api/worn/socket.js @@ -0,0 +1,17 @@ +import request from '@/utils/request' + +// 智能排风远程开关 +export function controlSocket(data) { + const payload = { + devEui: data.devEui, + deviceId: data.deviceId, + status: data.status + } + + return request({ + url: '/worn/socket/control', + method: 'post', + params: payload, + data: payload + }) +} diff --git a/src/router/index.js b/src/router/index.js index 07302ad..ebd78d9 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -83,6 +83,19 @@ export const constantRoutes = [ meta: { title: '个人中心', icon: 'user' } } ] + }, + { + path: '/worn/warehouse-dashboard', + component: Layout, + hidden: true, + children: [ + { + path: '', + component: () => import('@/views/worn/warehouseDashboard/index'), + name: 'WarehouseDashboard', + meta: { title: '仓库传感器看板', activeMenu: '/index' } + } + ] } ] diff --git a/src/utils/ws.js b/src/utils/ws.js index 4278df6..310c26f 100644 --- a/src/utils/ws.js +++ b/src/utils/ws.js @@ -1,72 +1,29 @@ import { getToken } from '@/utils/auth' -/** - * 当前 WebSocket 实例 - */ let ws = null - -/** - * 重连定时器 - */ let reconnectTimer = null - -/** - * 是否人为关闭(用于区分主动关闭 vs 异常断开) - */ let manualClose = false - -/** - * 当前连接的部门ID(用于断线重连) - */ -let currentDeptId = null - -/** - * 当前消息回调函数 - */ let currentOnMessage = null +let retryCount = 0 -/** - * WebSocket路径 - */ const WS_PATH = '/ws' +const MAX_RECONNECT_DELAY = 30000 -/** - * 重连间隔(毫秒) - */ -const RECONNECT_INTERVAL = 5000 - -/** - * 获取 WebSocket 基础地址 - * 适配: - * 1. VITE_APP_BASE_API 是完整URL(http://xxx) - * 2. VITE_APP_BASE_API 是相对路径(/dev-api) - */ function getWsBaseUrl() { const baseApi = import.meta.env.VITE_APP_BASE_API || '' - // 如果是完整URL(http/https) if (/^https?:\/\//.test(baseApi)) { - // 转换为 ws/wss return baseApi.replace(/^http/, 'ws').replace(/\/$/, '') } - // 根据当前页面协议自动判断 ws / wss const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:' return `${protocol}//${window.location.host}${baseApi}`.replace(/\/$/, '') } -/** - * 构建 WebSocket 连接地址 - * @param deptId 部门ID(用于数据隔离) - */ -function buildWsUrl(deptId) { +function buildWsUrl() { const url = new URL(`${getWsBaseUrl()}${WS_PATH}`) const token = getToken() - // 当前后端仍依赖 deptId 做数据隔离 - url.searchParams.set('deptId', deptId) - - // token 用于后续鉴权升级(预留) if (token) { url.searchParams.set('token', token) } @@ -74,88 +31,59 @@ function buildWsUrl(deptId) { return url.toString() } -/** - * 建立 WebSocket 连接 - * @param deptId 当前用户部门ID - * @param onMessage 消息回调函数 - */ -export function connectWs(deptId, onMessage) { - // 必须传 deptId(当前后端依赖) - if (!deptId) { - console.warn('[WebSocket] 缺少 deptId') +export function connectWs(onMessage) { + if (!getToken()) { + console.warn('[WebSocket] missing token') return } - currentDeptId = deptId currentOnMessage = onMessage manualClose = false - - // 清除旧的重连任务 clearReconnectTimer() - // 如果已经连接或正在连接,直接返回(防止重复连接) if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) { return } - // 创建 WebSocket 连接 - ws = new WebSocket(buildWsUrl(deptId)) + ws = new WebSocket(buildWsUrl()) - /** - * 连接成功 - */ ws.onopen = () => { - console.log('[WebSocket] 连接成功 deptId=', deptId) + retryCount = 0 + console.log('[WebSocket] connected') } - /** - * 收到消息 - */ ws.onmessage = (event) => { let data = event.data - // 尝试解析 JSON try { data = JSON.parse(event.data) } catch (e) { - // 非JSON消息保持原样 + // Keep plain text messages as-is. } - // 回调给业务层 currentOnMessage && currentOnMessage(data, event) } - /** - * 连接关闭 - */ ws.onclose = () => { - console.log('[WebSocket] 连接关闭 deptId=', currentDeptId) + console.log('[WebSocket] closed') ws = null - // 非人为关闭 → 自动重连 if (!manualClose) { reconnectTimer = setTimeout(() => { - console.log('[WebSocket] 开始重连 deptId=', currentDeptId) - connectWs(currentDeptId, currentOnMessage) - }, RECONNECT_INTERVAL) + console.log('[WebSocket] reconnecting') + connectWs(currentOnMessage) + }, getReconnectDelay()) } } - /** - * 连接异常 - */ ws.onerror = (error) => { - console.error('[WebSocket] 连接异常', error) + console.error('[WebSocket] error', error) } } -/** - * 主动关闭 WebSocket - */ export function closeWs() { manualClose = true - - // 清除重连任务 + retryCount = 0 clearReconnectTimer() if (ws) { @@ -164,36 +92,34 @@ export function closeWs() { } } -/** - * 发送消息 - * @param data 支持字符串或对象 - * @returns 是否发送成功 - */ +export function reconnectWs(onMessage = currentOnMessage) { + closeWs() + manualClose = false + connectWs(onMessage) +} + export function sendWs(data) { - // 连接未就绪直接返回 if (!ws || ws.readyState !== WebSocket.OPEN) { - console.warn('[WebSocket] 发送失败,连接未建立') + console.warn('[WebSocket] send failed, socket is not open') return false } - // 自动转JSON ws.send(typeof data === 'string' ? data : JSON.stringify(data)) return true } -/** - * 获取当前连接状态 - */ export function getWsState() { return ws ? ws.readyState : WebSocket.CLOSED } -/** - * 清除重连定时器 - */ +function getReconnectDelay() { + retryCount += 1 + return Math.min(5000 * retryCount, MAX_RECONNECT_DELAY) +} + function clearReconnectTimer() { if (reconnectTimer) { clearTimeout(reconnectTimer) reconnectTimer = null } -} \ No newline at end of file +} diff --git a/src/views/index.vue b/src/views/index.vue index 4c1ac56..4fba2bb 100644 --- a/src/views/index.vue +++ b/src/views/index.vue @@ -1,10 +1,1504 @@ + diff --git a/src/views/worn/warehouseDashboard/index.vue b/src/views/worn/warehouseDashboard/index.vue new file mode 100644 index 0000000..e6d8e2a --- /dev/null +++ b/src/views/worn/warehouseDashboard/index.vue @@ -0,0 +1,1157 @@ + + + + +