feat(phase2e-2): 会议首页落地 "创建 / 加入" 双入口

问题
- tabBar "会议" 指向 pages/meeting/index,但该页仍是占位的
  "视频会议功能开发中…",用户从底部 tab 进入无入口按钮,
  必须手改 URL 到 /pages/meeting/create 或 /join 才能进会议

修复
- 重写 pages/meeting/index.vue 为真实的 Meeting Hub:
  · 顶部 hero 标题 + 描述
  · "创建即时会议" 主按钮(蓝色渐变卡片,跳 /pages/meeting/create)
  · "加入会议" 次按钮(卡片,跳 /pages/meeting/join)
  · 提示文案说明入会流程与主持人能力
- 保留 CustomTabBar 底栏 current=2

验证
- Playwright 截图确认布局、两个入口按钮视觉与点击区域均正常

Made-with: Cursor
This commit is contained in:
bujinyuan
2026-04-22 16:04:06 +08:00
parent c529ff4689
commit ce09315fa6

View File

@@ -1,16 +1,59 @@
<!--
会议页占位
设计系统design-system/echochat/MASTER.md
TabBar 页面Phase 3会议模块中实现具体功能
会议Meeting Hub
职责
- 作为 tabBar "会议" 的统一入口提供创建 / 加入 / 最近会议跳转
- 不直接承载 mediasoup 连接只做导航与轻量查询
数据流
- 点击创建即时会议 /pages/meeting/create
- 点击加入会议 /pages/meeting/join
-->
<template>
<view class="page-wrapper">
<view class="placeholder-content">
<text class="placeholder-icon">🎥</text>
<text class="placeholder-title">会议</text>
<text class="placeholder-desc">视频会议功能开发中</text>
<view class="page">
<view class="hero">
<view class="hero-icon">🎥</view>
<text class="hero-title">视频会议</text>
<text class="hero-desc">创建或加入会议进行高清音视频协作</text>
</view>
<view class="actions">
<view class="action-card primary" @click="goCreate">
<view class="action-icon">
<svg viewBox="0 0 24 24" width="28" height="28" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polygon points="23 7 16 12 23 17 23 7"></polygon>
<rect x="1" y="5" width="15" height="14" rx="2" ry="2"></rect>
</svg>
</view>
<view class="action-text">
<text class="action-title">创建即时会议</text>
<text class="action-desc">立即发起一场新会议并邀请成员</text>
</view>
<view class="action-arrow"></view>
</view>
<view class="action-card" @click="goJoin">
<view class="action-icon alt">
<svg viewBox="0 0 24 24" width="28" height="28" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 9l6 6-6 6"></path>
<path d="M4 4v7a4 4 0 0 0 4 4h12"></path>
</svg>
</view>
<view class="action-text">
<text class="action-title">加入会议</text>
<text class="action-desc">输入 9 位会议号加入已有会议</text>
</view>
<view class="action-arrow"></view>
</view>
</view>
<view class="tips">
<text class="tips-title">提示</text>
<text class="tips-line"> 入会前会先进入设备预览页选择摄像头 / 麦克风</text>
<text class="tips-line"> 主持人可在会议中邀请成员管理权限结束会议</text>
<text class="tips-line"> 支持静音关闭摄像头实时聊天等常用操作</text>
</view>
<CustomTabBar :current="2" />
</view>
</template>
@@ -20,39 +63,140 @@ import CustomTabBar from '@/components/CustomTabBar.vue'
export default {
name: 'MeetingIndex',
components: { CustomTabBar }
components: { CustomTabBar },
methods: {
goCreate() {
uni.navigateTo({ url: '/pages/meeting/create' })
},
goJoin() {
uni.navigateTo({ url: '/pages/meeting/join' })
}
}
}
</script>
<style scoped>
.page-wrapper {
.page {
min-height: 100vh;
background-color: #F8FAFC;
padding-bottom: 120rpx;
background: linear-gradient(180deg, #EEF4FF 0%, #F8FAFC 40%);
padding: 48rpx 32rpx 180rpx;
box-sizing: border-box;
}
.placeholder-content {
.hero {
display: flex;
flex-direction: column;
align-items: flex-start;
padding: 20rpx 8rpx 40rpx;
}
.hero-icon {
font-size: 72rpx;
line-height: 1;
margin-bottom: 16rpx;
}
.hero-title {
font-size: 44rpx;
font-weight: 700;
color: #0F172A;
margin-bottom: 8rpx;
}
.hero-desc {
font-size: 26rpx;
color: #64748B;
line-height: 1.6;
}
.actions {
display: flex;
flex-direction: column;
gap: 20rpx;
margin-top: 8rpx;
}
.action-card {
display: flex;
align-items: center;
gap: 24rpx;
padding: 28rpx 28rpx;
background: #FFFFFF;
border-radius: 20rpx;
box-shadow: 0 4rpx 16rpx rgba(15, 23, 42, 0.05);
transition: transform 0.12s ease, box-shadow 0.12s ease;
cursor: pointer;
}
.action-card:active {
transform: translateY(1rpx);
box-shadow: 0 2rpx 8rpx rgba(15, 23, 42, 0.08);
}
.action-card.primary {
background: linear-gradient(135deg, #3B82F6 0%, #2563EB 100%);
box-shadow: 0 6rpx 20rpx rgba(59, 130, 246, 0.28);
}
.action-card.primary .action-title,
.action-card.primary .action-desc,
.action-card.primary .action-arrow {
color: #FFFFFF;
}
.action-card.primary .action-desc { color: rgba(255, 255, 255, 0.82); }
.action-icon {
width: 88rpx;
height: 88rpx;
border-radius: 20rpx;
display: flex;
align-items: center;
justify-content: center;
padding-top: 300rpx;
background: rgba(255, 255, 255, 0.22);
color: #FFFFFF;
flex-shrink: 0;
}
.action-icon.alt {
background: rgba(59, 130, 246, 0.12);
color: #2563EB;
}
.placeholder-icon {
font-size: 80rpx;
margin-bottom: 24rpx;
.action-text {
flex: 1;
display: flex;
flex-direction: column;
gap: 6rpx;
min-width: 0;
}
.placeholder-title {
font-size: 36rpx;
.action-title {
font-size: 30rpx;
font-weight: 600;
color: #1E293B;
margin-bottom: 12rpx;
color: #0F172A;
}
.action-desc {
font-size: 24rpx;
color: #64748B;
line-height: 1.5;
}
.action-arrow {
font-size: 40rpx;
color: #CBD5E1;
flex-shrink: 0;
}
.placeholder-desc {
font-size: 28rpx;
color: #94A3B8;
.tips {
margin-top: 48rpx;
padding: 24rpx 28rpx;
background: rgba(255, 255, 255, 0.7);
border-radius: 16rpx;
border: 1rpx solid rgba(59, 130, 246, 0.08);
display: flex;
flex-direction: column;
gap: 8rpx;
}
.tips-title {
font-size: 26rpx;
font-weight: 600;
color: #0F172A;
margin-bottom: 4rpx;
}
.tips-line {
font-size: 24rpx;
color: #475569;
line-height: 1.7;
}
</style>