视频通话

This commit is contained in:
duoaohui
2026-06-07 11:37:19 +08:00
parent 80a913c78e
commit c033b21b02
2 changed files with 43 additions and 11 deletions

View File

@@ -481,7 +481,8 @@ const requestCloudLawCommands = (url) => {
const notifyCloudLawEnd = () => {
if (!callId.value) return Promise.resolve()
const role = isLawRole.value ? 'law' : 'caller'
return notifyCloudLawBackendEnd(callId.value, role, cloudLawApiBase.value, cloudLawToken.value)
const roomCode = meetingStore.currentRoom?.room_code || formattedCode.value || ''
return notifyCloudLawBackendEnd(callId.value, role, cloudLawApiBase.value, cloudLawToken.value, roomCode)
}
const buildMiniProgramReturnUrl = () => {

View File

@@ -16,24 +16,55 @@ export function resolveCloudLawApiUrl(path, apiBase) {
}
/**
* 通知云律后端结束通话(律师端 /api/law/voiceCall用户端 /api/applet/voiceConnection
* 通知云律后端结束通话
* - 律师端:/api/law/voiceCall/{callId}/endPC 同域,带登录态)
* - 用户端:/api/applet/voiceConnection/publicEnd/{callId}?roomCode=xxx
* web-view 跨域调带登录态的 /{callId}/end 会被浏览器 CORS 拦截、根本到不了后端,
* 导致「挂断后 status 一直 accepted、律师端不结束、用户端不跳转」。
* publicEnd 是 @CrossOrigin 公开端点,以 callId+roomCode 配对为凭证,可靠收尾。
*/
export function notifyCloudLawBackendEnd(callId, role = 'law', apiBase = '', token = '') {
export function notifyCloudLawBackendEnd(callId, role = 'law', apiBase = '', token = '', roomCode = '') {
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 isLaw = String(role).toLowerCase() === 'law'
if (isLaw) {
const url = resolveCloudLawApiUrl(`/api/law/voiceCall/${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) })
})
}
// 用户端publicEnd@CrossOrigin 公开端点)。凭证是 URL 里的 callId+roomCode无需 token/body。
// 关键:不能带 application/json 或自定义头,否则触发 CORS 预检;预检失败时浏览器会直接
// 掐掉真正的 POST表现为「按钮触发了但没有请求发到后端」。
// 因此优先用 navigator.sendBeacon简单 POST、无预检、跨域也能到达服务器
const query = roomCode ? `?roomCode=${encodeURIComponent(roomCode)}` : ''
const url = resolveCloudLawApiUrl(`/api/applet/voiceConnection/publicEnd/${encodeURIComponent(callId)}${query}`, apiBase)
console.log('[cloudLawVoiceCall] publicEnd ->', url)
// #ifdef H5
try {
if (typeof navigator !== 'undefined' && typeof navigator.sendBeacon === 'function') {
const ok = navigator.sendBeacon(url)
console.log('[cloudLawVoiceCall] sendBeacon publicEnd result:', ok)
if (ok) return Promise.resolve(true)
}
} catch (e) {
console.warn('[cloudLawVoiceCall] sendBeacon failed', e)
}
// #endif
// 兜底uni.request 不带任何自定义头 / body尽量保持「简单请求」避免预检。
return new Promise(resolve => {
uni.request({
url,
method: 'POST',
data: {},
header,
timeout: 8000,
complete: () => resolve(true)
complete: (res) => {
console.log('[cloudLawVoiceCall] publicEnd request done:', res && res.statusCode)
resolve(true)
}
})
})
}