Files
EchoChat/frontend/src/constants/meeting.js
bujinyuan f97fec24a8 feat(phase2e-2): 前端 mediasoup-client 集成 + Pinia meeting Store(Task 9)
- frontend/src/api/meeting.js:12 个 REST 接口封装,统一 unwrap envelope.data
- frontend/src/services/websocket.js:新增 sendWithAck(Promise 化 + 超时 + 序列号)
- frontend/src/utils/mediasoup-client.js:MediaEngine 包装 Device/Transport/Producer/Consumer
- frontend/src/store/meeting.js:Pinia 会议状态机,桥接 14 个 WS 事件 + cleanupStaleMeetings
- frontend/src/constants/meeting.js:状态枚举 + 事件名集中管理
- frontend/src/pages/meeting/debug.vue:临时调试页(H5 原生 video/audio DOM 绕过 uni 组件限制)
- backend:meeting.consume.resume WS 事件 + create/join 响应透传 router_id + rtp_capabilities
- 文档:frontend/meeting.md、websocket.md、CURRENT_STATUS、plan 全部同步 Task 9 落地

Made-with: Cursor
2026-04-22 11:22:49 +08:00

164 lines
7.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 会议模块前端常量
*
* 与后端 backend/go-service/app/constants/meeting.go 严格一致
* 新增/修改任一常量时必须同步维护两端,否则运行时会因事件名不匹配而静默失败
*
* 版本说明:
* - Task 62026-04-20落地 13 个 WS 事件
* - Task 92026-04-22新增 meeting.consume.resume总计 14 个事件
*/
// ==================== 会议类型 ====================
export const MEETING_TYPE_INSTANT = 1 // 即时会议MVP 仅此)
export const MEETING_TYPE_SCHEDULED = 2 // 预约会议Phase 2e-3
export const MEETING_TYPE_LABEL = {
[MEETING_TYPE_INSTANT]: '即时会议',
[MEETING_TYPE_SCHEDULED]: '预约会议'
}
// ==================== 会议状态 ====================
export const MEETING_STATUS_PENDING = 0 // 未开始(仅预约会议)
export const MEETING_STATUS_ACTIVE = 1 // 进行中
export const MEETING_STATUS_ENDED = 2 // 已结束
export const MEETING_STATUS_LABEL = {
[MEETING_STATUS_PENDING]: '未开始',
[MEETING_STATUS_ACTIVE]: '进行中',
[MEETING_STATUS_ENDED]: '已结束'
}
// ==================== 参与者角色 ====================
export const MEETING_ROLE_PARTICIPANT = 0 // 普通参会人
export const MEETING_ROLE_HOST = 1 // 主持人
export const MEETING_ROLE_COHOST = 2 // 联合主持人保留MVP 不用)
export const MEETING_ROLE_LABEL = {
[MEETING_ROLE_PARTICIPANT]: '参会人',
[MEETING_ROLE_HOST]: '主持人',
[MEETING_ROLE_COHOST]: '联合主持人'
}
// ==================== 会议结束原因 ====================
export const MEETING_ENDED_REASON_HOST_ENDED = 'host_ended'
export const MEETING_ENDED_REASON_EMPTY_TTL = 'empty_ttl'
export const MEETING_ENDED_REASON_ADMIN_FORCE = 'admin_force'
export const MEETING_ENDED_REASON_SYSTEM_ERROR = 'system_error'
export const MEETING_ENDED_REASON_LABEL = {
[MEETING_ENDED_REASON_HOST_ENDED]: '主持人结束',
[MEETING_ENDED_REASON_EMPTY_TTL]: '空房超时',
[MEETING_ENDED_REASON_ADMIN_FORCE]: '管理员强制结束',
[MEETING_ENDED_REASON_SYSTEM_ERROR]: '系统异常'
}
// ==================== 离会原因 ====================
export const MEETING_LEFT_REASON_SELF = 'self'
export const MEETING_LEFT_REASON_KICKED = 'kicked'
export const MEETING_LEFT_REASON_HOST_END = 'host_end'
export const MEETING_LEFT_REASON_EMPTY_TTL = 'empty_ttl'
export const MEETING_LEFT_REASON_DISCONNECT = 'disconnect'
export const MEETING_LEFT_REASON_LABEL = {
[MEETING_LEFT_REASON_SELF]: '主动离开',
[MEETING_LEFT_REASON_KICKED]: '被移除',
[MEETING_LEFT_REASON_HOST_END]: '会议结束',
[MEETING_LEFT_REASON_EMPTY_TTL]: '空房超时',
[MEETING_LEFT_REASON_DISCONNECT]: '网络断开'
}
// ==================== 主持人变更自动转让原因Task 8 引入) ====================
export const MEETING_HOST_AUTO_REASON_GRACE_EXPIRED = 'host_grace_expired' // 主持人宽限期到期自动转让
export const MEETING_HOST_AUTO_REASON_HOST_KICKED = 'host_kicked' // (保留)主持人被管理员踢出自动转让
export const MEETING_HOST_AUTO_REASON_LABEL = {
[MEETING_HOST_AUTO_REASON_GRACE_EXPIRED]: '主持人掉线超时自动转让',
[MEETING_HOST_AUTO_REASON_HOST_KICKED]: '主持人被移除自动转让'
}
// ==================== 默认配置常量 ====================
export const MEETING_MVP_MAX_MEMBERS = 8 // MVP 单会议硬上限
export const MEETING_HOST_GRACE_SECONDS = 120 // 主持人掉线宽限期Task 8
export const MEETING_EMPTY_ROOM_TTL_SECONDS = 300 // 空房销毁 TTLTask 8
export const MEETING_WS_ACK_TIMEOUT_MS = 10000 // WS 事件 ACK 等待超时Task 9
// ==================== WS 事件名14 个,与后端 constants/meeting.go 一一对应) ====================
// 房间组3 个)
export const MEETING_WS_ROOM_JOIN = 'meeting.room.join' // C→S
export const MEETING_WS_ROOM_LEAVE = 'meeting.room.leave' // C→S
export const MEETING_WS_ROOM_ENDED = 'meeting.room.ended' // S→C
// 成员组6 个)
export const MEETING_WS_MEMBER_JOINED = 'meeting.member.joined' // S→C
export const MEETING_WS_MEMBER_LEFT = 'meeting.member.left' // S→C
export const MEETING_WS_MEMBER_STATE_CHANGED = 'meeting.member.state.changed' // 双向
export const MEETING_WS_MEMBER_KICKED = 'meeting.member.kicked' // S→C定向
export const MEETING_WS_MEMBER_PRODUCER_NEW = 'meeting.member.producer.new' // S→C
export const MEETING_WS_HOST_CHANGED = 'meeting.host.changed' // S→C
// 媒体组6 个,含 Task 9 新增 consume.resume
export const MEETING_WS_TRANSPORT_CREATE = 'meeting.transport.create' // C→S
export const MEETING_WS_TRANSPORT_CONNECT = 'meeting.transport.connect' // C→S
export const MEETING_WS_PRODUCE_START = 'meeting.produce.start' // C→S
export const MEETING_WS_CONSUME_START = 'meeting.consume.start' // C→S
export const MEETING_WS_CONSUME_RESUME = 'meeting.consume.resume' // C→STask 9 新增)
export const MEETING_WS_PRODUCER_CLOSE = 'meeting.producer.close' // C→S
// 聊天1 个)
export const MEETING_WS_CHAT_MESSAGE = 'meeting.chat.message' // S→C
/** C→S 客户端可主动发起的事件白名单 */
export const MEETING_WS_CLIENT_EVENTS = [
MEETING_WS_ROOM_JOIN,
MEETING_WS_ROOM_LEAVE,
MEETING_WS_MEMBER_STATE_CHANGED,
MEETING_WS_TRANSPORT_CREATE,
MEETING_WS_TRANSPORT_CONNECT,
MEETING_WS_PRODUCE_START,
MEETING_WS_CONSUME_START,
MEETING_WS_CONSUME_RESUME,
MEETING_WS_PRODUCER_CLOSE
]
/** S→C 服务端广播事件白名单(用于 Store 注册监听时统一处理) */
export const MEETING_WS_SERVER_EVENTS = [
MEETING_WS_ROOM_ENDED,
MEETING_WS_MEMBER_JOINED,
MEETING_WS_MEMBER_LEFT,
MEETING_WS_MEMBER_STATE_CHANGED,
MEETING_WS_MEMBER_KICKED,
MEETING_WS_MEMBER_PRODUCER_NEW,
MEETING_WS_HOST_CHANGED,
MEETING_WS_CHAT_MESSAGE
]
// ==================== 本地会议状态机(前端专用,与后端 meeting_rooms.status 无关) ====================
// Task 9 用于 store/meeting.js 驱动 UI 的本地状态
export const MEETING_LOCAL_STATE_IDLE = 'idle' // 未进入会议
export const MEETING_LOCAL_STATE_JOINING = 'joining' // REST JoinRoom 中
export const MEETING_LOCAL_STATE_CONNECTING = 'connecting' // Device load + Transport 创建中
export const MEETING_LOCAL_STATE_CONNECTED = 'connected' // 媒体层就绪,可推流/收流
export const MEETING_LOCAL_STATE_RECONNECTING = 'reconnecting' // WS 断线重连期间Task 8 host 宽限期共用)
export const MEETING_LOCAL_STATE_LEAVING = 'leaving' // REST LeaveRoom 中
export const MEETING_LOCAL_STATE_ENDED = 'ended' // 会议已结束room.ended 收到后进入)
export const MEETING_LOCAL_STATE_LABEL = {
[MEETING_LOCAL_STATE_IDLE]: '未入会',
[MEETING_LOCAL_STATE_JOINING]: '加入中',
[MEETING_LOCAL_STATE_CONNECTING]: '连接中',
[MEETING_LOCAL_STATE_CONNECTED]: '已连接',
[MEETING_LOCAL_STATE_RECONNECTING]: '重连中',
[MEETING_LOCAL_STATE_LEAVING]: '离开中',
[MEETING_LOCAL_STATE_ENDED]: '已结束'
}