运营数据
This commit is contained in:
@@ -163,6 +163,11 @@ import {
|
||||
} from '@/constants/meeting'
|
||||
import VideoTile from '@/components/meeting/VideoTile.vue'
|
||||
import { minimizeCloudLawMeeting } from '@/utils/cloudLawMiniProgram'
|
||||
import {
|
||||
notifyCloudLawBackendEnd,
|
||||
notifyCloudLawParentCallEnded,
|
||||
isCloudLawPcIframe
|
||||
} from '@/utils/cloudLawVoiceCall'
|
||||
import bgImage from '@/static/bg.png'
|
||||
import hangupIcon from '@/static/cacel.png'
|
||||
import voiceOnIcon from '@/static/vocie_calling_1.png'
|
||||
@@ -473,17 +478,9 @@ const requestCloudLawCommands = (url) => {
|
||||
}
|
||||
|
||||
const notifyCloudLawEnd = () => {
|
||||
if (!callId.value || !cloudLawApiBase.value) return Promise.resolve()
|
||||
return new Promise(resolve => {
|
||||
uni.request({
|
||||
url: resolveCloudLawApiUrl(`${voiceEndBase.value}/${encodeURIComponent(callId.value)}/end`),
|
||||
method: 'POST',
|
||||
data: {},
|
||||
header: cloudLawToken.value ? { 'Content-Type': 'application/json', token: `Bearer ${cloudLawToken.value}` } : { 'Content-Type': 'application/json' },
|
||||
timeout: 5000,
|
||||
complete: resolve
|
||||
})
|
||||
})
|
||||
if (!callId.value) return Promise.resolve()
|
||||
const role = isLawRole.value ? 'law' : 'caller'
|
||||
return notifyCloudLawBackendEnd(callId.value, role, cloudLawApiBase.value, cloudLawToken.value)
|
||||
}
|
||||
|
||||
const buildMiniProgramReturnUrl = () => {
|
||||
@@ -1113,8 +1110,12 @@ onMounted(() => {
|
||||
const label = MEETING_ENDED_REASON_LABEL?.[reason] || '视频咨询已结束'
|
||||
uni.showToast({ title: label, icon: 'none' })
|
||||
ended.value = true
|
||||
// 对方挂断或会议结束时,通知小程序跳转到「我的咨询详情」
|
||||
// 对方挂断或会议结束时,通知云律后端 + 父页面(PC 律师浮窗)+ 小程序
|
||||
notifyCloudLawEnd().finally(() => {
|
||||
if (isLawRole.value) {
|
||||
notifyCloudLawParentCallEnded(callId.value)
|
||||
if (isCloudLawPcIframe()) return
|
||||
}
|
||||
notifyMiniProgramCallEndedOnce()
|
||||
scheduleEndedRedirect()
|
||||
})
|
||||
|
||||
@@ -126,6 +126,7 @@ const joinPassword = ref('')
|
||||
const autoJoin = ref(false)
|
||||
const cloudLawRole = ref('')
|
||||
const cloudLawCallId = ref('')
|
||||
const cloudLawApiBase = ref('')
|
||||
const initializing = ref(true)
|
||||
// autoJoin 失败/超时的可见错误(替代无限"正在进入会议…"转圈)
|
||||
const autoJoinError = ref('')
|
||||
@@ -472,7 +473,8 @@ const onJoin = async (options = {}) => {
|
||||
const roomCode = meetingStore.currentRoom?.room_code
|
||||
const roleQ = cloudLawRole.value ? `&cloudLawRole=${encodeURIComponent(cloudLawRole.value)}` : ''
|
||||
const callQ = cloudLawCallId.value ? `&callId=${encodeURIComponent(cloudLawCallId.value)}` : ''
|
||||
uni.redirectTo({ url: `/pages/meeting/room${roomCode ? `?code=${roomCode}${roleQ}${callQ}` : `${roleQ || callQ ? `?${(roleQ + callQ).replace(/^&/, '')}` : ''}`}` })
|
||||
const apiBaseQ = cloudLawApiBase.value ? `&cloudLawApiBase=${encodeURIComponent(cloudLawApiBase.value)}` : ''
|
||||
uni.redirectTo({ url: `/pages/meeting/room${roomCode ? `?code=${roomCode}${roleQ}${callQ}${apiBaseQ}` : `${roleQ || callQ || apiBaseQ ? `?${(roleQ + callQ + apiBaseQ).replace(/^&/, '')}` : ''}`}` })
|
||||
} catch (err) {
|
||||
const msg = err?.message || JSON.stringify(err)
|
||||
// autoJoin 模式下把错误显式呈现在页面(toast 一闪而过,真机很难看清)
|
||||
@@ -498,6 +500,7 @@ onLoad(async (query) => {
|
||||
joinCode.value = query?.code || ''
|
||||
cloudLawRole.value = query?.cloudLawRole || query?.cloud_law_role || ''
|
||||
cloudLawCallId.value = query?.callId || query?.call_id || ''
|
||||
cloudLawApiBase.value = query?.cloudLawApiBase || query?.cloud_law_api_base || ''
|
||||
if (isCloudLaw.value) {
|
||||
try {
|
||||
uni.setNavigationBarTitle({ title: '用户视频咨询' })
|
||||
|
||||
@@ -238,6 +238,12 @@ import {
|
||||
minimizeCloudLawMeeting,
|
||||
notifyCloudLawCallEnded
|
||||
} from '@/utils/cloudLawMiniProgram'
|
||||
import {
|
||||
isCloudLawLawRoleInMeeting,
|
||||
isCloudLawPcIframe,
|
||||
notifyCloudLawBackendEnd,
|
||||
notifyCloudLawParentCallEnded
|
||||
} from '@/utils/cloudLawVoiceCall'
|
||||
|
||||
const meetingStore = useMeetingStore()
|
||||
const userStore = useUserStore()
|
||||
@@ -245,6 +251,7 @@ const userStore = useUserStore()
|
||||
/** 云律律师端:工具栏用共享屏幕替换聊天 */
|
||||
const cloudLawRole = ref('')
|
||||
const cloudLawCallId = ref('')
|
||||
const cloudLawApiBase = ref('')
|
||||
const minimizingToMiniProgram = ref(false)
|
||||
const replaceChatWithScreenShare = computed(() => String(cloudLawRole.value).toLowerCase() === 'law')
|
||||
const showCloudLawBack = computed(() => isCloudLawEmbed() && isCloudLawLawRole(cloudLawRole.value))
|
||||
@@ -848,6 +855,7 @@ let redirectingToJoin = false
|
||||
onLoad((query) => {
|
||||
cloudLawRole.value = query?.cloudLawRole || query?.cloud_law_role || ''
|
||||
cloudLawCallId.value = query?.callId || query?.call_id || ''
|
||||
cloudLawApiBase.value = query?.cloudLawApiBase || query?.cloud_law_api_base || ''
|
||||
if (!cloudLawRole.value) {
|
||||
// #ifdef H5
|
||||
try {
|
||||
@@ -899,6 +907,14 @@ onMounted(() => {
|
||||
const reason = meetingStore.lastEndedReason
|
||||
const label = MEETING_ENDED_REASON_LABEL?.[reason] || '会议已结束'
|
||||
uni.showToast({ title: label, icon: 'none' })
|
||||
// 云律律师端(含 PC iframe):用户挂断后同步云律后端 + 通知父页面释放浮窗
|
||||
if (isCloudLawLawRoleInMeeting(cloudLawRole.value) && cloudLawCallId.value) {
|
||||
notifyCloudLawBackendEnd(cloudLawCallId.value, 'law', cloudLawApiBase.value)
|
||||
notifyCloudLawParentCallEnded(cloudLawCallId.value)
|
||||
if (isCloudLawPcIframe()) {
|
||||
return
|
||||
}
|
||||
}
|
||||
setTimeout(() => redirectHome(true), 1200)
|
||||
}
|
||||
})
|
||||
|
||||
72
frontend/src/utils/cloudLawVoiceCall.js
Normal file
72
frontend/src/utils/cloudLawVoiceCall.js
Normal file
@@ -0,0 +1,72 @@
|
||||
/** 云律视频咨询:iframe / web-view 内通知云律后端结束通话,并通知父页面(律师 PC 浮窗)释放状态 */
|
||||
|
||||
export function getCloudLawApiBase(explicitBase) {
|
||||
const base = String(explicitBase || '').trim().replace(/\/+$/, '')
|
||||
if (base) return base
|
||||
if (typeof window !== 'undefined' && window.location && window.location.origin) {
|
||||
return window.location.origin
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
export function resolveCloudLawApiUrl(path, apiBase) {
|
||||
const base = getCloudLawApiBase(apiBase)
|
||||
const normalizedPath = path.startsWith('/') ? path : `/${path}`
|
||||
return `${base}${normalizedPath}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 通知云律后端结束通话(律师端 /api/law/voiceCall,用户端 /api/applet/voiceConnection)
|
||||
*/
|
||||
export function notifyCloudLawBackendEnd(callId, role = 'law', apiBase = '', token = '') {
|
||||
if (!callId) return Promise.resolve(false)
|
||||
const endBase = String(role).toLowerCase() === 'law' ? '/api/law/voiceCall' : '/api/applet/voiceConnection'
|
||||
const url = resolveCloudLawApiUrl(`${endBase}/${encodeURIComponent(callId)}/end`, apiBase)
|
||||
const header = { 'Content-Type': 'application/json' }
|
||||
if (token) {
|
||||
header.token = token.startsWith('Bearer') ? token : `Bearer ${token}`
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
uni.request({
|
||||
url,
|
||||
method: 'POST',
|
||||
data: {},
|
||||
header,
|
||||
timeout: 8000,
|
||||
complete: () => resolve(true)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/** PC 律师端 iframe 会议结束时,通知父页面(outbound 浮窗)清除「会议进行中」状态 */
|
||||
export function notifyCloudLawParentCallEnded(callId = '') {
|
||||
if (typeof window === 'undefined') return false
|
||||
try {
|
||||
if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage({
|
||||
type: 'cloudLawCallEnded',
|
||||
action: 'cloudLawCallEnded',
|
||||
callId: String(callId || '')
|
||||
}, '*')
|
||||
return true
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[cloudLawVoiceCall] parent postMessage failed', e)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export function isCloudLawLawRoleInMeeting(role) {
|
||||
if (String(role || '').toLowerCase() === 'law') return true
|
||||
try {
|
||||
return typeof window !== 'undefined'
|
||||
&& window.sessionStorage
|
||||
&& window.sessionStorage.getItem('echo_cloud_law_meeting_role') === 'law'
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function isCloudLawPcIframe() {
|
||||
return typeof window !== 'undefined' && !!(window.parent && window.parent !== window)
|
||||
}
|
||||
Reference in New Issue
Block a user