macos-web/src/apps/facetime/FaceTime.vue

92 lines
3.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="ft-body">
<div class="ft-stage">
<!-- 空闲联系人选择 -->
<template v-if="phase === 'idle'">
<div class="ft-title">选择联系人开始视频通话</div>
<div class="ft-grid">
<div v-for="c in contacts" :key="c.id" class="ft-cell">
<span class="contact-big-avatar">{{ c.name.slice(0, 1) }}</span>
<div>{{ c.name }}</div>
<button class="btn primary" @click="startCall(c)">📹 呼叫</button>
</div>
</div>
</template>
<!-- 通话中 -->
<template v-else-if="phase !== 'idle'">
<div class="ft-video" :class="{ live: phase === 'connected' }">
<span class="contact-big-avatar ft-avatar">{{ contact?.name?.slice(0, 1) }}</span>
</div>
<div class="ft-status">{{ statusText }}</div>
<div v-if="phase !== 'ended'" class="ft-self" :class="{ hidden: camOff }">
<span>🧑</span>
</div>
<div class="ft-controls">
<button class="ft-ctl" :class="{ off: micMuted }" title="静音" @click="micMuted = !micMuted">🎙</button>
<button class="ft-ctl" :class="{ off: camOff }" title="关闭视频" @click="camOff = !camOff">📷</button>
<button class="ft-ctl end" title="结束通话" @click="endCall">📞</button>
</div>
</template>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, onUnmounted, nextTick, computed } from 'vue'
import { store } from '../../composables/useStore'
const props = defineProps<{ win: any }>()
const phase = ref('idle') // idle | calling | connected | ended
const contact = ref<any>(null)
const micMuted = ref(false)
const camOff = ref(false)
const callSeconds = ref(0)
let callTimer: any = null
let connectTimer: any = null
const contacts = computed(() => store.get('contacts', []))
const statusText = computed(() => {
if (!contact.value) return ''
if (phase.value === 'calling') return `正在呼叫 ${contact.value.name}`
if (phase.value === 'connected') {
return `${contact.value.name} · ${String(Math.floor(callSeconds.value / 60)).padStart(2, '0')}:${String(callSeconds.value % 60).padStart(2, '0')}`
}
if (phase.value === 'ended') return '通话已结束'
return ''
})
function startCall(c: any) {
contact.value = c
phase.value = 'calling'
connectTimer = setTimeout(() => {
if (phase.value === 'calling') {
phase.value = 'connected'
callSeconds.value = 0
callTimer = setInterval(() => { callSeconds.value++ }, 1000)
}
}, 2500)
}
function endCall() {
clearInterval(callTimer)
clearTimeout(connectTimer)
phase.value = 'ended'
setTimeout(() => { phase.value = 'idle'; micMuted.value = false; camOff.value = false }, 1200)
}
props.win.appState = { startCall }
onMounted(() => {
const args = props.win.data
if (args?.call) startCall(args.call)
})
onUnmounted(() => {
clearInterval(callTimer)
clearTimeout(connectTimer)
})
</script>