diff --git a/common/ieApi.js b/common/ieApi.js index 7115b3a..84c850b 100644 --- a/common/ieApi.js +++ b/common/ieApi.js @@ -9,8 +9,25 @@ function unwrap(res) { return res.result !== undefined ? res.result : res } +function unwrapIeHome(res) { + if (!res) return null + if (res.success === false) { + const message = res.message || '请求失败' + if (message.indexOf('i/e 身份已被封禁') !== -1 || message.indexOf('ie 身份已被封禁') !== -1) { + return { banned: true, message } + } + uni.showToast({ title: message, icon: 'none' }) + return null + } + return res.result !== undefined ? res.result : res +} + export function ieHome() { - return tui.request('/app/ie/home', 'GET', {}, false, false, true).then(unwrap) + return tui.request('/app/ie/home', 'GET', {}, false, false, true).then(unwrapIeHome) +} + +export function getIeUnreadCount() { + return tui.request('/app/ie/unread-count', 'GET', {}, false, true, true).then(unwrap) } export function updateIeStatus(data) { @@ -104,3 +121,50 @@ export function pageIeReports(pageNumber = 1, pageSize = 10) { export function pageIeBlocks(pageNumber = 1, pageSize = 10) { return tui.request('/app/ie/blocks/page', 'GET', { pageNumber, pageSize }, false, true, true).then(unwrap) } + +export function getIeRoomStreak(roomId) { + return tui.request(`/app/ie/rooms/${roomId}/streak`, 'GET', {}, false, true, true).then(unwrap) +} + +export function startIeQuiz(roomId) { + return tui.request(`/app/ie/rooms/${roomId}/quiz/start`, 'POST', {}, false, false, true).then(unwrap) +} + +export function getIeQuizCurrent(roomId) { + return tui.request(`/app/ie/rooms/${roomId}/quiz/current`, 'GET', {}, false, true, true).then(unwrap) +} + +export function answerIeQuiz(roomId, answers) { + return tui.request(`/app/ie/rooms/${roomId}/quiz/answer`, 'POST', { answers }, false, false, true).then(unwrap) +} + +export function getIeDailyQuestion() { + return tui.request('/app/ie/daily-question/today', 'GET', {}, false, true, true).then(unwrap) +} + +export function answerIeDailyQuestion(content) { + return tui.request('/app/ie/daily-question/answer', 'POST', { content }, false, false, false).then(unwrap) +} + +export function pageIeDailyAnswers(pageNumber = 1, pageSize = 10) { + return tui.request('/app/ie/daily-question/answers/page', 'GET', { pageNumber, pageSize }, false, true, true).then(unwrap) +} + +export function matchIeByAnswer(answerId) { + return tui.request(`/app/ie/daily-question/answers/${answerId}/match`, 'POST', {}, false, false, false).then(unwrap) +} + +export function publishIeMoment(data) { + return tui.request('/app/ie/moments', 'POST', data, false, false, false).then(unwrap) +} + +export function pageIeMoments(userId, pageNumber = 1, pageSize = 10, roomId = '') { + const params = { pageNumber, pageSize } + if (userId) params.userId = userId + if (roomId) params.roomId = roomId + return tui.request('/app/ie/moments/page', 'GET', params, false, true, true).then(unwrap) +} + +export function deleteIeMoment(momentId) { + return tui.request(`/app/ie/moments/${momentId}`, 'DELETE', {}, false, false, true).then(unwrap) +} diff --git a/common/ieSocket.js b/common/ieSocket.js index 3eacf19..06d5f47 100644 --- a/common/ieSocket.js +++ b/common/ieSocket.js @@ -6,6 +6,10 @@ const socket = { heartbeatTimer: null, subscriptions: {}, connecting: false, + manualClosed: false, + reconnectTimer: null, + reconnectAttempts: 0, + roomIds: [], messageHandlers: [], ackHandlers: [], presenceHandlers: [], @@ -66,7 +70,9 @@ function subscribe(destination, id) { } function subscribeRoom(roomId) { - if (!socket.connected || !socket.task || !roomId) return false + if (!roomId) return false + if (socket.roomIds.indexOf(roomId) < 0) socket.roomIds.push(roomId) + if (!socket.connected || !socket.task) return false const id = 'ie-room-' + roomId if (socket.subscriptions[id]) return true socket.subscriptions[id] = true @@ -74,6 +80,12 @@ function subscribeRoom(roomId) { return true } +function unsubscribeRoom(roomId) { + const index = socket.roomIds.indexOf(roomId) + if (index > -1) socket.roomIds.splice(index, 1) + delete socket.subscriptions['ie-room-' + roomId] +} + function bindSubscriptions() { subscribe('/user/queue/ie/ack', 'ie-ack') subscribe('/user/queue/ie/message', 'ie-message') @@ -81,6 +93,25 @@ function bindSubscriptions() { subscribe('/user/queue/ie/room-end', 'ie-room-end') subscribe('/user/queue/ie/offline', 'ie-offline') send('/app/ie/connect') + // 重连后恢复房间订阅 + socket.roomIds.forEach(roomId => { + const id = 'ie-room-' + roomId + if (!socket.subscriptions[id]) { + socket.subscriptions[id] = true + subscribe('/topic/ie/room/' + roomId, id) + } + }) +} + +function scheduleReconnect() { + if (socket.manualClosed || socket.reconnectTimer) return + // 指数退避:2s/4s/8s/16s/30s 封顶 + const delay = Math.min(2000 * Math.pow(2, socket.reconnectAttempts), 30000) + socket.reconnectAttempts += 1 + socket.reconnectTimer = setTimeout(() => { + socket.reconnectTimer = null + connect().catch(() => scheduleReconnect()) + }, delay) } function handleMessage(raw) { @@ -88,6 +119,8 @@ function handleMessage(raw) { const data = parseFrame(raw) if (data.command === 'CONNECTED') { socket.connected = true + socket.reconnectAttempts = 0 + socket.subscriptions = {} bindSubscriptions() startHeartbeat() return @@ -113,6 +146,7 @@ function startHeartbeat() { function connect() { if (socket.connected || socket.connecting) return Promise.resolve() socket.connecting = true + socket.manualClosed = false return new Promise((resolve, reject) => { socket.task = uni.connectSocket({ url: wsUrl(), @@ -134,17 +168,27 @@ function connect() { socket.task.onClose(() => { socket.connected = false socket.connecting = false + socket.subscriptions = {} clearInterval(socket.heartbeatTimer) + scheduleReconnect() }) socket.task.onError(() => { socket.connected = false socket.connecting = false + socket.subscriptions = {} clearInterval(socket.heartbeatTimer) + scheduleReconnect() }) }) } function close() { + socket.manualClosed = true + clearTimeout(socket.reconnectTimer) + socket.reconnectTimer = null + socket.reconnectAttempts = 0 + socket.roomIds = [] + socket.subscriptions = {} clearInterval(socket.heartbeatTimer) if (socket.task) socket.task.close() socket.connected = false @@ -164,6 +208,7 @@ export default { close, resetHandlers, subscribeRoom, + unsubscribeRoom, sendMessage(data) { return send('/app/ie/message', data) }, sendPresence(data) { return send('/app/ie/presence', data) }, onAck(handler) { socket.ackHandlers.push(handler) },