签字不显示问题
This commit is contained in:
@@ -35,22 +35,58 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
//前端唯一标识 当然后端还有用户id作为唯一标识
|
// 二维码携带本次组件实例的标识,与服务端当前登录用户共同确定签字记录。
|
||||||
id: new Date().getTime() + Math.floor(Math.random() * 10000) + 1,
|
id: new Date().getTime() + Math.floor(Math.random() * 10000) + 1,
|
||||||
signatureAddress: null,
|
signatureAddress: null,
|
||||||
interval: null,
|
interval: null,
|
||||||
|
connectionWaitResolve: null,
|
||||||
|
unsubscribeSignature: null,
|
||||||
signatureContent: null,
|
signatureContent: null,
|
||||||
loading: true,
|
loading: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async init() {
|
/**
|
||||||
const {code, data} = await this.$axios.post("/platform/signature/get")
|
* 无请求参数,返回 Promise;响应 code 为0表示成功,data.signature 为已有签字图片地址。
|
||||||
if (code === 0) {
|
* 请求结束后由 mounted 的 finally 统一关闭 loading。
|
||||||
this.signatureContent = data && data.signature
|
*/
|
||||||
this.$emit("input", this.signatureContent)
|
init() {
|
||||||
}
|
|
||||||
this.signatureAddress = origin + "/platform/signature/scanPcCode?id=" + this.id
|
this.signatureAddress = origin + "/platform/signature/scanPcCode?id=" + this.id
|
||||||
|
return this.$axios.post("/platform/signature/get")
|
||||||
|
.then((res) => {
|
||||||
|
if (this._isBeingDestroyed || this._isDestroyed) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (res.code !== 0) {
|
||||||
|
throw new Error("签字信息加载失败")
|
||||||
|
}
|
||||||
|
this.signatureContent = res.data && res.data.signature
|
||||||
|
this.$emit("input", this.signatureContent)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 返回等待完成的 Promise;连接成功、等待30秒或组件销毁时结束等待。
|
||||||
|
waitForConnection() {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const startedAt = Date.now()
|
||||||
|
this.connectionWaitResolve = resolve
|
||||||
|
const checkReady = () => {
|
||||||
|
this.interval = null
|
||||||
|
if (this._isBeingDestroyed || this._isDestroyed ||
|
||||||
|
(webSocketPubSub.ws && webSocketPubSub.ws.readyState === WebSocket.OPEN)) {
|
||||||
|
this.connectionWaitResolve = null
|
||||||
|
resolve()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (Date.now() - startedAt >= 30000) {
|
||||||
|
this.connectionWaitResolve = null
|
||||||
|
this.$message.warning("签字消息连接超时,请刷新页面重试")
|
||||||
|
resolve()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.interval = setTimeout(checkReady, 100)
|
||||||
|
}
|
||||||
|
checkReady()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
signatureAgain() {
|
signatureAgain() {
|
||||||
const val = sessionStorage.getItem("h5-scan-code-signature-" + this.id)
|
const val = sessionStorage.getItem("h5-scan-code-signature-" + this.id)
|
||||||
@@ -58,25 +94,42 @@ module.exports = {
|
|||||||
this.$emit("input", val)
|
this.$emit("input", val)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted() {
|
mounted() {
|
||||||
await this.init()
|
this.loading = true
|
||||||
webSocketPubSub.subscribe("h5-scan-code-signature", (data) => {
|
// 先登记消息回调,连接成功后由公共连接加入房间,避免请求期间遗漏订阅。
|
||||||
console.info("ws:收到签字成功消息:", data)
|
this.unsubscribeSignature = webSocketPubSub.subscribe("h5-scan-code-signature", (data) => {
|
||||||
this.signatureContent = data.value
|
this.signatureContent = data.value
|
||||||
this.$emit("input", data.value)
|
this.$emit("input", data.value)
|
||||||
})
|
})
|
||||||
|
this.init()
|
||||||
// 可选:轮询或 watch ready 状态
|
.then(() => {
|
||||||
const checkReady = () => {
|
if (!this._isBeingDestroyed && !this._isDestroyed) {
|
||||||
if (webSocketPubSub.ws && webSocketPubSub.ws.readyState === WebSocket.OPEN) {
|
return this.waitForConnection()
|
||||||
console.info("ws.readyState is open");
|
}
|
||||||
this.loading = false;
|
})
|
||||||
console.log(this.signatureAddress)
|
.catch(() => {
|
||||||
} else {
|
if (!this._isBeingDestroyed && !this._isDestroyed) {
|
||||||
setTimeout(checkReady, 100);
|
this.$message.error("签字信息加载失败,请刷新页面重试")
|
||||||
}
|
}
|
||||||
};
|
})
|
||||||
checkReady();
|
.finally(() => {
|
||||||
|
if (!this._isBeingDestroyed && !this._isDestroyed) {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
// pjax 切换页面时取消轮询和订阅,旧组件不得继续接收签字消息。
|
||||||
|
clearTimeout(this.interval)
|
||||||
|
this.interval = null
|
||||||
|
if (this.connectionWaitResolve) {
|
||||||
|
this.connectionWaitResolve()
|
||||||
|
this.connectionWaitResolve = null
|
||||||
|
}
|
||||||
|
if (this.unsubscribeSignature) {
|
||||||
|
this.unsubscribeSignature()
|
||||||
|
this.unsubscribeSignature = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -443,50 +443,76 @@
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.ws = null
|
this.ws = null
|
||||||
this.subscribers = new Map()
|
this.subscribers = new Map()
|
||||||
this.isSubscribed = false // 添加订阅状态标记
|
this.isSubscribed = false
|
||||||
|
this.connectTimer = null
|
||||||
|
this.reconnectTimer = null
|
||||||
|
this.pingTimer = null
|
||||||
|
this.isDisposed = false
|
||||||
this.init()
|
this.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 页面只创建一个心跳任务;每次连接自行绑定事件及握手超时。
|
||||||
init() {
|
init() {
|
||||||
|
this.setupWindowEvents()
|
||||||
|
this.setupPing()
|
||||||
|
this.connect()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 正在连接或关闭时等待对应事件,避免同时创建多个连接。
|
||||||
|
connect() {
|
||||||
|
if (this.isDisposed || this.reconnectTimer !== null ||
|
||||||
|
(this.ws && this.ws.readyState !== WebSocket.CLOSED)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
this.connect()
|
const WS_URL = window.location.host + "${base}/websocket"
|
||||||
|
const protocol = window.location.protocol === "http:" ? "ws://" : "wss://"
|
||||||
|
this.ws = new WebSocket(protocol + WS_URL)
|
||||||
|
this.isSubscribed = false
|
||||||
this.setupEventListeners()
|
this.setupEventListeners()
|
||||||
this.setupPing()
|
const socket = this.ws
|
||||||
this.setupWindowEvents()
|
// 握手最多等待30秒,心跳不得提前关闭仍处于 CONNECTING 的连接。
|
||||||
} catch (ex) {
|
this.connectTimer = setTimeout(() => {
|
||||||
console.info(ex)
|
this.connectTimer = null
|
||||||
|
if (this.ws === socket && socket.readyState === WebSocket.CONNECTING) {
|
||||||
|
console.warn("WebSocket 握手超时,关闭当前连接后重试", socket.url)
|
||||||
|
socket.close()
|
||||||
|
}
|
||||||
|
}, 30000)
|
||||||
|
} catch (error) {
|
||||||
|
console.error("WebSocket 创建连接失败", error)
|
||||||
|
this.reconnect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
connect() {
|
/**
|
||||||
const WS_URL = window.location.host + "${base}/websocket"
|
* type 为消息 action 名称,callback 接收服务端消息对象;返回取消本次订阅的方法。
|
||||||
const protocol = window.location.protocol === "http:" ? "ws://" : "wss://"
|
* 连接尚未建立时先保留回调,在 onopen 中统一加入当前用户的消息房间。
|
||||||
this.ws = new WebSocket(protocol + WS_URL)
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
//订阅
|
|
||||||
subscribe(type, callback) {
|
subscribe(type, callback) {
|
||||||
if (!this.subscribers.has(type)) {
|
if (!this.subscribers.has(type)) {
|
||||||
this.subscribers.set(type, new Set())
|
this.subscribers.set(type, new Set())
|
||||||
}
|
}
|
||||||
this.subscribers.get(type).add(callback)
|
const callbacks = this.subscribers.get(type)
|
||||||
|
callbacks.add(callback)
|
||||||
setTimeout(() => {
|
this.sendJoinMessage()
|
||||||
// 所有订阅完成后,发送 join 消息
|
return () => {
|
||||||
if (!this.isSubscribed && this.ws.readyState === WebSocket.OPEN) {
|
callbacks.delete(callback)
|
||||||
this.isSubscribed = true
|
if (callbacks.size === 0 && this.subscribers.get(type) === callbacks) {
|
||||||
this.sendJoinMessage()
|
this.subscribers.delete(type)
|
||||||
}
|
}
|
||||||
}, 2000)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 事件处理
|
// 事件绑定到本次连接,旧连接的延迟事件不得影响新连接。
|
||||||
setupEventListeners() {
|
setupEventListeners() {
|
||||||
// 消息处理
|
const socket = this.ws
|
||||||
this.ws.onmessage = (event) => {
|
socket.onmessage = (event) => {
|
||||||
|
if (this.isDisposed || this.ws !== socket) {
|
||||||
|
return
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(event.data)
|
const data = JSON.parse(event.data)
|
||||||
// 触发订阅者的回调
|
|
||||||
if (this.subscribers.has(data.action)) {
|
if (this.subscribers.has(data.action)) {
|
||||||
this.subscribers.get(data.action).forEach((callback) => {
|
this.subscribers.get(data.action).forEach((callback) => {
|
||||||
try {
|
try {
|
||||||
@@ -500,82 +526,112 @@
|
|||||||
console.error("消息解析错误:", error)
|
console.error("消息解析错误:", error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
socket.onopen = () => {
|
||||||
// 连接建立
|
if (this.isDisposed || this.ws !== socket) {
|
||||||
this.ws.onopen = () => {
|
return
|
||||||
// this.ws.send(
|
|
||||||
// JSON.stringify({
|
|
||||||
// room: store.state.room,
|
|
||||||
// action: "join"
|
|
||||||
// })
|
|
||||||
// )
|
|
||||||
// 连接建立时不立即发送 join,等待订阅完成
|
|
||||||
this.ping()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 新增发送 join 消息的方法
|
|
||||||
sendJoinMessage() {
|
|
||||||
this.send({
|
|
||||||
room: store.state.room,
|
|
||||||
action: "join"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 心跳检测
|
|
||||||
setupPing() {
|
|
||||||
setInterval(() => this.ping(), (11624317 / 1000) * 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
ping() {
|
|
||||||
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
||||||
try {
|
|
||||||
this.ws.send("{}")
|
|
||||||
} catch (e) {
|
|
||||||
this.reconnect()
|
|
||||||
}
|
}
|
||||||
} else {
|
clearTimeout(this.connectTimer)
|
||||||
|
this.connectTimer = null
|
||||||
|
this.sendJoinMessage()
|
||||||
|
this.ping()
|
||||||
|
console.info("WebSocket 连接已建立", socket.url)
|
||||||
|
}
|
||||||
|
socket.onerror = () => {
|
||||||
|
if (!this.isDisposed && this.ws === socket) {
|
||||||
|
console.warn("WebSocket 连接异常,等待关闭后重连", socket.url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
socket.onclose = (event) => {
|
||||||
|
if (this.isDisposed || this.ws !== socket) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
clearTimeout(this.connectTimer)
|
||||||
|
this.connectTimer = null
|
||||||
|
this.isSubscribed = false
|
||||||
|
console.warn("WebSocket 已关闭", event.code, event.reason)
|
||||||
this.reconnect()
|
this.reconnect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 每个已建立的连接只加入一次房间,首次连接及断线恢复都补发已有订阅。
|
||||||
|
sendJoinMessage() {
|
||||||
|
if (this.isDisposed || this.isSubscribed || this.subscribers.size === 0 ||
|
||||||
|
!window.store || !store.state.room || !this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.send({
|
||||||
|
room: store.state.room,
|
||||||
|
action: "join"
|
||||||
|
})
|
||||||
|
this.isSubscribed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 沿用原心跳间隔,仅对已建立的连接发送心跳。
|
||||||
|
setupPing() {
|
||||||
|
this.pingTimer = setInterval(() => this.ping(), (11624317 / 1000) * 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CONNECTING/CLOSING 状态分别由握手超时和关闭事件处理。
|
||||||
|
ping() {
|
||||||
|
if (this.isDisposed) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
||||||
|
try {
|
||||||
|
this.ws.send("{}")
|
||||||
|
} catch (error) {
|
||||||
|
console.warn("WebSocket 心跳发送失败,等待关闭后重连", error)
|
||||||
|
this.ws.close()
|
||||||
|
}
|
||||||
|
} else if (!this.ws || this.ws.readyState === WebSocket.CLOSED) {
|
||||||
|
this.reconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭事件和心跳共用一个重连任务,避免重复定时器创建并行连接。
|
||||||
reconnect() {
|
reconnect() {
|
||||||
if (this.ws) {
|
if (this.isDisposed || this.reconnectTimer !== null ||
|
||||||
this.ws.close() // 确保旧连接已关闭
|
(this.ws && this.ws.readyState !== WebSocket.CLOSED)) {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
this.reconnectTimer = setTimeout(() => {
|
||||||
|
this.reconnectTimer = null
|
||||||
this.connect()
|
this.connect()
|
||||||
this.setupEventListeners()
|
}, 3000)
|
||||||
// 如果之前已订阅,重新发送join消息
|
|
||||||
if (this.isSubscribed) {
|
|
||||||
setTimeout(() => {
|
|
||||||
if (this.ws.readyState === WebSocket.OPEN) {
|
|
||||||
this.sendJoinMessage()
|
|
||||||
}
|
|
||||||
}, 1000)
|
|
||||||
}
|
|
||||||
}, 3000) // 延迟3秒重连
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 窗口事件处理
|
// 真正离开页面时释放连接和定时器;进入往返缓存时保留页面状态。
|
||||||
setupWindowEvents() {
|
setupWindowEvents() {
|
||||||
let _beforeUnload_time = 0
|
window.addEventListener("pagehide", (event) => {
|
||||||
window.onbeforeunload = () => {
|
if (event.persisted) {
|
||||||
_beforeUnload_time = new Date().getTime()
|
return
|
||||||
}
|
|
||||||
window.onunload = () => {
|
|
||||||
const _gap_time = new Date().getTime() - _beforeUnload_time
|
|
||||||
if (_gap_time <= 5) {
|
|
||||||
this.send({
|
|
||||||
room: "${@auth.getPrincipalProperty('loginname')}:${@auth.getSessionId()}",
|
|
||||||
action: "left"
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
this.isDisposed = true
|
||||||
|
clearTimeout(this.connectTimer)
|
||||||
|
clearTimeout(this.reconnectTimer)
|
||||||
|
clearInterval(this.pingTimer)
|
||||||
|
this.connectTimer = null
|
||||||
|
this.reconnectTimer = null
|
||||||
|
this.pingTimer = null
|
||||||
|
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
||||||
|
try {
|
||||||
|
this.send({
|
||||||
|
room: store.state.room,
|
||||||
|
action: "left"
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.warn("WebSocket 离开房间消息发送失败", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.ws && this.ws.readyState !== WebSocket.CLOSED) {
|
||||||
|
this.ws.close()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// message 为消息对象或 JSON 字符串;连接未建立时不发送,返回值为 undefined。
|
||||||
send(message) {
|
send(message) {
|
||||||
if (this.ws) {
|
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
||||||
const messageStr = typeof message === "string" ? message : JSON.stringify(message)
|
const messageStr = typeof message === "string" ? message : JSON.stringify(message)
|
||||||
this.ws.send(messageStr)
|
this.ws.send(messageStr)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -154,51 +154,76 @@
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.ws = null
|
this.ws = null
|
||||||
this.subscribers = new Map()
|
this.subscribers = new Map()
|
||||||
this.isSubscribed = false // 添加订阅状态标记
|
this.isSubscribed = false
|
||||||
|
this.connectTimer = null
|
||||||
|
this.reconnectTimer = null
|
||||||
|
this.pingTimer = null
|
||||||
|
this.isDisposed = false
|
||||||
this.init()
|
this.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 页面只创建一个心跳任务;每次连接自行绑定事件及握手超时。
|
||||||
init() {
|
init() {
|
||||||
|
this.setupWindowEvents()
|
||||||
|
this.setupPing()
|
||||||
|
this.connect()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 正在连接或关闭时等待对应事件,避免同时创建多个连接。
|
||||||
|
connect() {
|
||||||
|
if (this.isDisposed || this.reconnectTimer !== null ||
|
||||||
|
(this.ws && this.ws.readyState !== WebSocket.CLOSED)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
this.connect()
|
const WS_URL = window.location.host + "${base}/websocket"
|
||||||
|
const protocol = window.location.protocol === "http:" ? "ws://" : "wss://"
|
||||||
|
this.ws = new WebSocket(protocol + WS_URL)
|
||||||
|
this.isSubscribed = false
|
||||||
this.setupEventListeners()
|
this.setupEventListeners()
|
||||||
this.setupPing()
|
const socket = this.ws
|
||||||
this.setupWindowEvents()
|
// 握手最多等待30秒,心跳不得提前关闭仍处于 CONNECTING 的连接。
|
||||||
} catch (ex) {
|
this.connectTimer = setTimeout(() => {
|
||||||
console.info(ex)
|
this.connectTimer = null
|
||||||
|
if (this.ws === socket && socket.readyState === WebSocket.CONNECTING) {
|
||||||
|
console.warn("WebSocket 握手超时,关闭当前连接后重试", socket.url)
|
||||||
|
socket.close()
|
||||||
|
}
|
||||||
|
}, 30000)
|
||||||
|
} catch (error) {
|
||||||
|
console.error("WebSocket 创建连接失败", error)
|
||||||
|
this.reconnect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
connect() {
|
/**
|
||||||
const WS_URL = window.location.host + "${base}/websocket"
|
* type 为消息 action 名称,callback 接收服务端消息对象;返回取消本次订阅的方法。
|
||||||
// const WS_URL = 'zhgh.jshvc.edu.cn' + "${base}/websocket"
|
* 连接尚未建立时先保留回调,在 onopen 中统一加入当前用户的消息房间。
|
||||||
const protocol = window.location.protocol === "http:" ? "ws://" : "wss://"
|
*/
|
||||||
this.ws = new WebSocket(protocol + WS_URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
//订阅
|
|
||||||
subscribe(type, callback) {
|
subscribe(type, callback) {
|
||||||
if (!this.subscribers.has(type)) {
|
if (!this.subscribers.has(type)) {
|
||||||
this.subscribers.set(type, new Set())
|
this.subscribers.set(type, new Set())
|
||||||
}
|
}
|
||||||
this.subscribers.get(type).add(callback)
|
const callbacks = this.subscribers.get(type)
|
||||||
|
callbacks.add(callback)
|
||||||
setTimeout(() => {
|
this.sendJoinMessage()
|
||||||
// 所有订阅完成后,发送 join 消息
|
return () => {
|
||||||
if (!this.isSubscribed && this.ws.readyState === WebSocket.OPEN) {
|
callbacks.delete(callback)
|
||||||
this.isSubscribed = true
|
if (callbacks.size === 0 && this.subscribers.get(type) === callbacks) {
|
||||||
this.sendJoinMessage()
|
this.subscribers.delete(type)
|
||||||
}
|
}
|
||||||
}, 1000)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 事件处理
|
// 事件绑定到本次连接,旧连接的延迟事件不得影响新连接。
|
||||||
setupEventListeners() {
|
setupEventListeners() {
|
||||||
// 消息处理
|
const socket = this.ws
|
||||||
this.ws.onmessage = (event) => {
|
socket.onmessage = (event) => {
|
||||||
|
if (this.isDisposed || this.ws !== socket) {
|
||||||
|
return
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(event.data)
|
const data = JSON.parse(event.data)
|
||||||
// 触发订阅者的回调
|
|
||||||
if (this.subscribers.has(data.action)) {
|
if (this.subscribers.has(data.action)) {
|
||||||
this.subscribers.get(data.action).forEach((callback) => {
|
this.subscribers.get(data.action).forEach((callback) => {
|
||||||
try {
|
try {
|
||||||
@@ -212,83 +237,112 @@
|
|||||||
console.error("消息解析错误:", error)
|
console.error("消息解析错误:", error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
socket.onopen = () => {
|
||||||
// 连接建立
|
if (this.isDisposed || this.ws !== socket) {
|
||||||
this.ws.onopen = () => {
|
return
|
||||||
// this.ws.send(
|
|
||||||
// JSON.stringify({
|
|
||||||
// room: store.state.room,
|
|
||||||
// action: "join"
|
|
||||||
// })
|
|
||||||
// )
|
|
||||||
// 连接建立时不立即发送 join,等待订阅完成
|
|
||||||
this.ping()
|
|
||||||
console.info('websocket open success')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 新增发送 join 消息的方法
|
|
||||||
sendJoinMessage() {
|
|
||||||
this.send({
|
|
||||||
room: store.state.room,
|
|
||||||
action: "join"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 心跳检测
|
|
||||||
setupPing() {
|
|
||||||
setInterval(() => this.ping(), (11624317 / 1000) * 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
ping() {
|
|
||||||
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
||||||
try {
|
|
||||||
this.ws.send("{}")
|
|
||||||
} catch (e) {
|
|
||||||
this.reconnect()
|
|
||||||
}
|
}
|
||||||
} else {
|
clearTimeout(this.connectTimer)
|
||||||
|
this.connectTimer = null
|
||||||
|
this.sendJoinMessage()
|
||||||
|
this.ping()
|
||||||
|
console.info("WebSocket 连接已建立", socket.url)
|
||||||
|
}
|
||||||
|
socket.onerror = () => {
|
||||||
|
if (!this.isDisposed && this.ws === socket) {
|
||||||
|
console.warn("WebSocket 连接异常,等待关闭后重连", socket.url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
socket.onclose = (event) => {
|
||||||
|
if (this.isDisposed || this.ws !== socket) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
clearTimeout(this.connectTimer)
|
||||||
|
this.connectTimer = null
|
||||||
|
this.isSubscribed = false
|
||||||
|
console.warn("WebSocket 已关闭", event.code, event.reason)
|
||||||
this.reconnect()
|
this.reconnect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 每个已建立的连接只加入一次房间,首次连接及断线恢复都补发已有订阅。
|
||||||
|
sendJoinMessage() {
|
||||||
|
if (this.isDisposed || this.isSubscribed || this.subscribers.size === 0 ||
|
||||||
|
!window.store || !store.state.room || !this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.send({
|
||||||
|
room: store.state.room,
|
||||||
|
action: "join"
|
||||||
|
})
|
||||||
|
this.isSubscribed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 沿用原心跳间隔,仅对已建立的连接发送心跳。
|
||||||
|
setupPing() {
|
||||||
|
this.pingTimer = setInterval(() => this.ping(), (11624317 / 1000) * 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CONNECTING/CLOSING 状态分别由握手超时和关闭事件处理。
|
||||||
|
ping() {
|
||||||
|
if (this.isDisposed) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
||||||
|
try {
|
||||||
|
this.ws.send("{}")
|
||||||
|
} catch (error) {
|
||||||
|
console.warn("WebSocket 心跳发送失败,等待关闭后重连", error)
|
||||||
|
this.ws.close()
|
||||||
|
}
|
||||||
|
} else if (!this.ws || this.ws.readyState === WebSocket.CLOSED) {
|
||||||
|
this.reconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭事件和心跳共用一个重连任务,避免重复定时器创建并行连接。
|
||||||
reconnect() {
|
reconnect() {
|
||||||
if (this.ws) {
|
if (this.isDisposed || this.reconnectTimer !== null ||
|
||||||
this.ws.close() // 确保旧连接已关闭
|
(this.ws && this.ws.readyState !== WebSocket.CLOSED)) {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
this.reconnectTimer = setTimeout(() => {
|
||||||
|
this.reconnectTimer = null
|
||||||
this.connect()
|
this.connect()
|
||||||
this.setupEventListeners()
|
}, 1000)
|
||||||
// 如果之前已订阅,重新发送join消息
|
|
||||||
if (this.isSubscribed) {
|
|
||||||
setTimeout(() => {
|
|
||||||
if (this.ws.readyState === WebSocket.OPEN) {
|
|
||||||
this.sendJoinMessage()
|
|
||||||
}
|
|
||||||
}, 500)
|
|
||||||
}
|
|
||||||
}, 1000) // 延迟2秒重连
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 窗口事件处理
|
// 真正离开页面时释放连接和定时器;进入往返缓存时保留页面状态。
|
||||||
setupWindowEvents() {
|
setupWindowEvents() {
|
||||||
let _beforeUnload_time = 0
|
window.addEventListener("pagehide", (event) => {
|
||||||
window.onbeforeunload = () => {
|
if (event.persisted) {
|
||||||
_beforeUnload_time = new Date().getTime()
|
return
|
||||||
}
|
|
||||||
window.onunload = () => {
|
|
||||||
const _gap_time = new Date().getTime() - _beforeUnload_time
|
|
||||||
if (_gap_time <= 5) {
|
|
||||||
this.send({
|
|
||||||
room: "${@auth.getPrincipalProperty('loginname')}:${@auth.getSessionId()}",
|
|
||||||
action: "left"
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
this.isDisposed = true
|
||||||
|
clearTimeout(this.connectTimer)
|
||||||
|
clearTimeout(this.reconnectTimer)
|
||||||
|
clearInterval(this.pingTimer)
|
||||||
|
this.connectTimer = null
|
||||||
|
this.reconnectTimer = null
|
||||||
|
this.pingTimer = null
|
||||||
|
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
||||||
|
try {
|
||||||
|
this.send({
|
||||||
|
room: store.state.room,
|
||||||
|
action: "left"
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.warn("WebSocket 离开房间消息发送失败", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.ws && this.ws.readyState !== WebSocket.CLOSED) {
|
||||||
|
this.ws.close()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// message 为消息对象或 JSON 字符串;连接未建立时不发送,返回值为 undefined。
|
||||||
send(message) {
|
send(message) {
|
||||||
if (this.ws) {
|
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
||||||
const messageStr = typeof message === "string" ? message : JSON.stringify(message)
|
const messageStr = typeof message === "string" ? message : JSON.stringify(message)
|
||||||
this.ws.send(messageStr)
|
this.ws.send(messageStr)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user