fix(phase2e-2): 会议内聊天面板 UI 布局优化

问题修复:
- 原遮罩式抽屉覆盖底部 toolbar,导致按钮不可点击
- 发送按钮过小不显眼
- 聊天面板打开时视频区被遮挡出现大片空白

改进:
- room.vue 主区改为 flex-row 布局:视频列 + 聊天列并排,聊天打开时视频自动收窄
- ChatPanel 去除全屏遮罩,作为侧边栏嵌入 chat-col,保留过渡动画
- 发送按钮增加纸飞机图标并采用渐变背景,hover / active / disabled 状态清晰
- msg-list 使用 flex:1 + min-height:0 + height:0 修复 scroll-view 高度撑破问题,保证输入区始终固定在底部
- 小屏(<750px)自动回退为全屏浮层,避免挤压视频

Made-with: Cursor
This commit is contained in:
bujinyuan
2026-04-22 15:32:10 +08:00
parent 1222bf551d
commit 16225c413d
2 changed files with 103 additions and 69 deletions

View File

@@ -11,20 +11,19 @@
- 发送通过 @send 事件回传成功/失败由父层决定是否 toast - 发送通过 @send 事件回传成功/失败由父层决定是否 toast
--> -->
<template> <template>
<view v-if="visible" class="panel-root" @click.self="close"> <view v-if="visible" class="panel" :class="{ show }">
<view class="panel" :class="{ show }"> <view class="header">
<view class="header"> <view class="title-area">
<view class="title-area"> <text class="title">会议聊天</text>
<text class="title">会议聊天</text> <text class="count">({{ messages.length }})</text>
<text class="count">({{ messages.length }})</text>
</view>
<view class="btn-close" @click="close">
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</view>
</view> </view>
<view class="btn-close" @click="close">
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</view>
</view>
<scroll-view <scroll-view
class="msg-list" class="msg-list"
@@ -81,11 +80,14 @@
@input="onDraftInput" @input="onDraftInput"
@confirm="onSend" @confirm="onSend"
/> />
<button class="btn-send" :disabled="!canSend || sending" @click="onSend"> <button class="btn-send" :disabled="!canSend || sending" :class="{ active: canSend && !sending }" @click="onSend">
<text v-if="!sending">发送</text> <svg v-if="!sending" viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<text v-else>发送中</text> <line x1="22" y1="2" x2="11" y2="13"></line>
</button> <polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
</view> </svg>
<text v-if="!sending" class="btn-send-label">发送</text>
<text v-else class="btn-send-label">发送中</text>
</button>
</view> </view>
</view> </view>
</template> </template>
@@ -222,28 +224,15 @@ const close = () => emit('close')
</script> </script>
<style scoped> <style scoped>
.panel-root { /* 面板作为并排侧边栏:父容器 .chat-col 控制宽度/显隐动画 */
position: fixed;
inset: 0;
z-index: 205;
background: rgba(0, 0, 0, 0.45);
display: flex;
justify-content: flex-end;
}
.panel { .panel {
width: 640rpx; width: 100%;
max-width: 92vw;
height: 100%; height: 100%;
background: #1F2937; background: #1F2937;
color: #F3F4F6; color: #F3F4F6;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
transform: translateX(100%);
transition: transform 0.24s ease;
box-shadow: -4rpx 0 24rpx rgba(0, 0, 0, 0.4);
} }
.panel.show { transform: translateX(0); }
.header { .header {
display: flex; display: flex;
@@ -269,7 +258,9 @@ const close = () => emit('close')
.btn-close:hover { background: rgba(255, 255, 255, 0.08); } .btn-close:hover { background: rgba(255, 255, 255, 0.08); }
.msg-list { .msg-list {
flex: 1; flex: 1 1 0;
min-height: 0;
height: 0;
padding: 16rpx 24rpx 24rpx; padding: 16rpx 24rpx 24rpx;
box-sizing: border-box; box-sizing: border-box;
} }
@@ -284,10 +275,14 @@ const close = () => emit('close')
.load-more:hover { color: rgba(255, 255, 255, 0.8); } .load-more:hover { color: rgba(255, 255, 255, 0.8); }
.empty { .empty {
padding: 100rpx 0 80rpx; flex: 1;
display: flex;
align-items: center;
justify-content: center;
text-align: center; text-align: center;
color: rgba(255, 255, 255, 0.45); color: rgba(255, 255, 255, 0.45);
font-size: 24rpx; font-size: 24rpx;
padding: 40rpx 0;
} }
.msg-row { .msg-row {
@@ -382,18 +377,30 @@ const close = () => emit('close')
.btn-send { .btn-send {
all: unset; all: unset;
cursor: pointer; cursor: pointer;
padding: 14rpx 28rpx; display: inline-flex;
align-items: center;
justify-content: center;
gap: 8rpx;
padding: 16rpx 28rpx;
background: #3B82F6; background: #3B82F6;
color: #FFFFFF; color: #FFFFFF;
font-size: 26rpx;
font-weight: 600;
border-radius: 14rpx; border-radius: 14rpx;
transition: background-color 0.15s ease; 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;
flex-shrink: 0; flex-shrink: 0;
min-height: 64rpx;
} }
.btn-send svg { display: block; }
.btn-send .btn-send-label { font-size: 26rpx; font-weight: 600; }
.btn-send:hover { background: #2563EB; } .btn-send:hover { background: #2563EB; }
.btn-send:active { transform: translateY(1rpx); }
.btn-send[disabled] { .btn-send[disabled] {
background: rgba(59, 130, 246, 0.35); background: rgba(59, 130, 246, 0.28);
color: rgba(255, 255, 255, 0.55);
box-shadow: none;
cursor: not-allowed; cursor: not-allowed;
} }
.btn-send.active {
background: linear-gradient(135deg, #3B82F6 0%, #2563EB 100%);
}
</style> </style>

View File

@@ -34,22 +34,38 @@
</view> </view>
</view> </view>
<!-- 视频网格 --> <!-- 主区左视频 + 右侧聊天面板 chatVisible 时侧栏展开 -->
<view class="body"> <view class="body">
<VideoGrid :tiles="tiles"> <view class="video-col">
<template #tile="{ tile }"> <VideoGrid :tiles="tiles">
<VideoTile <template #tile="{ tile }">
:user-id="tile.userId" <VideoTile
:name="tile.name" :user-id="tile.userId"
:is-local="tile.isLocal" :name="tile.name"
:is-host="tile.isHost" :is-local="tile.isLocal"
:audio-enabled="tile.audioEnabled" :is-host="tile.isHost"
:video-enabled="tile.videoEnabled" :audio-enabled="tile.audioEnabled"
:audio-track="tile.audioTrack" :video-enabled="tile.videoEnabled"
:video-track="tile.videoTrack" :audio-track="tile.audioTrack"
/> :video-track="tile.videoTrack"
</template> />
</VideoGrid> </template>
</VideoGrid>
</view>
<view class="chat-col" :class="{ open: chatVisible }">
<ChatPanel
:visible="chatVisible"
:messages="chatMessages"
:current-user-id="myUserId"
:display-name-map="displayNameMap"
:has-more="chatHasMore"
:loading-more="chatLoadingMore"
@close="closeChat"
@send="onChatSend"
@load-more="onChatLoadMore"
@request-initial-load="onChatRequestInitialLoad"
/>
</view>
</view> </view>
<!-- 底部工具条 --> <!-- 底部工具条 -->
@@ -92,20 +108,6 @@
@close="inviteVisible = false" @close="inviteVisible = false"
/> />
<!-- 聊天面板 -->
<ChatPanel
:visible="chatVisible"
:messages="chatMessages"
:current-user-id="myUserId"
:display-name-map="displayNameMap"
:has-more="chatHasMore"
:loading-more="chatLoadingMore"
@close="closeChat"
@send="onChatSend"
@load-more="onChatLoadMore"
@request-initial-load="onChatRequestInitialLoad"
/>
<!-- 离会确认弹窗 --> <!-- 离会确认弹窗 -->
<view v-if="leaveDialogVisible" class="leave-mask" @click.self="leaveDialogVisible = false"> <view v-if="leaveDialogVisible" class="leave-mask" @click.self="leaveDialogVisible = false">
<view class="leave-modal"> <view class="leave-modal">
@@ -633,6 +635,31 @@ onUnload(() => {
min-height: 0; min-height: 0;
background: #0B1220; background: #0B1220;
overflow: hidden; overflow: hidden;
display: flex;
flex-direction: row;
}
.video-col {
flex: 1;
min-width: 0;
min-height: 0;
display: flex;
overflow: hidden;
}
.chat-col {
width: 0;
min-height: 0;
flex-shrink: 0;
overflow: hidden;
transition: width 0.24s ease;
border-left: 1rpx solid rgba(255, 255, 255, 0.06);
background: #1F2937;
}
.chat-col.open { width: 640rpx; }
@media (max-width: 750px) {
/* 小屏幕:聊天面板改为全屏浮层,避免挤压视频 */
.chat-col { position: fixed; top: 0; right: 0; bottom: 0; z-index: 205; }
.chat-col.open { width: 100vw; }
} }
/* 离会弹窗 */ /* 离会弹窗 */