电话咨询

This commit is contained in:
duoaohui
2026-06-04 12:23:14 +08:00
parent 6727259e8b
commit 3b51aba8ec
8 changed files with 172 additions and 48 deletions

View File

@@ -10,6 +10,9 @@
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<!-- 微信 JSSDKH5 在小程序 web-view 内需要它才能调用 wx.miniProgram.redirectTo/navigateBack 等,
否则视频结束后无法驱动外层小程序跳转PC/普通浏览器加载它无副作用) -->
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<!--preload-links-->
<!--app-context-->
</head>

View File

@@ -245,15 +245,21 @@ const emitIf = (name) => {
width: 72rpx;
height: 72rpx;
border-radius: 50%;
background: rgba(55, 65, 81, 0.9);
background: linear-gradient(180deg, rgba(71, 85, 105, 0.95), rgba(51, 65, 81, 0.95));
display: flex;
align-items: center;
justify-content: center;
color: #FFFFFF;
transition: background-color 0.15s ease;
box-shadow: inset 0 1rpx 0 rgba(255, 255, 255, 0.12), 0 4rpx 10rpx rgba(0, 0, 0, 0.28);
transition: background 0.18s ease, transform 0.12s ease, box-shadow 0.18s ease;
}
.btn.active .icon { background: #3B82F6; }
.btn.active .icon {
background: linear-gradient(180deg, #4F8DFF, #2563EB);
box-shadow: inset 0 1rpx 0 rgba(255, 255, 255, 0.28), 0 4rpx 14rpx rgba(37, 99, 235, 0.5);
}
.btn.active .label { color: #BFDBFE; }
.btn.loading .icon { opacity: 0.6; }
.btn:active .icon { transform: scale(0.92); }
.label {
font-size: 22rpx;
@@ -262,8 +268,12 @@ const emitIf = (name) => {
}
.label-mobile { display: none; }
.btn-leave .icon { background: #EF4444; }
.btn-leave:hover .icon { background: #DC2626; }
.btn-leave .icon {
background: linear-gradient(180deg, #FB5B5B, #EF4444);
box-shadow: inset 0 1rpx 0 rgba(255, 255, 255, 0.28), 0 4rpx 14rpx rgba(239, 68, 68, 0.5);
}
.btn-leave:hover .icon { background: linear-gradient(180deg, #F87171, #DC2626); }
.btn-leave .label { color: #FECACA; }
/* Phase B 录制按钮:录制中红色脉动 */
.btn-recording.is-recording .icon {
@@ -283,16 +293,17 @@ const emitIf = (name) => {
height: 32rpx;
padding: 0 6rpx;
border-radius: 999rpx;
background: #10B981;
background: linear-gradient(180deg, #34D399, #10B981);
color: #FFFFFF;
font-size: 18rpx;
font-weight: 600;
font-weight: 700;
display: inline-flex;
align-items: center;
justify-content: center;
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.4);
border: 2rpx solid rgba(13, 21, 38, 0.95);
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.45);
}
.badge.badge-red { background: #EF4444; }
.badge.badge-red { background: linear-gradient(180deg, #FB7185, #EF4444); }
@media (max-width: 750px) {
.toolbar {
@@ -301,52 +312,61 @@ const emitIf = (name) => {
right: 14rpx;
bottom: calc(12rpx + env(safe-area-inset-bottom));
justify-content: space-between;
gap: 6rpx;
gap: 4rpx;
box-sizing: border-box;
padding: 14rpx 14rpx;
background: rgba(7, 15, 30, 0.9);
backdrop-filter: blur(18px);
border: 1rpx solid rgba(148, 163, 184, 0.18);
border-radius: 32rpx;
box-shadow: 0 12rpx 34rpx rgba(0, 0, 0, 0.42);
padding: 18rpx 12rpx;
background: linear-gradient(180deg, rgba(17, 26, 46, 0.92), rgba(7, 15, 30, 0.94));
backdrop-filter: blur(20px);
border: 1rpx solid rgba(148, 163, 184, 0.2);
border-radius: 34rpx;
box-shadow: 0 16rpx 40rpx rgba(0, 0, 0, 0.48), inset 0 1rpx 0 rgba(255, 255, 255, 0.06);
overflow-x: hidden;
overflow-y: hidden;
}
.btn {
min-width: 0;
flex: 1 1 0;
gap: 6rpx;
gap: 10rpx;
padding: 4rpx 0;
border-radius: 18rpx;
}
.btn:hover { background: transparent; }
.btn:active { background: rgba(255, 255, 255, 0.08); }
.btn:active { background: transparent; }
.btn:active .icon { transform: scale(0.9); }
.btn-screen {
display: none;
}
.icon {
width: 56rpx;
height: 56rpx;
background: rgba(51, 65, 85, 0.92);
box-shadow: inset 0 0 0 1rpx rgba(255, 255, 255, 0.08);
width: 64rpx;
height: 64rpx;
background: linear-gradient(180deg, rgba(71, 85, 105, 0.95), rgba(44, 56, 78, 0.96));
box-shadow: inset 0 1rpx 0 rgba(255, 255, 255, 0.12), 0 6rpx 16rpx rgba(0, 0, 0, 0.36);
}
.icon svg {
width: 40rpx;
height: 40rpx;
width: 42rpx;
height: 42rpx;
}
.btn.active .icon {
background: linear-gradient(180deg, #4F8DFF, #2563EB);
box-shadow: inset 0 1rpx 0 rgba(255, 255, 255, 0.3), 0 6rpx 18rpx rgba(37, 99, 235, 0.55);
}
.btn.active .icon { background: #2563EB; }
.btn[disabled] .icon {
background: rgba(30, 41, 59, 0.72);
color: rgba(255, 255, 255, 0.38);
box-shadow: inset 0 0 0 1rpx rgba(255, 255, 255, 0.05);
}
.btn[disabled] .label { color: rgba(255, 255, 255, 0.36); }
.btn-leave .icon { background: #EF4444; }
.btn-leave .icon {
background: linear-gradient(180deg, #FB5B5B, #EF4444);
box-shadow: inset 0 1rpx 0 rgba(255, 255, 255, 0.3), 0 6rpx 18rpx rgba(239, 68, 68, 0.55);
}
.btn-leave .label { color: #FECACA; }
.label {
max-width: 100%;
font-size: 19rpx;
font-size: 20rpx;
line-height: 1;
font-weight: 500;
color: rgba(255, 255, 255, 0.74);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -370,15 +390,15 @@ const emitIf = (name) => {
padding-right: 8rpx;
}
.icon {
width: 50rpx;
height: 50rpx;
width: 56rpx;
height: 56rpx;
}
.icon svg {
width: 36rpx;
height: 36rpx;
width: 38rpx;
height: 38rpx;
}
.label {
font-size: 17rpx;
font-size: 18rpx;
}
}
</style>

View File

@@ -427,25 +427,43 @@ const buildMiniProgramReturnUrl = () => {
}
let endedRedirectTimer = null
let miniProgramRedirected = false
const getMiniProgram = () => {
return typeof window !== 'undefined' && window.wx && window.wx.miniProgram ? window.wx.miniProgram : null
}
const notifyMiniProgramCallEnded = () => {
const returnUrl = buildMiniProgramReturnUrl()
const payload = {
type: 'cloudLawCallEnded',
action: 'cloudLawCallEnded',
callId: callId.value,
consultId: consultId.value,
returnUrl: buildMiniProgramReturnUrl()
returnUrl
}
const miniProgram = getMiniProgram()
try {
const miniProgram = typeof window !== 'undefined' && window.wx && window.wx.miniProgram ? window.wx.miniProgram : null
// postMessage 只在 web-view 销毁/分享等时机投递;先发一份,作为小程序侧 onMessage 的兜底
if (miniProgram && typeof miniProgram.postMessage === 'function') {
miniProgram.postMessage({ data: payload })
}
if (miniProgram && typeof miniProgram.redirectTo === 'function' && payload.returnUrl) {
miniProgram.redirectTo({ url: payload.returnUrl })
} catch (e) {
console.warn('[CloudLawVideoCall] postMessage failed', e)
}
if (miniProgramRedirected) return
try {
if (miniProgram && returnUrl && typeof miniProgram.redirectTo === 'function') {
miniProgramRedirected = true
miniProgram.redirectTo({ url: returnUrl })
} else if (miniProgram && typeof miniProgram.navigateBack === 'function') {
// 没有可跳转的咨询详情地址时,至少退回上一页(等待页),由小程序侧轮询兜底跳转
miniProgramRedirected = true
miniProgram.navigateBack({ delta: 1 })
}
} catch (e) {
console.warn('[CloudLawVideoCall] notify mini program failed', e)
miniProgramRedirected = false
console.warn('[CloudLawVideoCall] redirect mini program failed', e)
}
}

View File

@@ -739,15 +739,21 @@ const onLeaveClick = () => { leaveDialogVisible.value = true }
const confirmLeaveSelf = async () => {
leaveDialogVisible.value = false
let failed = false
try {
await meetingStore.leave()
} catch (err) {
failed = true
uni.showToast({ title: err?.message || '操作失败', icon: 'none' })
} finally {
redirectHome()
leaveAndExit(failed ? '' : '已离开会议')
}
}
const confirmEndOrLeave = async () => {
leaveDialogVisible.value = false
const tip = isHost.value ? '会议已结束' : '已离开会议'
let failed = false
try {
if (isHost.value) {
await meetingStore.endMeeting()
@@ -757,13 +763,61 @@ const confirmEndOrLeave = async () => {
await meetingStore.leave()
}
} catch (err) {
failed = true
uni.showToast({ title: err?.message || '操作失败', icon: 'none' })
} finally {
redirectHome()
leaveAndExit(failed ? '' : tip)
}
}
// 是否运行在云律小程序 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) => {
if (tip) {
uni.showToast({ title: tip, icon: 'none', duration: 1200 })
}
// 留一点时间让提示可见,再退出视频界面
setTimeout(redirectHome, tip ? 600 : 200)
}
let meetingExited = false
const redirectHome = () => {
if (meetingExited) return
const miniProgram = getMiniProgram()
if (isCloudLawEmbed() && miniProgram) {
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
}
}
uni.reLaunch({ url: '/pages/index/index' })
}