diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 94cefa4f..2f9b0654 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -19,5 +19,8 @@ module.exports = { rules: { // override/add rules settings here, such as: + }, + globals: { + NodeJS: 'readonly' } }; \ No newline at end of file diff --git a/package.json b/package.json index 2dc2ae7d..ea1e9abf 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@commitlint/config-conventional": "^17.4.0", "@types/lodash-es": "^4.17.6", "@types/moment": "^2.13.0", - "@types/node": "^18.11.17", + "@types/node": "^18.14.0", "@vitejs/plugin-vue": "^4.0.0", "@vuemap/unplugin-resolver": "^1.0.4", "autoprefixer": "^10.4.13", diff --git a/src/api/comm.ts b/src/api/comm.ts index 29cf4f11..563871fb 100644 --- a/src/api/comm.ts +++ b/src/api/comm.ts @@ -27,4 +27,11 @@ export const deleteSearchHistory = (target:string, id:string) => server.remove server.get<{edition?: string}>('/system/version') \ No newline at end of file +export const systemVersion = () => server.get<{edition?: string}>('/system/version') + +/** + * 聚合查询 + * @param data + * @returns + */ +export const queryDashboard = (data: Record) => server.post(`/dashboard/_multi`, data) \ No newline at end of file diff --git a/src/api/device/instance.ts b/src/api/device/instance.ts index 0d73ffb4..10c0321d 100644 --- a/src/api/device/instance.ts +++ b/src/api/device/instance.ts @@ -314,3 +314,29 @@ export const getGatewayDetail = (id: string) => server.get(`/gateway/device/${id * @returns 单位列表 */ export const getUnit = () => server.get(`/protocol/units`) + +/** + * 执行功能 + * @param deviceId 设备id + * @param functionId 功能id + * @param data + * @returns + */ +export const executeFunctions = (deviceId: string, functionId: string, data: any) => server.post(`/device/invoked/${deviceId}/function/${functionId}`, data) + +/** + * 读取属性 + * @param deviceId 设备id + * @param data + * @returns + */ +export const readProperties = (deviceId: string, data: any) => server.post(`/device/instance/${deviceId}/properties/_read`, data) + +/** + * 设置属性 + * @param deviceId 设备id + * @param data + * @returns + */ +export const settingProperties = (deviceId: string, data: any) => server.put(`/device/instance/${deviceId}/property`, data) + diff --git a/src/utils/websocket.ts b/src/utils/websocket.ts new file mode 100644 index 00000000..0bd4547a --- /dev/null +++ b/src/utils/websocket.ts @@ -0,0 +1,127 @@ +import { Observable } from 'rxjs' +import { BASE_API_PATH } from '@/utils/variable'; +import { notification } from 'ant-design-vue'; +import { getToken } from '@/utils/comm'; + +let ws: any = null +let count = 0 // 重连计数 +let timer: NodeJS.Timeout = null +let lockReconnect = false // 避免重复连接 +const total = 100 // 重连总次数 +const subs = {} +const timeout = 5000 +const tempQueue: any[] = [] // websocket未连接上时,缓存消息列 + +export const initWebSocket = () => { + if (ws) { + return ws + } + const token = getToken() + const url = `${document.location.protocol.replace('http', 'ws')}//${document.location.host}${BASE_API_PATH}/messaging/${token}?:X_Access_Token=${token}`; + if (count < total) { + count += 1 + ws = new WebSocket(url) + + ws.onopen = () => { + count = 0 + timer = setInterval(heartCheck, 2000) + if (tempQueue.length > 0) { + for (let i = tempQueue.length - 1; i >= 0; i--) { + ws.send(tempQueue[i]) + tempQueue.splice(i, 1) + } + } + } + + ws.onclose = () => { + console.log('onerror', count) + ws = null + reconnect() + } + + ws.onmessage = (msg: Record) => { + const data = JSON.parse(msg.data) + + if (data.type === 'error') { + notification.error({ key: 'wserr', message: data.message }) + } + + if (subs[data.requestId]) { + if (data.type === 'complete') { + subs[data.requestId].forEach((item: Record) => { + item.complete() + }) + } else if (data.type === 'result') { + subs[data.requestId].forEach((element: Record) => { + element.next(data) + }) + } + } + } + + ws.onerror = () => { + console.log('onerror', count) + ws = null + reconnect() + } + + return ws + } +} + +export const getWebSocket = (id: string, topic: string, parameter: Record) => new Observable(subscriber => { + if (!subs[id]) { + subs[id] = [] + } + + subs[id].push({ + next(val: Record) { + subscriber.next(val) + }, + complete() { + subscriber.complete() + } + }) + + const msg = JSON.stringify({ id, topic, parameter, type: 'sub' }) + const thisWs = initWebSocket() + if (thisWs) { + if (thisWs.readyState === WebSocket.OPEN) { + thisWs.send(msg) + } else { + tempQueue.push(msg) + } + } + + return () => { + const unsub = JSON.stringify({ id, type: 'unsub' }) + delete subs[id] + if (thisWs) { + thisWs.send(unsub) + } + } +}) + +/** + * 重连 + */ +function reconnect() { + timer && clearInterval(timer) + if (lockReconnect) { + return + } + lockReconnect = true + timer = setTimeout(() => { + initWebSocket() + lockReconnect = false + }, timeout * count) +} + +/** + * 心跳检测 + */ +function heartCheck() { + if (ws) { + ws.send(JSON.stringify({ type: 'ping' })) + } +} \ No newline at end of file diff --git a/src/views/device/Instance/Detail/Diagnose/Message/Function/EditTable.vue b/src/views/device/Instance/Detail/Diagnose/Message/Function/EditTable.vue index 975d91fd..5aa519c6 100644 --- a/src/views/device/Instance/Detail/Diagnose/Message/Function/EditTable.vue +++ b/src/views/device/Instance/Detail/Diagnose/Message/Function/EditTable.vue @@ -72,18 +72,9 @@ const columns = [ }, ]; -// const dataSource = ref[]>(_props.modelValue || []); - const dataSource = computed({ get: () => { - return _props.modelValue || { - messageType: undefined, - message: { - properties: undefined, - functionId: undefined, - inputs: [] - } - } + return _props.modelValue || [] }, set: (val: any) => { _emit('update:modelValue', val); diff --git a/src/views/device/Instance/Detail/Diagnose/Message/Function/index.vue b/src/views/device/Instance/Detail/Diagnose/Message/Function/index.vue index 32462129..e9b3d049 100644 --- a/src/views/device/Instance/Detail/Diagnose/Message/Function/index.vue +++ b/src/views/device/Instance/Detail/Diagnose/Message/Function/index.vue @@ -1,60 +1,118 @@