电话咨询

This commit is contained in:
duoaohui
2026-06-04 15:52:22 +08:00
parent 495f0aae1b
commit cae3876d8b
4 changed files with 188 additions and 71 deletions

View File

@@ -15,6 +15,10 @@
<!-- 顶部信息栏 -->
<view class="top-bar">
<view class="top-left">
<view v-if="showCloudLawBack" class="cloud-law-back" @click="onCloudLawBack">
<text class="cloud-law-back-icon"></text>
</view>
<view class="top-left-info">
<text class="meeting-title">{{ meetingTitle }}</text>
<view class="code-pill" @click="openInvite">
<text class="code-text">{{ formattedCode }}</text>
@@ -23,6 +27,7 @@
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
</svg>
</view>
</view>
</view>
<view class="top-right">
<view class="state-pill" :class="stateClass">
@@ -227,13 +232,22 @@ import InviteDialog from '@/components/meeting/InviteDialog.vue'
import NetworkBadge from '@/components/meeting/NetworkBadge.vue'
import ChatPanel from '@/components/meeting/ChatPanel.vue'
import SelfVideoFloat from '@/components/meeting/SelfVideoFloat.vue'
import {
isCloudLawEmbed,
isCloudLawLawRole,
minimizeCloudLawMeeting,
notifyCloudLawCallEnded
} from '@/utils/cloudLawMiniProgram'
const meetingStore = useMeetingStore()
const userStore = useUserStore()
/** 云律律师端:工具栏用共享屏幕替换聊天 */
const cloudLawRole = ref('')
const cloudLawCallId = ref('')
const minimizingToMiniProgram = ref(false)
const replaceChatWithScreenShare = computed(() => String(cloudLawRole.value).toLowerCase() === 'law')
const showCloudLawBack = computed(() => isCloudLawEmbed() && isCloudLawLawRole(cloudLawRole.value))
const memberVisible = ref(false)
const inviteVisible = ref(false)
@@ -740,7 +754,20 @@ const onTransferHost = async (uid) => {
}
}
const onLeaveClick = () => { leaveDialogVisible.value = true }
const onCloudLawBack = () => {
if (minimizingToMiniProgram.value) return
minimizingToMiniProgram.value = true
meetingStore.leave().catch(() => {})
minimizeCloudLawMeeting(cloudLawCallId.value)
}
const onLeaveClick = () => {
if (showCloudLawBack.value) {
onCloudLawBack()
return
}
leaveDialogVisible.value = true
}
const confirmLeaveSelf = async () => {
leaveDialogVisible.value = false
@@ -775,53 +802,27 @@ const confirmEndOrLeave = async () => {
}
}
// 是否运行在云律小程序 web-view 内SSO 进入时打的标记)
const isCloudLawEmbed = () => {
try {
return typeof window !== 'undefined'
&& !!window.sessionStorage
&& window.sessionStorage.getItem('echo_cloud_law_meeting_embed') === '1'
} catch (e) {
return false
}
}
const getMiniProgram = () => {
return typeof window !== 'undefined' && window.wx && window.wx.miniProgram ? window.wx.miniProgram : null
}
// 退出会议视频界面:先给提示,再退出。
// 云律小程序 web-view 内 → 通知并 navigateBack 回到小程序(关闭会议 web-view 页);
// 普通浏览器/PC → 回 EchoChat 首页。
const leaveAndExit = (tip) => {
// 云律律师端「返回」→ 最小化并弹出「返回会议」;真正挂断/结束 → cloudLawCallEnded。
const leaveAndExit = (tip, ended = true) => {
if (tip) {
uni.showToast({ title: tip, icon: 'none', duration: 1200 })
}
// 留一点时间让提示可见,再退出视频界面
setTimeout(redirectHome, tip ? 600 : 800)
setTimeout(() => redirectHome(ended), tip ? 600 : 800)
}
let meetingExited = false
const redirectHome = () => {
const redirectHome = (ended = true) => {
if (meetingExited) return
const miniProgram = getMiniProgram()
if (isCloudLawEmbed() && miniProgram) {
if (isCloudLawEmbed() && isCloudLawLawRole(cloudLawRole.value)) {
meetingExited = true
try {
miniProgram.postMessage({ data: { type: 'cloudLawCallEnded', action: 'cloudLawCallEnded' } })
} catch (e) {}
try {
if (typeof miniProgram.navigateBack === 'function') {
miniProgram.navigateBack({ delta: 1 })
return
}
if (typeof miniProgram.redirectTo === 'function') {
miniProgram.redirectTo({ url: '/pages/index/home_page/home_page' })
return
}
} catch (e) {
meetingExited = false
const minimize = minimizingToMiniProgram.value || !ended
if (minimize) {
if (minimizeCloudLawMeeting(cloudLawCallId.value)) return
} else if (notifyCloudLawCallEnded(cloudLawCallId.value)) {
return
}
meetingExited = false
}
uni.reLaunch({ url: '/pages/index/index' })
}
@@ -838,6 +839,7 @@ const syncViewportHeight = () => {
// ============ 生命周期 ============
let stateStopWatch = null
let popstateHandler = null
// P2-3 修复redirectTo 后必须 return避免 onMounted 继续执行闪默认 UI
// 使用 module-scoped 标记onMounted 读取后判断是否提前退出
@@ -845,6 +847,7 @@ let redirectingToJoin = false
onLoad((query) => {
cloudLawRole.value = query?.cloudLawRole || query?.cloud_law_role || ''
cloudLawCallId.value = query?.callId || query?.call_id || ''
if (!cloudLawRole.value) {
// #ifdef H5
try {
@@ -888,12 +891,31 @@ onMounted(() => {
// 会议被主持人/后端结束ENDED 状态)时,弹提示并回首页
stateStopWatch = watch(() => meetingStore.localState, (s) => {
if (s === MEETING_LOCAL_STATE_ENDED) {
if (minimizingToMiniProgram.value) {
minimizingToMiniProgram.value = false
redirectHome(false)
return
}
const reason = meetingStore.lastEndedReason
const label = MEETING_ENDED_REASON_LABEL?.[reason] || '会议已结束'
uni.showToast({ title: label, icon: 'none' })
setTimeout(redirectHome, 1200)
setTimeout(() => redirectHome(true), 1200)
}
})
// #ifdef H5
if (showCloudLawBack.value) {
try {
history.pushState({ cloudLawMeeting: 1 }, '')
popstateHandler = () => {
if (!minimizingToMiniProgram.value) {
onCloudLawBack()
}
}
window.addEventListener('popstate', popstateHandler)
} catch (e) {}
}
// #endif
})
onBeforeUnmount(() => {
@@ -903,6 +925,12 @@ onBeforeUnmount(() => {
}
if (viewportCleanup) { viewportCleanup(); viewportCleanup = null }
if (stateStopWatch) { stateStopWatch(); stateStopWatch = null }
// #ifdef H5
if (popstateHandler) {
window.removeEventListener('popstate', popstateHandler)
popstateHandler = null
}
// #endif
})
onUnload(() => {
@@ -949,6 +977,23 @@ onUnload(() => {
z-index: 1000;
}
.cloud-law-back {
width: 64rpx;
height: 64rpx;
margin-right: 12rpx;
border-radius: 50%;
background: rgba(255, 255, 255, 0.12);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.cloud-law-back-icon {
font-size: 44rpx;
line-height: 1;
color: #FFFFFF;
font-weight: 300;
}
.top-bar {
display: flex;
align-items: center;
@@ -962,6 +1007,14 @@ onUnload(() => {
}
.top-left {
display: flex;
flex-direction: row;
align-items: center;
gap: 6rpx;
min-width: 0;
flex: 1;
}
.top-left-info {
display: flex;
flex-direction: column;
gap: 6rpx;