feat: 添加视频组件并在公告中集成视频播放功能
This commit is contained in:
120
src/views/home/components/video.vue
Normal file
120
src/views/home/components/video.vue
Normal file
@@ -0,0 +1,120 @@
|
||||
<script lang='ts' setup>
|
||||
import { modalController } from "@ionic/vue";
|
||||
import { closeOutline } from "ionicons/icons";
|
||||
|
||||
interface VideoConfigItem {
|
||||
title: string;
|
||||
link: string;
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
title?: string;
|
||||
config: VideoConfigItem[];
|
||||
}>();
|
||||
|
||||
const activeIndex = ref(0);
|
||||
const videoRef = ref<HTMLVideoElement | null>(null);
|
||||
|
||||
function handleClose() {
|
||||
modalController.dismiss();
|
||||
}
|
||||
|
||||
function handleVideoSelect(index: number) {
|
||||
activeIndex.value = index;
|
||||
// 切换视频时重新加载
|
||||
nextTick(() => {
|
||||
if (videoRef.value) {
|
||||
videoRef.value.load();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const currentVideo = computed(() => props.config[activeIndex.value]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ion-page>
|
||||
<ion-header class="ion-no-border">
|
||||
<ion-toolbar>
|
||||
<ion-title>{{ props.title || "视频播放" }}</ion-title>
|
||||
<ion-button slot="end" fill="clear" color="dark" @click="handleClose">
|
||||
<ion-icon :icon="closeOutline" />
|
||||
</ion-button>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content :fullscreen="true">
|
||||
<div class="p-4">
|
||||
<!-- 视频标题 -->
|
||||
<div class="mb-4">
|
||||
<h2 class="text-lg font-bold text-[#1a1a1a] mb-2">
|
||||
{{ currentVideo.title }}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<!-- 视频播放器 -->
|
||||
<div class="video-container rounded-2xl overflow-hidden bg-black shadow-lg mb-4">
|
||||
<video
|
||||
ref="videoRef"
|
||||
:src="currentVideo.link"
|
||||
controls
|
||||
playsinline
|
||||
class="w-full h-auto"
|
||||
controlslist="nodownload"
|
||||
>
|
||||
您的浏览器不支持视频播放
|
||||
</video>
|
||||
</div>
|
||||
|
||||
<!-- 多视频列表(如果有多个视频) -->
|
||||
<div v-if="config.length > 1" class="mt-6">
|
||||
<div class="text-sm font-semibold text-[#666] mb-3">
|
||||
直播列表 ({{ config.length }})
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div
|
||||
v-for="(item, index) in config"
|
||||
:key="index"
|
||||
class="p-3 rounded-xl cursor-pointer transition-all"
|
||||
:class="index === activeIndex
|
||||
? 'bg-(--ion-color-primary) text-white shadow-md'
|
||||
: 'bg-white text-[#333] active:bg-gray-50'"
|
||||
@click="handleVideoSelect(index)"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<div
|
||||
class="w-8 h-8 rounded-lg flex-center font-semibold text-sm shrink-0"
|
||||
:class="index === activeIndex
|
||||
? 'bg-white/20'
|
||||
: 'bg-(--ion-color-primary)/10 text-(--ion-color-primary)'"
|
||||
>
|
||||
{{ index + 1 }}
|
||||
</div>
|
||||
<div class="flex-1 text-sm line-clamp-2">
|
||||
{{ item.title }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ion-content>
|
||||
</ion-page>
|
||||
</template>
|
||||
|
||||
<style lang='css' scoped>
|
||||
.video-container {
|
||||
position: relative;
|
||||
aspect-ratio: 16 / 9;
|
||||
}
|
||||
|
||||
video {
|
||||
display: block;
|
||||
max-height: 60vh;
|
||||
}
|
||||
|
||||
/* iOS Safari 视频全屏优化 */
|
||||
video::-webkit-media-controls-panel {
|
||||
background-image: linear-gradient(transparent, rgba(0, 0, 0, 0.5));
|
||||
}
|
||||
</style>
|
||||
@@ -3,11 +3,13 @@ import type { Treaty } from "@elysiajs/eden";
|
||||
import type { InfiniteScrollCustomEvent } from "@ionic/vue";
|
||||
import type { Action } from "./";
|
||||
import type { TreatyQuery } from "@/api/types";
|
||||
import { modalController } from "@ionic/vue";
|
||||
import { chevronForwardOutline, eyeOutline, megaphoneOutline, timeOutline } from "ionicons/icons";
|
||||
import { client, safeClient } from "@/api";
|
||||
import banner2 from "@/assets/images/home-banner2.jpg?url";
|
||||
import banner1 from "@/assets/images/home-banner.jpg?url";
|
||||
import { actions } from "./";
|
||||
import Video from "./components/video.vue";
|
||||
|
||||
type NewsItem = Treaty.Data<typeof client.api.news.get>["data"][number];
|
||||
type NewsQuery = TreatyQuery<typeof client.api.news.get>;
|
||||
@@ -36,9 +38,32 @@ interface Announcement {
|
||||
const announcements = ref<Announcement[]>([
|
||||
{
|
||||
id: 1,
|
||||
title: "深化改革线上视频大会-18:30分",
|
||||
onClick: async () => {
|
||||
const modal = await modalController.create({
|
||||
component: Video,
|
||||
componentProps: {
|
||||
title: "视频大会",
|
||||
config: [
|
||||
{
|
||||
title: "深化改革线上视频大会18:30分",
|
||||
link: "https://www.w3schools.com/html/mov_bbb.mp4",
|
||||
},
|
||||
{
|
||||
title: "深化改革线上视频大会20:30分",
|
||||
link: "https://www.w3schools.com/html/mov_bbb.mp4",
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
await modal.present();
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "欢迎使用我们的服务平台,祝您投资顺利!",
|
||||
onClick: () => {
|
||||
console.log("点击了第一条公告");
|
||||
console.log("公告2点击");
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user