106 lines
3.2 KiB
Vue
106 lines
3.2 KiB
Vue
<template>
|
|
<view class="page call">
|
|
<view class="stage">
|
|
<web-view v-if="roomSrc" :src="roomSrc" class="wv" />
|
|
<view v-else class="wait">
|
|
<view class="av">{{ initial }}</view>
|
|
<text class="name">{{ peerName }}</text>
|
|
<text class="st">{{ statusText }}</text>
|
|
</view>
|
|
</view>
|
|
<view class="acts">
|
|
<view v-if="ringing" class="btn ok" @click="accept">接听</view>
|
|
<view class="btn no" @click="hang">挂断</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import { store } from '../../utils/store.js'
|
|
|
|
export default {
|
|
data() {
|
|
return { off: null, tick: 0 }
|
|
},
|
|
computed: {
|
|
call() {
|
|
this.tick
|
|
return store.call
|
|
},
|
|
ringing() {
|
|
return this.call && this.call.status === 'ringing'
|
|
},
|
|
peerName() {
|
|
const c = this.call
|
|
if (!c) return '通话'
|
|
const p = store.person(c.peerId)
|
|
return (p && p.name) || '同事'
|
|
},
|
|
initial() {
|
|
return this.peerName.slice(0, 1)
|
|
},
|
|
statusText() {
|
|
const s = this.call && this.call.status
|
|
if (s === 'calling') return '正在呼叫…'
|
|
if (s === 'ringing') return '邀请你通话'
|
|
if (s === 'active') return '通话中'
|
|
return '连接中'
|
|
},
|
|
roomSrc() {
|
|
const c = this.call
|
|
if (!c || !c.token || !c.url) return ''
|
|
if (c.status !== 'active' && c.direction !== 'out') return ''
|
|
return 'https://meet.livekit.io/custom/?liveKitUrl=' + encodeURIComponent(c.url) + '&token=' + encodeURIComponent(c.token)
|
|
}
|
|
},
|
|
onShow() {
|
|
if (this.off) this.off()
|
|
this.off = store.on(() => {
|
|
this.tick += 1
|
|
if (!store.call) {
|
|
const pages = getCurrentPages()
|
|
if (pages.length > 1) uni.navigateBack()
|
|
}
|
|
})
|
|
if (!store.call) uni.navigateBack()
|
|
},
|
|
onHide() {
|
|
if (this.off) this.off()
|
|
this.off = null
|
|
},
|
|
onUnload() {
|
|
if (this.off) this.off()
|
|
if (store.call) store.endCall(true)
|
|
},
|
|
methods: {
|
|
async accept() {
|
|
try {
|
|
uni.showLoading({ title: '接通中…', mask: true })
|
|
await store.acceptCall()
|
|
} catch (e) {
|
|
uni.showToast({ title: (e && e.message) || '接听失败', icon: 'none' })
|
|
}
|
|
try { uni.hideLoading() } catch (_) {}
|
|
},
|
|
hang() {
|
|
store.endCall(true)
|
|
uni.navigateBack()
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.call { height: 100vh; background: #0f172a; color: #fff; display: flex; flex-direction: column; }
|
|
.stage { flex: 1; position: relative; }
|
|
.wv { position: absolute; inset: 0; }
|
|
.wait { height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; }
|
|
.av { width: 160rpx; height: 160rpx; border-radius: 50%; background: #2563eb; display: flex; align-items: center; justify-content: center; font-size: 64rpx; font-weight: 700; }
|
|
.name { margin-top: 24rpx; font-size: 36rpx; font-weight: 700; }
|
|
.st { margin-top: 8rpx; color: rgba(255,255,255,0.65); }
|
|
.acts { display: flex; justify-content: center; gap: 32rpx; padding: 32rpx 24rpx calc(32rpx + env(safe-area-inset-bottom)); }
|
|
.btn { min-width: 200rpx; height: 80rpx; border-radius: 999rpx; display: flex; align-items: center; justify-content: center; font-size: 28rpx; font-weight: 600; }
|
|
.ok { background: #006c49; }
|
|
.no { background: #ba1a1a; }
|
|
</style>
|