电话咨询

This commit is contained in:
duoaohui
2026-06-04 14:58:03 +08:00
parent b89b930c41
commit 3ffdaa30d9
4 changed files with 159 additions and 6 deletions

View File

@@ -96,7 +96,17 @@
</view>
<view class="controls-row controls-row-bottom">
<view class="control-item" @click="takeSnapshot" @tap="takeSnapshot">
<!-- 律师端底部左侧为共享屏幕替代通用会议页聊天能力 -->
<view v-if="isLawRole" class="control-item" @click="onScreenToggle" @tap="onScreenToggle">
<view
class="control-btn dark-btn text-icon-btn"
:class="{ active: screenSharingByMe, loading: screenLoading, disabled: screenDisabled && !screenSharingByMe }"
>
<text class="text-icon">{{ screenSharingByMe ? '停' : '屏' }}</text>
</view>
<text class="control-label">{{ screenSharingByMe ? '停止共享' : '共享屏幕' }}</text>
</view>
<view v-else class="control-item" @click="takeSnapshot" @tap="takeSnapshot">
<view class="control-btn dark-btn text-icon-btn">
<image v-if="!captureIconError" class="control-image" :src="captureIcon" mode="aspectFit" @error="captureIconError = true"></image>
<text v-else class="text-icon"></text>
@@ -177,6 +187,7 @@ const joining = ref(false)
const joinError = ref('')
const audioLoading = ref(false)
const videoLoading = ref(false)
const screenLoading = ref(false)
const leaving = ref(false)
const startedAt = ref(0)
const nowTs = ref(Date.now())
@@ -244,7 +255,56 @@ const participants = computed(() => {
const localTrackVersion = computed(() => {
const producers = meetingStore.localProducers || {}
return `${producers.audio || ''}-${producers.video || ''}`
return `${producers.audio || ''}-${producers.video || ''}-${producers.screen || ''}`
})
const screenSharingActive = computed(() => !!meetingStore.screenShare?.ownerUserId)
const screenSharingByMe = computed(() => {
const owner = meetingStore.screenShare?.ownerUserId
return !!owner && sameUser(owner, myUserId.value)
})
const screenSupported = computed(() => {
// #ifdef H5
return typeof navigator !== 'undefined' &&
!!navigator.mediaDevices &&
typeof navigator.mediaDevices.getDisplayMedia === 'function'
// #endif
// #ifndef H5
return false
// #endif
})
const screenDisabled = computed(() => {
if (!screenSupported.value) return true
if (screenSharingActive.value && !screenSharingByMe.value) return true
return false
})
const screenDisabledReason = computed(() => {
if (!screenSupported.value) return '当前环境不支持屏幕共享'
if (screenSharingActive.value && !screenSharingByMe.value) return '已有成员正在共享屏幕'
return ''
})
const screenTile = computed(() => {
const owner = meetingStore.screenShare?.ownerUserId
if (!owner) return null
localTrackVersion.value
remoteTrackVersion.value
const isLocal = sameUser(owner, myUserId.value)
const track = isLocal
? meetingStore.getLocalTrack('screen')
: meetingStore.getRemoteTrack(owner, 'screen')
if (!track) return null
return {
key: `screen_${owner}`,
userId: owner,
name: isLocal ? '你' : nameOf(owner),
isLocal,
isHost: sameUser(owner, hostId.value),
audioEnabled: false,
videoEnabled: true,
audioTrack: null,
videoTrack: track
}
})
const remoteTrackVersion = computed(() => {
@@ -252,7 +312,7 @@ const remoteTrackVersion = computed(() => {
const map = meetingStore.remoteConsumers || {}
Object.keys(map).forEach(uid => {
const slot = map[uid]
parts.push(`${uid}:${slot?.audio?.id || ''}:${slot?.video?.id || ''}`)
parts.push(`${uid}:${slot?.audio?.id || ''}:${slot?.video?.id || ''}:${slot?.screen?.id || ''}`)
})
return parts.join('|')
})
@@ -315,6 +375,7 @@ const tiles = computed(() => {
const selfTile = computed(() => tiles.value.find(t => t.isLocal) || null)
const remoteTile = computed(() => tiles.value.find(t => !t.isLocal && t.videoTrack) || tiles.value.find(t => !t.isLocal) || null)
const primaryTile = computed(() => {
if (screenTile.value) return screenTile.value
if (preferSelfMain.value && selfTile.value) return selfTile.value
return remoteTile.value || selfTile.value
})
@@ -650,6 +711,28 @@ const flipCamera = () => {
flipCameraByCommand()
}
const onScreenToggle = async () => {
if (screenLoading.value) return
if (screenDisabled.value && !screenSharingByMe.value) {
uni.showToast({ title: screenDisabledReason.value || '无法共享屏幕', icon: 'none' })
return
}
screenLoading.value = true
try {
if (screenSharingByMe.value) {
await meetingStore.stopScreenShare()
} else {
await meetingStore.startScreenShare()
}
} catch (err) {
if (err?.name !== 'NotAllowedError') {
uni.showToast({ title: err?.message || '屏幕共享失败', icon: 'none' })
}
} finally {
screenLoading.value = false
}
}
const executeCloudLawCommand = async (cmd = {}) => {
const command = String(cmd.command || cmd.type || '').toLowerCase()
const value = cmd.value
@@ -893,6 +976,13 @@ onLoad(query => {
cloudLawApiBase.value = query?.cloudLawApiBase || query?.cloud_law_api_base || ''
cloudLawToken.value = query?.cloudLawToken || query?.cloud_law_token || ''
cloudLawRole.value = query?.cloudLawRole || query?.cloud_law_role || ''
// #ifdef H5
if (String(cloudLawRole.value).toLowerCase() === 'law') {
try {
window.sessionStorage.setItem('echo_cloud_law_meeting_role', 'law')
} catch (e) {}
}
// #endif
const mode = String(query?.mode || query?.callType || query?.type || '').toLowerCase()
callMode.value = mode === 'voice' || mode === 'audio' ? 'voice' : 'video'
joinMeeting()
@@ -1233,6 +1323,10 @@ onUnload(() => {
.control-btn.disabled {
opacity: 0.94;
}
.control-btn.active {
background: linear-gradient(180deg, #4f8dff, #2563eb);
border-color: rgba(79, 141, 255, 0.55);
}
.hangup-btn {
width: 150rpx;
height: 150rpx;