From 750f25410cd94258be3f34ec67530a313c794d1f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 9 May 2026 15:23:07 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(im):=20=E5=9F=BA=E4=BA=8E=20li?= =?UTF-8?q?vekit=20=E6=9E=84=E5=BB=BA=20im=20=E9=80=9A=E8=AF=9D=EF=BC=88?= =?UTF-8?q?=E8=AF=AD=E9=9F=B3=E8=81=8A=E5=A4=A9=E3=80=81=E8=A7=86=E9=A2=91?= =?UTF-8?q?=E8=81=8A=E5=A4=A9=E3=80=81=E5=85=B1=E4=BA=AB=E6=A1=8C=E9=9D=A2?= =?UTF-8?q?=EF=BC=89v0.1=EF=BC=9A=E6=8E=A8=E8=BF=9B=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + src/api/im/home/rtc/index.ts | 162 ++++++++++++++++++++++++++++++++ src/views/im/utils/constants.ts | 9 ++ 3 files changed, 172 insertions(+) create mode 100644 src/api/im/home/rtc/index.ts diff --git a/package.json b/package.json index b29817573..481eca6a1 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "jsbarcode": "^3.12.3", "jsencrypt": "^3.3.2", "jsoneditor": "^10.1.3", + "livekit-client": "^2.18.9", "localforage": "^1.10.0", "lodash-es": "^4.17.21", "markdown-it": "^14.1.0", diff --git a/src/api/im/home/rtc/index.ts b/src/api/im/home/rtc/index.ts new file mode 100644 index 000000000..d9a93473c --- /dev/null +++ b/src/api/im/home/rtc/index.ts @@ -0,0 +1,162 @@ +import request from '@/config/axios' + +/** 会话场景;对齐后端 ImConversationTypeEnum */ +export const ImCallScene = { + PRIVATE: 1, + GROUP: 2 +} as const + +/** 媒体类型;对齐后端 ImCallMediaTypeEnum */ +export const ImCallMediaType = { + VOICE: 1, + VIDEO: 2 +} as const + +/** 通话状态;对齐后端 ImCallStatusEnum */ +export const ImCallStatus = { + INVITING: 10, + ONGOING: 20, + ENDED: 30 +} as const + +/** 通话结束原因;对齐后端 ImCallEndReasonEnum */ +export const ImCallEndReason = { + HANGUP: 1, + REJECT: 2, + CANCEL: 3, + TIMEOUT: 4, + BUSY: 5, + ERROR: 9 +} as const + +/** 发起通话请求 VO */ +export interface ImRtcCallInviteReqVO { + scene: number + mediaType: number + peerUserId?: number + groupId?: number + /** 群通话场景:前端选定的子集;为空回退到群活跃成员 */ + inviteeIds?: number[] +} + +/** 通话中添加成员请求 VO */ +export interface ImRtcCallInviteMoreReqVO { + roomName: string + inviteeIds: number[] +} + +/** 通话会话 VO;invite / accept / refreshToken / getActiveSessions 共用 */ +export interface ImRtcCallRespVO { + callId: string + roomName: string + livekitUrl: string + token?: string + scene: number + mediaType: number + status: number + inviterId: number + groupId?: number + inviteeIds?: number[] + joinedUserIds?: number[] + newCreated?: boolean +} + +/** RTC_INVITE 信令载荷;payload 走 ImPrivateMessageDTO.content(JSON 字符串) */ +export interface ImRtcInviteNotification { + callId: string + roomName: string + livekitUrl: string + token: string + scene: number + mediaType: number + inviterId: number + inviterNickname?: string + inviterAvatar?: string + groupId?: number +} + +/** RTC_ACCEPT 信令载荷 */ +export interface ImRtcAcceptNotification { + callId: string + roomName: string + acceptorId: number +} + +/** RTC_END 信令载荷 */ +export interface ImRtcEndNotification { + callId: string + roomName: string + operatorId?: number + reason: number + durationSeconds?: number +} + +/** RTC_GROUP_STARTED / RTC_GROUP_UPDATED / RTC_GROUP_ENDED 共用载荷 */ +export interface ImRtcGroupNotification { + callId: string + roomName: string + groupId: number + mediaType: number + inviterId: number + joinedUserIds?: number[] + inviteeIds?: number[] +} + +/** 群活跃通话查询响应;不含 token */ +export interface ImRtcGroupCallRespVO { + callId: string + roomName: string + groupId: number + mediaType: number + inviterId: number + joinedUserIds?: number[] + inviteeIds?: number[] +} + +/** 发起通话;同好友对 / 群已有进行中通话则返回该会话并标记 newCreated=false */ +export const inviteCall = (data: ImRtcCallInviteReqVO) => { + return request.post({ url: '/im/rtc/invite', data }) +} + +/** 通话中添加成员;仅群通话可用 */ +export const inviteMoreCall = (data: ImRtcCallInviteMoreReqVO) => { + return request.post({ url: '/im/rtc/invite-more', data }) +} + +/** 接听通话 */ +export const acceptCall = (roomName: string) => { + return request.post({ url: '/im/rtc/accept', params: { roomName } }) +} + +/** 拒绝通话 */ +export const rejectCall = (roomName: string) => { + return request.post({ url: '/im/rtc/reject', params: { roomName } }) +} + +/** 取消邀请;主叫接通前调用 */ +export const cancelCall = (roomName: string) => { + return request.post({ url: '/im/rtc/cancel', params: { roomName } }) +} + +/** 离开通话;接通后调用 */ +export const leaveCall = (roomName: string) => { + return request.post({ url: '/im/rtc/leave', params: { roomName } }) +} + +/** 重新签发 Token;客户端重连或 Token 过期续期 */ +export const refreshCallToken = (roomName: string) => { + return request.get({ url: '/im/rtc/refresh-token', params: { roomName } }) +} + +/** 查询当前用户活跃通话;冷启动 / 推送点开恢复 */ +export const getActiveCallSessions = () => { + return request.get({ url: '/im/rtc/active-sessions' }) +} + +/** 查询群当前进行中的通话;用于群聊顶部胶囊条;返回 null 表示无活跃通话 */ +export const getGroupActiveCall = (groupId: number) => { + return request.get({ + url: '/im/rtc/group-active-call', + params: { groupId } + }) +} diff --git a/src/views/im/utils/constants.ts b/src/views/im/utils/constants.ts index 2023a15c4..cd8357d5c 100644 --- a/src/views/im/utils/constants.ts +++ b/src/views/im/utils/constants.ts @@ -13,6 +13,15 @@ export const ImMessageType = { RECALL: 2101, // 撤回(对应 OpenIM RevokeNotification=2101) RECEIPT: 2200, // 回执(对应 OpenIM HasReadReceipt=2200) READ: 2201, // 已读(多端同步,OpenIM 无对应;自有扩展) + // TODO @AI:是不是要把单聊、群聊的信令融合? + // ========== 实时通话信令(2300-2302) ========== + RTC_INVITE: 2300, // 通话邀请(推给被叫弹来电) + RTC_ACCEPT: 2301, // 通话接通(推给主叫切到通话中 UI) + RTC_END: 2302, // 通话结束(拒绝/取消/挂断/超时统一) + // ========== 群通话广播(2310-2312):让所有群成员能看胶囊条 / 主动加入 ========== + RTC_GROUP_STARTED: 2310, // 群通话开始(全群广播) + RTC_GROUP_ENDED: 2311, // 群通话结束(全群广播;胶囊条移除) + RTC_GROUP_UPDATED: 2312, // 群通话成员变更(全群广播;胶囊条人数刷新) // ========== 好友通知(1201-1210 直接复用 OpenIM 段位编号) ========== FRIEND_REQUEST_APPROVED: 1201, // 好友申请被同意 FRIEND_REQUEST_REJECTED: 1202, // 好友申请被拒绝