fix(phase2e-2): 修复刷新后重入会失败 + 聊天输入区布局防御
问题 - 刷新会议页面被踢回 join 页,再次加入报"已在会议中" - 极窄聊天面板下,发送按钮在 uni-app H5 渲染为 uni-button 时可能被默认 width:100% 样式撑满导致"竖排变形" 修复 1. meeting store: joinAndEnter / createAndEnter 捕获 staleMeetingHint 时自动 调用 cleanupStaleMeetings 清理后端残留的僵尸活跃成员记录,并重试一次; 日志链路:加入失败 → 检测僵尸 → 自动清理 → 重试加入 2. ChatPanel: input-area 显式声明 flex-direction:row + flex-wrap:nowrap; .btn-send 追加 width:auto / line-height:1 / box-sizing,并通过 ::v-deep 复位 uni-app 内部 <uni-button> 默认 width,彻底避免按钮独占一行变形 验证 - Playwright 刷新 room 页 → 回 join → 预览 → 加入会议:日志显示自动清理僵尸 "581-702-753"、重试加入 "925-409-354" 成功,MediaEngine 正常建立 - 1024x576 视口下 toolbar 完整可见,聊天面板并排无右侧留白,发送按钮在 输入框右侧 Made-with: Cursor
This commit is contained in:
@@ -350,6 +350,8 @@ const close = () => emit('close')
|
|||||||
|
|
||||||
.input-area {
|
.input-area {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: nowrap;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
gap: 12rpx;
|
gap: 12rpx;
|
||||||
padding: 16rpx 24rpx calc(16rpx + env(safe-area-inset-bottom));
|
padding: 16rpx 24rpx calc(16rpx + env(safe-area-inset-bottom));
|
||||||
@@ -375,6 +377,7 @@ const close = () => emit('close')
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-send {
|
.btn-send {
|
||||||
|
/* 覆盖 uni-app <uni-button> 默认 width:100% / border / margin */
|
||||||
all: unset;
|
all: unset;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
@@ -388,7 +391,16 @@ const close = () => emit('close')
|
|||||||
box-shadow: 0 4rpx 14rpx rgba(59, 130, 246, 0.35);
|
box-shadow: 0 4rpx 14rpx rgba(59, 130, 246, 0.35);
|
||||||
transition: background-color 0.15s ease, transform 0.08s ease, box-shadow 0.15s ease;
|
transition: background-color 0.15s ease, transform 0.08s ease, box-shadow 0.15s ease;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
width: auto;
|
||||||
min-height: 64rpx;
|
min-height: 64rpx;
|
||||||
|
line-height: 1;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
/* 防御 uni-app H5 <uni-button> 内部嵌套 <button> 的全宽/默认边框 */
|
||||||
|
.btn-send::after { border: none !important; }
|
||||||
|
.input-area ::v-deep(uni-button.btn-send) {
|
||||||
|
width: auto;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
.btn-send svg { display: block; }
|
.btn-send svg { display: block; }
|
||||||
.btn-send .btn-send-label { font-size: 26rpx; font-weight: 600; }
|
.btn-send .btn-send-label { font-size: 26rpx; font-weight: 600; }
|
||||||
|
|||||||
@@ -528,7 +528,7 @@ export const useMeetingStore = defineStore('meeting', () => {
|
|||||||
* @param {Object} payload - { title, password?, max_members?, enter_muted?, allow_chat? }
|
* @param {Object} payload - { title, password?, max_members?, enter_muted?, allow_chat? }
|
||||||
* @param {Object} [mediaPrefs] - 设备预览页的媒体偏好,入会成功后自动推流(可空)
|
* @param {Object} [mediaPrefs] - 设备预览页的媒体偏好,入会成功后自动推流(可空)
|
||||||
*/
|
*/
|
||||||
const createAndEnter = async (payload, mediaPrefs) => {
|
const createAndEnter = async (payload, mediaPrefs, _retried = false) => {
|
||||||
if (isInMeeting.value) {
|
if (isInMeeting.value) {
|
||||||
throw new Error('你当前已在其他会议中')
|
throw new Error('你当前已在其他会议中')
|
||||||
}
|
}
|
||||||
@@ -550,7 +550,14 @@ export const useMeetingStore = defineStore('meeting', () => {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
_log('error', '[Meeting] 创建并入会失败', err)
|
_log('error', '[Meeting] 创建并入会失败', err)
|
||||||
_reset()
|
_reset()
|
||||||
throw _enrichStaleMeetingError(err)
|
const enriched = _enrichStaleMeetingError(err)
|
||||||
|
// 刷新/崩溃残留:后端仍标记当前用户为活跃成员 → 自动清理后重试一次
|
||||||
|
if (enriched?.staleMeetingHint && !_retried) {
|
||||||
|
_log('warn', '[Meeting] 检测到僵尸会议残留,自动清理并重试创建')
|
||||||
|
try { await cleanupStaleMeetings() } catch (e) { _log('warn', '[Meeting] 自动清理失败', e) }
|
||||||
|
return createAndEnter(payload, mediaPrefs, true)
|
||||||
|
}
|
||||||
|
throw enriched
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,7 +567,7 @@ export const useMeetingStore = defineStore('meeting', () => {
|
|||||||
* @param {string} [password]
|
* @param {string} [password]
|
||||||
* @param {Object} [mediaPrefs] - 设备预览页的媒体偏好(可空)
|
* @param {Object} [mediaPrefs] - 设备预览页的媒体偏好(可空)
|
||||||
*/
|
*/
|
||||||
const joinAndEnter = async (roomCode, password = '', mediaPrefs) => {
|
const joinAndEnter = async (roomCode, password = '', mediaPrefs, _retried = false) => {
|
||||||
if (isInMeeting.value) {
|
if (isInMeeting.value) {
|
||||||
throw new Error('你当前已在其他会议中')
|
throw new Error('你当前已在其他会议中')
|
||||||
}
|
}
|
||||||
@@ -575,7 +582,14 @@ export const useMeetingStore = defineStore('meeting', () => {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
_log('error', '[Meeting] 加入会议失败', err)
|
_log('error', '[Meeting] 加入会议失败', err)
|
||||||
_reset()
|
_reset()
|
||||||
throw _enrichStaleMeetingError(err)
|
const enriched = _enrichStaleMeetingError(err)
|
||||||
|
// 刷新/崩溃残留:后端仍记该用户为活跃成员 → 自动清理后重试一次
|
||||||
|
if (enriched?.staleMeetingHint && !_retried) {
|
||||||
|
_log('warn', '[Meeting] 检测到僵尸会议残留,自动清理并重试加入')
|
||||||
|
try { await cleanupStaleMeetings() } catch (e) { _log('warn', '[Meeting] 自动清理失败', e) }
|
||||||
|
return joinAndEnter(roomCode, password, mediaPrefs, true)
|
||||||
|
}
|
||||||
|
throw enriched
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user