| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- <template>
- <div class="page-container">
- <div class="page-header">
- <el-button :icon="ArrowLeft" @click="goBack">返回</el-button>
- <span class="title">Cloudflare Stream 测试</span>
- </div>
- <!-- 配置区域 -->
- <div class="config-section">
- <el-form :model="config" label-width="auto" inline>
- <el-form-item label="播放器类型">
- <el-select v-model="config.playerType" style="width: 200px">
- <el-option label="Cloudflare iframe" value="cloudflare-iframe" />
- <el-option label="HLS.js" value="hls" />
- <el-option label="原生 Video" value="native" />
- </el-select>
- </el-form-item>
- <el-form-item label="Video ID">
- <el-input v-model="config.videoId" placeholder="Cloudflare Stream Video ID" style="width: 300px" />
- </el-form-item>
- <el-form-item label="自定义域名">
- <el-input
- v-model="config.customerDomain"
- placeholder="customer-xxx.cloudflarestream.com"
- style="width: 300px"
- />
- </el-form-item>
- <el-form-item>
- <el-button type="primary" @click="loadVideo">加载视频</el-button>
- </el-form-item>
- </el-form>
- <el-divider />
- <el-form label-width="auto" inline>
- <el-form-item label="或输入 HLS 地址">
- <el-input v-model="config.hlsUrl" placeholder="https://xxx/manifest/video.m3u8" style="width: 500px" />
- </el-form-item>
- <el-form-item>
- <el-button type="success" @click="loadHlsUrl">播放 HLS</el-button>
- </el-form-item>
- </el-form>
- </div>
- <!-- 播放器区域 -->
- <div class="player-section">
- <VideoPlayer
- ref="playerRef"
- :player-type="currentPlayerType"
- :video-id="currentVideoId"
- :customer-domain="config.customerDomain"
- :src="currentSrc"
- :use-iframe="config.playerType === 'cloudflare-iframe'"
- :autoplay="config.autoplay"
- :muted="config.muted"
- :controls="true"
- @play="onPlay"
- @pause="onPause"
- @error="onError"
- />
- </div>
- <!-- 控制按钮 -->
- <div class="control-section">
- <el-space wrap>
- <el-button type="primary" @click="handlePlay">播放</el-button>
- <el-button @click="handlePause">暂停</el-button>
- <el-button type="danger" @click="handleStop">停止</el-button>
- <el-button @click="handleScreenshot">截图</el-button>
- <el-button @click="handleFullscreen">全屏</el-button>
- <el-divider direction="vertical" />
- <el-switch v-model="config.muted" active-text="静音" inactive-text="有声" />
- <el-switch v-model="config.autoplay" active-text="自动播放" inactive-text="手动播放" />
- </el-space>
- </div>
- <!-- 使用说明 -->
- <div class="info-section">
- <el-alert title="Cloudflare Stream 接入说明" type="info" :closable="false">
- <template #default>
- <ol>
- <li>在 Cloudflare Dashboard 中上传视频或创建直播</li>
- <li>
- 获取 Video ID(格式如:
- <code>ea95132c15732412d22c1476fa83f27a</code>
- )
- </li>
- <li>
- 获取自定义域名(格式如:
- <code>customer-xxx.cloudflarestream.com</code>
- )
- </li>
- <li>填入上方表单并点击加载视频</li>
- </ol>
- <p style="margin-top: 10px">
- <strong>HLS 地址格式:</strong>
- <code>https://customer-xxx.cloudflarestream.com/{video_id}/manifest/video.m3u8</code>
- </p>
- <p>
- <strong>iframe 地址格式:</strong>
- <code>https://customer-xxx.cloudflarestream.com/{video_id}/iframe</code>
- </p>
- </template>
- </el-alert>
- </div>
- <!-- 日志区域 -->
- <div class="log-section">
- <h4>事件日志</h4>
- <div class="log-content">
- <div v-for="(log, index) in logs" :key="index" class="log-item" :class="log.type">
- <span class="time">{{ log.time }}</span>
- <span class="message">{{ log.message }}</span>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script setup lang="ts">
- import { ref, reactive, computed } from 'vue'
- import { useRouter } from 'vue-router'
- import { ArrowLeft } from '@element-plus/icons-vue'
- import VideoPlayer from '@/components/VideoPlayer.vue'
- const router = useRouter()
- const playerRef = ref<InstanceType<typeof VideoPlayer>>()
- const config = reactive({
- playerType: 'cloudflare-iframe' as 'cloudflare-iframe' | 'hls' | 'native',
- videoId: '',
- customerDomain: '',
- hlsUrl: '',
- autoplay: false,
- muted: true
- })
- const currentVideoId = ref('')
- const currentSrc = ref('')
- const currentPlayerType = computed(() => {
- if (config.playerType === 'cloudflare-iframe') return 'cloudflare'
- return config.playerType
- })
- interface LogItem {
- time: string
- type: 'info' | 'success' | 'error'
- message: string
- }
- const logs = ref<LogItem[]>([])
- function addLog(message: string, type: LogItem['type'] = 'info') {
- const time = new Date().toLocaleTimeString()
- logs.value.unshift({ time, type, message })
- if (logs.value.length > 50) {
- logs.value.pop()
- }
- }
- function loadVideo() {
- if (!config.videoId) {
- addLog('请输入 Video ID', 'error')
- return
- }
- currentVideoId.value = config.videoId
- if (config.playerType === 'hls') {
- const domain = config.customerDomain || 'customer-xxx.cloudflarestream.com'
- currentSrc.value = `https://${domain}/${config.videoId}/manifest/video.m3u8`
- } else {
- currentSrc.value = ''
- }
- addLog(`加载视频: ${config.videoId}`, 'success')
- }
- function loadHlsUrl() {
- if (!config.hlsUrl) {
- addLog('请输入 HLS 地址', 'error')
- return
- }
- config.playerType = 'hls'
- currentSrc.value = config.hlsUrl
- currentVideoId.value = ''
- addLog(`加载 HLS: ${config.hlsUrl}`, 'success')
- }
- function handlePlay() {
- playerRef.value?.play()
- addLog('播放', 'info')
- }
- function handlePause() {
- playerRef.value?.pause()
- addLog('暂停', 'info')
- }
- function handleStop() {
- playerRef.value?.stop()
- addLog('停止', 'info')
- }
- function handleScreenshot() {
- playerRef.value?.screenshot()
- addLog('截图', 'info')
- }
- function handleFullscreen() {
- playerRef.value?.fullscreen()
- addLog('全屏', 'info')
- }
- function onPlay() {
- addLog('视频开始播放', 'success')
- }
- function onPause() {
- addLog('视频已暂停', 'info')
- }
- function onError(error: any) {
- addLog(`播放错误: ${JSON.stringify(error)}`, 'error')
- }
- function goBack() {
- router.push('/camera')
- }
- </script>
- <style lang="scss" scoped>
- .page-container {
- padding: 20px;
- }
- .page-header {
- display: flex;
- align-items: center;
- background-color: #fff;
- border-radius: 4px;
- margin-bottom: 20px;
- .title {
- margin-left: 15px;
- font-size: 16px;
- font-weight: 600;
- }
- }
- .config-section {
- background-color: #fff;
- border-radius: 4px;
- }
- .player-section {
- height: 480px;
- margin-bottom: 20px;
- border-radius: 4px;
- overflow: hidden;
- }
- .control-section {
- background-color: #fff;
- border-radius: 4px;
- margin-bottom: 20px;
- }
- .info-section {
- margin-bottom: 20px;
- code {
- background-color: #f5f5f5;
- padding: 2px 6px;
- border-radius: 4px;
- font-size: 12px;
- }
- ol {
- padding-left: 20px;
- margin: 10px 0;
- }
- }
- .log-section {
- background-color: #fff;
- border-radius: 4px;
- h4 {
- margin-bottom: 10px;
- font-size: 14px;
- }
- .log-content {
- max-height: 200px;
- overflow-y: auto;
- background-color: #fafafa;
- border-radius: 4px;
- padding: 10px;
- }
- .log-item {
- font-size: 12px;
- padding: 4px 0;
- border-bottom: 1px solid #eee;
- &:last-child {
- border-bottom: none;
- }
- .time {
- color: #999;
- margin-right: 10px;
- }
- &.success .message {
- color: #67c23a;
- }
- &.error .message {
- color: #f56c6c;
- }
- }
- }
- </style>
|