运营数据
This commit is contained in:
@@ -163,6 +163,11 @@ import {
|
|||||||
} from '@/constants/meeting'
|
} from '@/constants/meeting'
|
||||||
import VideoTile from '@/components/meeting/VideoTile.vue'
|
import VideoTile from '@/components/meeting/VideoTile.vue'
|
||||||
import { minimizeCloudLawMeeting } from '@/utils/cloudLawMiniProgram'
|
import { minimizeCloudLawMeeting } from '@/utils/cloudLawMiniProgram'
|
||||||
|
import {
|
||||||
|
notifyCloudLawBackendEnd,
|
||||||
|
notifyCloudLawParentCallEnded,
|
||||||
|
isCloudLawPcIframe
|
||||||
|
} from '@/utils/cloudLawVoiceCall'
|
||||||
import bgImage from '@/static/bg.png'
|
import bgImage from '@/static/bg.png'
|
||||||
import hangupIcon from '@/static/cacel.png'
|
import hangupIcon from '@/static/cacel.png'
|
||||||
import voiceOnIcon from '@/static/vocie_calling_1.png'
|
import voiceOnIcon from '@/static/vocie_calling_1.png'
|
||||||
@@ -473,17 +478,9 @@ const requestCloudLawCommands = (url) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const notifyCloudLawEnd = () => {
|
const notifyCloudLawEnd = () => {
|
||||||
if (!callId.value || !cloudLawApiBase.value) return Promise.resolve()
|
if (!callId.value) return Promise.resolve()
|
||||||
return new Promise(resolve => {
|
const role = isLawRole.value ? 'law' : 'caller'
|
||||||
uni.request({
|
return notifyCloudLawBackendEnd(callId.value, role, cloudLawApiBase.value, cloudLawToken.value)
|
||||||
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
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildMiniProgramReturnUrl = () => {
|
const buildMiniProgramReturnUrl = () => {
|
||||||
@@ -1113,8 +1110,12 @@ onMounted(() => {
|
|||||||
const label = MEETING_ENDED_REASON_LABEL?.[reason] || '视频咨询已结束'
|
const label = MEETING_ENDED_REASON_LABEL?.[reason] || '视频咨询已结束'
|
||||||
uni.showToast({ title: label, icon: 'none' })
|
uni.showToast({ title: label, icon: 'none' })
|
||||||
ended.value = true
|
ended.value = true
|
||||||
// 对方挂断或会议结束时,通知小程序跳转到「我的咨询详情」
|
// 对方挂断或会议结束时,通知云律后端 + 父页面(PC 律师浮窗)+ 小程序
|
||||||
notifyCloudLawEnd().finally(() => {
|
notifyCloudLawEnd().finally(() => {
|
||||||
|
if (isLawRole.value) {
|
||||||
|
notifyCloudLawParentCallEnded(callId.value)
|
||||||
|
if (isCloudLawPcIframe()) return
|
||||||
|
}
|
||||||
notifyMiniProgramCallEndedOnce()
|
notifyMiniProgramCallEndedOnce()
|
||||||
scheduleEndedRedirect()
|
scheduleEndedRedirect()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ const joinPassword = ref('')
|
|||||||
const autoJoin = ref(false)
|
const autoJoin = ref(false)
|
||||||
const cloudLawRole = ref('')
|
const cloudLawRole = ref('')
|
||||||
const cloudLawCallId = ref('')
|
const cloudLawCallId = ref('')
|
||||||
|
const cloudLawApiBase = ref('')
|
||||||
const initializing = ref(true)
|
const initializing = ref(true)
|
||||||
// autoJoin 失败/超时的可见错误(替代无限"正在进入会议…"转圈)
|
// autoJoin 失败/超时的可见错误(替代无限"正在进入会议…"转圈)
|
||||||
const autoJoinError = ref('')
|
const autoJoinError = ref('')
|
||||||
@@ -472,7 +473,8 @@ const onJoin = async (options = {}) => {
|
|||||||
const roomCode = meetingStore.currentRoom?.room_code
|
const roomCode = meetingStore.currentRoom?.room_code
|
||||||
const roleQ = cloudLawRole.value ? `&cloudLawRole=${encodeURIComponent(cloudLawRole.value)}` : ''
|
const roleQ = cloudLawRole.value ? `&cloudLawRole=${encodeURIComponent(cloudLawRole.value)}` : ''
|
||||||
const callQ = cloudLawCallId.value ? `&callId=${encodeURIComponent(cloudLawCallId.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) {
|
} catch (err) {
|
||||||
const msg = err?.message || JSON.stringify(err)
|
const msg = err?.message || JSON.stringify(err)
|
||||||
// autoJoin 模式下把错误显式呈现在页面(toast 一闪而过,真机很难看清)
|
// autoJoin 模式下把错误显式呈现在页面(toast 一闪而过,真机很难看清)
|
||||||
@@ -498,6 +500,7 @@ onLoad(async (query) => {
|
|||||||
joinCode.value = query?.code || ''
|
joinCode.value = query?.code || ''
|
||||||
cloudLawRole.value = query?.cloudLawRole || query?.cloud_law_role || ''
|
cloudLawRole.value = query?.cloudLawRole || query?.cloud_law_role || ''
|
||||||
cloudLawCallId.value = query?.callId || query?.call_id || ''
|
cloudLawCallId.value = query?.callId || query?.call_id || ''
|
||||||
|
cloudLawApiBase.value = query?.cloudLawApiBase || query?.cloud_law_api_base || ''
|
||||||
if (isCloudLaw.value) {
|
if (isCloudLaw.value) {
|
||||||
try {
|
try {
|
||||||
uni.setNavigationBarTitle({ title: '用户视频咨询' })
|
uni.setNavigationBarTitle({ title: '用户视频咨询' })
|
||||||
|
|||||||
@@ -238,6 +238,12 @@ import {
|
|||||||
minimizeCloudLawMeeting,
|
minimizeCloudLawMeeting,
|
||||||
notifyCloudLawCallEnded
|
notifyCloudLawCallEnded
|
||||||
} from '@/utils/cloudLawMiniProgram'
|
} from '@/utils/cloudLawMiniProgram'
|
||||||
|
import {
|
||||||
|
isCloudLawLawRoleInMeeting,
|
||||||
|
isCloudLawPcIframe,
|
||||||
|
notifyCloudLawBackendEnd,
|
||||||
|
notifyCloudLawParentCallEnded
|
||||||
|
} from '@/utils/cloudLawVoiceCall'
|
||||||
|
|
||||||
const meetingStore = useMeetingStore()
|
const meetingStore = useMeetingStore()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
@@ -245,6 +251,7 @@ const userStore = useUserStore()
|
|||||||
/** 云律律师端:工具栏用共享屏幕替换聊天 */
|
/** 云律律师端:工具栏用共享屏幕替换聊天 */
|
||||||
const cloudLawRole = ref('')
|
const cloudLawRole = ref('')
|
||||||
const cloudLawCallId = ref('')
|
const cloudLawCallId = ref('')
|
||||||
|
const cloudLawApiBase = ref('')
|
||||||
const minimizingToMiniProgram = ref(false)
|
const minimizingToMiniProgram = ref(false)
|
||||||
const replaceChatWithScreenShare = computed(() => String(cloudLawRole.value).toLowerCase() === 'law')
|
const replaceChatWithScreenShare = computed(() => String(cloudLawRole.value).toLowerCase() === 'law')
|
||||||
const showCloudLawBack = computed(() => isCloudLawEmbed() && isCloudLawLawRole(cloudLawRole.value))
|
const showCloudLawBack = computed(() => isCloudLawEmbed() && isCloudLawLawRole(cloudLawRole.value))
|
||||||
@@ -848,6 +855,7 @@ let redirectingToJoin = false
|
|||||||
onLoad((query) => {
|
onLoad((query) => {
|
||||||
cloudLawRole.value = query?.cloudLawRole || query?.cloud_law_role || ''
|
cloudLawRole.value = query?.cloudLawRole || query?.cloud_law_role || ''
|
||||||
cloudLawCallId.value = query?.callId || query?.call_id || ''
|
cloudLawCallId.value = query?.callId || query?.call_id || ''
|
||||||
|
cloudLawApiBase.value = query?.cloudLawApiBase || query?.cloud_law_api_base || ''
|
||||||
if (!cloudLawRole.value) {
|
if (!cloudLawRole.value) {
|
||||||
// #ifdef H5
|
// #ifdef H5
|
||||||
try {
|
try {
|
||||||
@@ -899,6 +907,14 @@ onMounted(() => {
|
|||||||
const reason = meetingStore.lastEndedReason
|
const reason = meetingStore.lastEndedReason
|
||||||
const label = MEETING_ENDED_REASON_LABEL?.[reason] || '会议已结束'
|
const label = MEETING_ENDED_REASON_LABEL?.[reason] || '会议已结束'
|
||||||
uni.showToast({ title: label, icon: 'none' })
|
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)
|
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