Files
EchoChat/frontend/src/pages/meeting/index.vue
bujinyuan ce09315fa6 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
2026-04-22 16:04:06 +08:00

203 lines
5.0 KiB
Vue
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.

<!--
会议首页Meeting Hub
职责
- 作为 tabBar "会议" 的统一入口提供创建 / 加入 / 最近会议跳转
- 不直接承载 mediasoup 连接只做导航与轻量查询
数据流
- 点击创建即时会议 /pages/meeting/create
- 点击加入会议 /pages/meeting/join
-->
<template>
<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>
<script>
import CustomTabBar from '@/components/CustomTabBar.vue'
export default {
name: 'MeetingIndex',
components: { CustomTabBar },
methods: {
goCreate() {
uni.navigateTo({ url: '/pages/meeting/create' })
},
goJoin() {
uni.navigateTo({ url: '/pages/meeting/join' })
}
}
}
</script>
<style scoped>
.page {
min-height: 100vh;
background: linear-gradient(180deg, #EEF4FF 0%, #F8FAFC 40%);
padding: 48rpx 32rpx 180rpx;
box-sizing: border-box;
}
.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;
background: rgba(255, 255, 255, 0.22);
color: #FFFFFF;
flex-shrink: 0;
}
.action-icon.alt {
background: rgba(59, 130, 246, 0.12);
color: #2563EB;
}
.action-text {
flex: 1;
display: flex;
flex-direction: column;
gap: 6rpx;
min-width: 0;
}
.action-title {
font-size: 30rpx;
font-weight: 600;
color: #0F172A;
}
.action-desc {
font-size: 24rpx;
color: #64748B;
line-height: 1.5;
}
.action-arrow {
font-size: 40rpx;
color: #CBD5E1;
flex-shrink: 0;
}
.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>