This commit is contained in:
zx
2026-04-20 08:59:03 +08:00
6 changed files with 2753 additions and 103 deletions

43
src/api/worn/home.js Normal file
View File

@@ -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'
})
}

17
src/api/worn/socket.js Normal file
View File

@@ -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
})
}

View File

@@ -83,6 +83,19 @@ export const constantRoutes = [
meta: { title: '个人中心', icon: 'user' } 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' }
}
]
} }
] ]

View File

@@ -1,72 +1,29 @@
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
/**
* 当前 WebSocket 实例
*/
let ws = null let ws = null
/**
* 重连定时器
*/
let reconnectTimer = null let reconnectTimer = null
/**
* 是否人为关闭(用于区分主动关闭 vs 异常断开)
*/
let manualClose = false let manualClose = false
/**
* 当前连接的部门ID用于断线重连
*/
let currentDeptId = null
/**
* 当前消息回调函数
*/
let currentOnMessage = null let currentOnMessage = null
let retryCount = 0
/**
* WebSocket路径
*/
const WS_PATH = '/ws' const WS_PATH = '/ws'
const MAX_RECONNECT_DELAY = 30000
/**
* 重连间隔(毫秒)
*/
const RECONNECT_INTERVAL = 5000
/**
* 获取 WebSocket 基础地址
* 适配:
* 1. VITE_APP_BASE_API 是完整URLhttp://xxx
* 2. VITE_APP_BASE_API 是相对路径(/dev-api
*/
function getWsBaseUrl() { function getWsBaseUrl() {
const baseApi = import.meta.env.VITE_APP_BASE_API || '' const baseApi = import.meta.env.VITE_APP_BASE_API || ''
// 如果是完整URLhttp/https
if (/^https?:\/\//.test(baseApi)) { if (/^https?:\/\//.test(baseApi)) {
// 转换为 ws/wss
return baseApi.replace(/^http/, 'ws').replace(/\/$/, '') return baseApi.replace(/^http/, 'ws').replace(/\/$/, '')
} }
// 根据当前页面协议自动判断 ws / wss
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:' const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
return `${protocol}//${window.location.host}${baseApi}`.replace(/\/$/, '') return `${protocol}//${window.location.host}${baseApi}`.replace(/\/$/, '')
} }
/** function buildWsUrl() {
* 构建 WebSocket 连接地址
* @param deptId 部门ID用于数据隔离
*/
function buildWsUrl(deptId) {
const url = new URL(`${getWsBaseUrl()}${WS_PATH}`) const url = new URL(`${getWsBaseUrl()}${WS_PATH}`)
const token = getToken() const token = getToken()
// 当前后端仍依赖 deptId 做数据隔离
url.searchParams.set('deptId', deptId)
// token 用于后续鉴权升级(预留)
if (token) { if (token) {
url.searchParams.set('token', token) url.searchParams.set('token', token)
} }
@@ -74,88 +31,59 @@ function buildWsUrl(deptId) {
return url.toString() return url.toString()
} }
/** export function connectWs(onMessage) {
* 建立 WebSocket 连接 if (!getToken()) {
* @param deptId 当前用户部门ID console.warn('[WebSocket] missing token')
* @param onMessage 消息回调函数
*/
export function connectWs(deptId, onMessage) {
// 必须传 deptId当前后端依赖
if (!deptId) {
console.warn('[WebSocket] 缺少 deptId')
return return
} }
currentDeptId = deptId
currentOnMessage = onMessage currentOnMessage = onMessage
manualClose = false manualClose = false
// 清除旧的重连任务
clearReconnectTimer() clearReconnectTimer()
// 如果已经连接或正在连接,直接返回(防止重复连接)
if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) { if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) {
return return
} }
// 创建 WebSocket 连接 ws = new WebSocket(buildWsUrl())
ws = new WebSocket(buildWsUrl(deptId))
/**
* 连接成功
*/
ws.onopen = () => { ws.onopen = () => {
console.log('[WebSocket] 连接成功 deptId=', deptId) retryCount = 0
console.log('[WebSocket] connected')
} }
/**
* 收到消息
*/
ws.onmessage = (event) => { ws.onmessage = (event) => {
let data = event.data let data = event.data
// 尝试解析 JSON
try { try {
data = JSON.parse(event.data) data = JSON.parse(event.data)
} catch (e) { } catch (e) {
// 非JSON消息保持原样 // Keep plain text messages as-is.
} }
// 回调给业务层
currentOnMessage && currentOnMessage(data, event) currentOnMessage && currentOnMessage(data, event)
} }
/**
* 连接关闭
*/
ws.onclose = () => { ws.onclose = () => {
console.log('[WebSocket] 连接关闭 deptId=', currentDeptId) console.log('[WebSocket] closed')
ws = null ws = null
// 非人为关闭 → 自动重连
if (!manualClose) { if (!manualClose) {
reconnectTimer = setTimeout(() => { reconnectTimer = setTimeout(() => {
console.log('[WebSocket] 开始重连 deptId=', currentDeptId) console.log('[WebSocket] reconnecting')
connectWs(currentDeptId, currentOnMessage) connectWs(currentOnMessage)
}, RECONNECT_INTERVAL) }, getReconnectDelay())
} }
} }
/**
* 连接异常
*/
ws.onerror = (error) => { ws.onerror = (error) => {
console.error('[WebSocket] 连接异常', error) console.error('[WebSocket] error', error)
} }
} }
/**
* 主动关闭 WebSocket
*/
export function closeWs() { export function closeWs() {
manualClose = true manualClose = true
retryCount = 0
// 清除重连任务
clearReconnectTimer() clearReconnectTimer()
if (ws) { if (ws) {
@@ -164,33 +92,31 @@ export function closeWs() {
} }
} }
/** export function reconnectWs(onMessage = currentOnMessage) {
* 发送消息 closeWs()
* @param data 支持字符串或对象 manualClose = false
* @returns 是否发送成功 connectWs(onMessage)
*/ }
export function sendWs(data) { export function sendWs(data) {
// 连接未就绪直接返回
if (!ws || ws.readyState !== WebSocket.OPEN) { if (!ws || ws.readyState !== WebSocket.OPEN) {
console.warn('[WebSocket] 发送失败,连接未建立') console.warn('[WebSocket] send failed, socket is not open')
return false return false
} }
// 自动转JSON
ws.send(typeof data === 'string' ? data : JSON.stringify(data)) ws.send(typeof data === 'string' ? data : JSON.stringify(data))
return true return true
} }
/**
* 获取当前连接状态
*/
export function getWsState() { export function getWsState() {
return ws ? ws.readyState : WebSocket.CLOSED return ws ? ws.readyState : WebSocket.CLOSED
} }
/** function getReconnectDelay() {
* 清除重连定时器 retryCount += 1
*/ return Math.min(5000 * retryCount, MAX_RECONNECT_DELAY)
}
function clearReconnectTimer() { function clearReconnectTimer() {
if (reconnectTimer) { if (reconnectTimer) {
clearTimeout(reconnectTimer) clearTimeout(reconnectTimer)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff