电话咨询
This commit is contained in:
@@ -162,6 +162,7 @@ import {
|
||||
MEETING_ENDED_REASON_LABEL
|
||||
} from '@/constants/meeting'
|
||||
import VideoTile from '@/components/meeting/VideoTile.vue'
|
||||
import { minimizeCloudLawMeeting } from '@/utils/cloudLawMiniProgram'
|
||||
import bgImage from '@/static/bg.png'
|
||||
import hangupIcon from '@/static/cacel.png'
|
||||
import voiceOnIcon from '@/static/vocie_calling_1.png'
|
||||
@@ -1003,28 +1004,9 @@ const minimizeToMiniProgram = () => {
|
||||
minimizingToMiniProgram.value = true
|
||||
stopCommandPolling()
|
||||
meetingStore.leave().catch(() => {})
|
||||
const mp = getMiniProgram()
|
||||
try {
|
||||
if (mp && typeof mp.postMessage === 'function') {
|
||||
mp.postMessage({
|
||||
data: {
|
||||
type: 'cloudLawMinimized',
|
||||
action: 'cloudLawMinimized',
|
||||
callId: callId.value
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[CloudLawVideoCall] minimize postMessage failed', e)
|
||||
}
|
||||
try {
|
||||
if (mp && typeof mp.navigateBack === 'function') {
|
||||
mp.navigateBack({ delta: 1 })
|
||||
if (minimizeCloudLawMeeting(callId.value)) {
|
||||
return
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[CloudLawVideoCall] minimize navigateBack failed', e)
|
||||
}
|
||||
minimizingToMiniProgram.value = false
|
||||
uni.showToast({ title: '请使用左上角返回', icon: 'none' })
|
||||
}
|
||||
|
||||
@@ -115,6 +115,7 @@ import { ref, reactive, computed, onBeforeUnmount, nextTick } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { useMeetingStore } from '@/store/meeting'
|
||||
import { useUserStore } from '@/store/user'
|
||||
import { isCloudLawEmbed, isCloudLawLawRole, minimizeCloudLawMeeting } from '@/utils/cloudLawMiniProgram'
|
||||
|
||||
const meetingStore = useMeetingStore()
|
||||
const userStore = useUserStore()
|
||||
@@ -124,6 +125,7 @@ const joinCode = ref('')
|
||||
const joinPassword = ref('')
|
||||
const autoJoin = ref(false)
|
||||
const cloudLawRole = ref('')
|
||||
const cloudLawCallId = ref('')
|
||||
const initializing = ref(true)
|
||||
// autoJoin 失败/超时的可见错误(替代无限"正在进入会议…"转圈)
|
||||
const autoJoinError = ref('')
|
||||
@@ -372,6 +374,10 @@ const onToggleVideoDefault = (e) => { mediaPrefs.startVideo = e.detail.value }
|
||||
const onToggleAudioDefault = (e) => { mediaPrefs.startAudio = e.detail.value }
|
||||
|
||||
const onCancel = () => {
|
||||
if (isCloudLawEmbed() && isCloudLawLawRole(cloudLawRole.value)) {
|
||||
minimizeCloudLawMeeting(cloudLawCallId.value)
|
||||
return
|
||||
}
|
||||
uni.navigateBack()
|
||||
}
|
||||
|
||||
@@ -398,16 +404,10 @@ const retryAutoJoin = () => {
|
||||
|
||||
const exitAutoJoin = () => {
|
||||
clearAutoJoinWatchdog()
|
||||
// 云律小程序 web-view 内:返回到小程序;否则回上一步
|
||||
try {
|
||||
const embedded = typeof window !== 'undefined' && window.sessionStorage
|
||||
&& window.sessionStorage.getItem('echo_cloud_law_meeting_embed') === '1'
|
||||
const mp = typeof window !== 'undefined' && window.wx && window.wx.miniProgram ? window.wx.miniProgram : null
|
||||
if (embedded && mp && typeof mp.navigateBack === 'function') {
|
||||
mp.navigateBack({ delta: 1 })
|
||||
if (isCloudLawEmbed() && isCloudLawLawRole(cloudLawRole.value)) {
|
||||
minimizeCloudLawMeeting(cloudLawCallId.value)
|
||||
return
|
||||
}
|
||||
} catch (e) {}
|
||||
onCancel()
|
||||
}
|
||||
|
||||
@@ -469,7 +469,8 @@ const onJoin = async (options = {}) => {
|
||||
}
|
||||
const roomCode = meetingStore.currentRoom?.room_code
|
||||
const roleQ = cloudLawRole.value ? `&cloudLawRole=${encodeURIComponent(cloudLawRole.value)}` : ''
|
||||
uni.redirectTo({ url: `/pages/meeting/room${roomCode ? `?code=${roomCode}${roleQ}` : (roleQ ? `?${roleQ.slice(1)}` : '')}` })
|
||||
const callQ = cloudLawCallId.value ? `&callId=${encodeURIComponent(cloudLawCallId.value)}` : ''
|
||||
uni.redirectTo({ url: `/pages/meeting/room${roomCode ? `?code=${roomCode}${roleQ}${callQ}` : `${roleQ || callQ ? `?${(roleQ + callQ).replace(/^&/, '')}` : ''}`}` })
|
||||
} catch (err) {
|
||||
const msg = err?.message || JSON.stringify(err)
|
||||
// autoJoin 模式下把错误显式呈现在页面(toast 一闪而过,真机很难看清)
|
||||
@@ -494,6 +495,7 @@ onLoad(async (query) => {
|
||||
mode.value = query?.mode === 'join' ? 'join' : 'create'
|
||||
joinCode.value = query?.code || ''
|
||||
cloudLawRole.value = query?.cloudLawRole || query?.cloud_law_role || ''
|
||||
cloudLawCallId.value = query?.callId || query?.call_id || ''
|
||||
autoJoin.value = query?.autoJoin === '1' || query?.autoJoin === 'true' || query?.autoJoin === true
|
||||
// #ifdef H5
|
||||
if (String(cloudLawRole.value).toLowerCase() === 'law') {
|
||||
|
||||
@@ -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>
|
||||
@@ -24,6 +28,7 @@
|
||||
</svg>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="top-right">
|
||||
<view class="state-pill" :class="stateClass">
|
||||
<view class="state-dot"></view>
|
||||
@@ -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,54 +802,28 @@ 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 })
|
||||
const minimize = minimizingToMiniProgram.value || !ended
|
||||
if (minimize) {
|
||||
if (minimizeCloudLawMeeting(cloudLawCallId.value)) return
|
||||
} else if (notifyCloudLawCallEnded(cloudLawCallId.value)) {
|
||||
return
|
||||
}
|
||||
if (typeof miniProgram.redirectTo === 'function') {
|
||||
miniProgram.redirectTo({ url: '/pages/index/home_page/home_page' })
|
||||
return
|
||||
}
|
||||
} catch (e) {
|
||||
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;
|
||||
|
||||
80
frontend/src/utils/cloudLawMiniProgram.js
Normal file
80
frontend/src/utils/cloudLawMiniProgram.js
Normal file
@@ -0,0 +1,80 @@
|
||||
/** 云律小程序 web-view 内与原生壳通信(返回会议浮窗 / 挂断) */
|
||||
|
||||
export function getMiniProgram() {
|
||||
return typeof window !== 'undefined' && window.wx && window.wx.miniProgram ? window.wx.miniProgram : null
|
||||
}
|
||||
|
||||
export function isCloudLawEmbed() {
|
||||
try {
|
||||
return typeof window !== 'undefined'
|
||||
&& !!window.sessionStorage
|
||||
&& window.sessionStorage.getItem('echo_cloud_law_meeting_embed') === '1'
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function isCloudLawLawRole(role) {
|
||||
if (String(role || '').toLowerCase() === 'law') return true
|
||||
try {
|
||||
return window.sessionStorage.getItem('echo_cloud_law_meeting_role') === 'law'
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/** 律师端返回上一页:会议仍在进行,通知小程序弹出「返回会议」浮窗 */
|
||||
export function minimizeCloudLawMeeting(callId = '') {
|
||||
const mp = getMiniProgram()
|
||||
if (!isCloudLawEmbed() || !mp) return false
|
||||
try {
|
||||
if (typeof mp.postMessage === 'function') {
|
||||
mp.postMessage({
|
||||
data: {
|
||||
type: 'cloudLawMinimized',
|
||||
action: 'cloudLawMinimized',
|
||||
callId: String(callId || '')
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[cloudLawMiniProgram] minimize postMessage failed', e)
|
||||
}
|
||||
try {
|
||||
if (typeof mp.navigateBack === 'function') {
|
||||
mp.navigateBack({ delta: 1 })
|
||||
return true
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[cloudLawMiniProgram] minimize navigateBack failed', e)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/** 会议真正结束:通知小程序释放占用 */
|
||||
export function notifyCloudLawCallEnded(callId = '') {
|
||||
const mp = getMiniProgram()
|
||||
if (!isCloudLawEmbed() || !mp) return false
|
||||
try {
|
||||
if (typeof mp.postMessage === 'function') {
|
||||
mp.postMessage({
|
||||
data: {
|
||||
type: 'cloudLawCallEnded',
|
||||
action: 'cloudLawCallEnded',
|
||||
callId: String(callId || '')
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[cloudLawMiniProgram] ended postMessage failed', e)
|
||||
}
|
||||
try {
|
||||
if (typeof mp.navigateBack === 'function') {
|
||||
mp.navigateBack({ delta: 1 })
|
||||
return true
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[cloudLawMiniProgram] ended navigateBack failed', e)
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user