diff --git a/src/App.vue b/src/App.vue index e698776..a964565 100644 --- a/src/App.vue +++ b/src/App.vue @@ -46,6 +46,13 @@ systemUpgrade() // 获取用户信息 getUserInfo() + // 初始化 WebSocket + const { accessToken } = useUserStore() + // if (accessToken) { + // import('@/utils/sys/wsClient').then(({ initWebSocket }) => { + // initWebSocket(accessToken) + // }) + // } }) // 获取用户信息 diff --git a/src/api/usersApi.ts b/src/api/usersApi.ts index 04929a1..44fac2e 100644 --- a/src/api/usersApi.ts +++ b/src/api/usersApi.ts @@ -85,4 +85,11 @@ export class UserService { params }) } + //离职分配 + static leaveUser(params: any) { + return request.get({ + url: '/admin/crm/customer/allocation', + params + }) + } } diff --git a/src/components/core/tables/ArtTableHeader.vue b/src/components/core/tables/ArtTableHeader.vue index 74e235d..c977247 100644 --- a/src/components/core/tables/ArtTableHeader.vue +++ b/src/components/core/tables/ArtTableHeader.vue @@ -4,6 +4,7 @@
+
@@ -68,7 +69,6 @@ }}
- diff --git a/src/utils/sys/wsClient.ts b/src/utils/sys/wsClient.ts new file mode 100644 index 0000000..1c98797 --- /dev/null +++ b/src/utils/sys/wsClient.ts @@ -0,0 +1,124 @@ +import mittBus from './mittBus' +import { useUserStore } from '@/store/modules/user' + +type JsonValue = Record | any[] + +const WS_BASE = 'wss://mzl.dev.hnxinyouhe.com/ws?token=' + +let socket: WebSocket | null = null +let reconnectTimer: any = null +let heartbeatTimer: any = null +let reconnectAttempts = 0 +const maxReconnectDelayMs = 30000 +const heartbeatIntervalMs = 30000 + +const getReconnectDelay = () => { + const base = 1000 * Math.pow(2, reconnectAttempts) + return Math.min(base, maxReconnectDelayMs) +} + +const cleanup = () => { + if (reconnectTimer) { + clearTimeout(reconnectTimer) + reconnectTimer = null + } + if (heartbeatTimer) { + clearTimeout(heartbeatTimer) + heartbeatTimer = null + } +} + +const startHeartbeat = () => { + // 清理上一次的心跳 + if (heartbeatTimer) { + clearTimeout(heartbeatTimer) + heartbeatTimer = null + } + // 递归 setTimeout,确保固定间隔执行 + heartbeatTimer = setTimeout(() => { + try { + if (socket && socket.readyState === WebSocket.OPEN) { + socket.send(JSON.stringify({ type: 'ping' })) + } + } catch (_) {} + // 下一次心跳 + startHeartbeat() + }, heartbeatIntervalMs) +} + +const scheduleReconnect = () => { + cleanup() + const delay = getReconnectDelay() + reconnectTimer = setTimeout(() => { + const { accessToken } = useUserStore() + if (accessToken) initWebSocket(accessToken) + }, delay) +} + +export const initWebSocket = (token: string) => { + try { + if (!token) return + if (socket) { + try { + socket.close() + } catch (_) {} + socket = null + } + cleanup() + + const url = `${WS_BASE}${token}` + socket = new WebSocket(url) + + socket.onopen = () => { + reconnectAttempts = 0 + startHeartbeat() + mittBus.emit('ws:open') + try { + socket?.send(JSON.stringify({ type: 'ping' })) + } catch (_) {} + } + + socket.onmessage = (event) => { + const dataStr = event.data + let data: any = dataStr + try { + data = JSON.parse(dataStr) + } catch (_) {} + mittBus.emit('ws:message', data) + } + + socket.onerror = (err) => { + mittBus.emit('ws:error', err) + } + + socket.onclose = () => { + mittBus.emit('ws:close') + reconnectAttempts += 1 + scheduleReconnect() + } + } catch (e) { + mittBus.emit('ws:error', e) + scheduleReconnect() + } +} + +export const closeWebSocket = () => { + cleanup() + try { + socket?.close() + } catch (_) {} + socket = null +} + +export const sendWebSocket = (payload: string | JsonValue) => { + if (!socket || socket.readyState !== WebSocket.OPEN) return false + try { + const data = typeof payload === 'string' ? payload : JSON.stringify(payload) + socket.send(data) + return true + } catch (_) { + return false + } +} + + diff --git a/src/views/admin/customer/customeraudit.vue b/src/views/admin/customer/customeraudit.vue index 03de504..d3887bb 100644 --- a/src/views/admin/customer/customeraudit.vue +++ b/src/views/admin/customer/customeraudit.vue @@ -70,20 +70,80 @@
- - - + + +
+
+ 标记原因: + {{ reportRemark || '-' }} +
+
+ 附件说明: +
+
+ + + 下载 +
+
+ +
+
+ + -
+
取消 确定
+ +