diff --git a/pages/tv/index.vue b/pages/tv/index.vue index a60bdc4..cccdc3e 100644 --- a/pages/tv/index.vue +++ b/pages/tv/index.vue @@ -26,6 +26,7 @@ import "video.js/dist/video-js.css"; import bgImage from '~/assets/tv-bg-1.jpg'; import { sourcesAipan } from "~/assets/vod/tv"; import { useTvStore } from "~/stores/tv"; +import { ElMessage } from 'element-plus'; definePageMeta({ layout: 'custom', }); @@ -37,8 +38,9 @@ const videoSrc = ref(''); const modalShow = ref(false); const videoPlayStatus = ref(false); const videoLoading = ref(false); +const isChannelSwitching = ref(false); const videoMuted = ref(false); - +const isPlaying = ref(false); // 视频播放/暂停状态 let player = null; let hls = null; // 缓存 HLS 实例 let currentEffectIndex = 0; @@ -110,7 +112,10 @@ const loadHLS = (url) => { }); player.on("waiting", showLoadingSpinner); - player.on("playing", hideLoadingSpinner); + player.on("playing", () => { + hideLoadingSpinner(); + isPlaying.value = true; + }); player.on("error", hideLoadingSpinner); } @@ -139,26 +144,51 @@ const loadHLS = (url) => { player.on("loadedmetadata", hideLoadingSpinner); }; -const handleSwithcSource = async (url) => { +const handleSwitchSource = async (url) => { if (channelCategory.value === 3) { modalShow.value = true } else { + isChannelSwitching.value = true; videoLoading.value = true; videoSrc.value = url; loadHLS(url); videoPlayStatus.value = true; + isPlaying.value = true; } }; // 视频播放和暂停 const handleSwitchVideoStatus = () => { - if (player) { + if (player && videoPlayStatus.value) { // 只在TV开启时可用 if (videoPlayer.value.paused) { videoPlayer.value.play(); - videoPlayStatus.value = true; + isPlaying.value = true; } else { videoPlayer.value.pause(); - videoPlayStatus.value = false; + isPlaying.value = false; + } + } +}; + +// 处理TV开关机 +const handlePowerSwitch = () => { + if (!videoPlayStatus.value) { + // 开机:加载视频并播放 + videoPlayStatus.value = true; + if (videoSrc.value) { + loadHLS(videoSrc.value); + isPlaying.value = true; + } + } else { + // 关机:停止播放,清除视频源 + videoPlayStatus.value = false; + isPlaying.value = false; + if (player) { + player.pause(); + if (hls) { + hls.destroy(); + hls = null; + } } } }; @@ -200,11 +230,15 @@ const handleFullscreen = () => { // 处理视频加载和播放状态 const handleWaiting = () => { + if (!isChannelSwitching.value) { + return; + } videoLoading.value = true; }; const handlePlaying = () => { videoLoading.value = false; + isChannelSwitching.value = false; }; const handleMute = () => { if (player) { @@ -248,48 +282,68 @@ const handleSwithcChannelCategory = (id) => { } } const getFsList = async (params) => { - if (!alistUrl.value) return - let res = await $fetch(`${alistUrl.value}/api/fs/list`, { - method: 'POST', - body: params - }) - // console.log(res) - if (res.code === 200) { - alistData.value = res.data - tvStore.setAlistData(res.data) - } else { - alistData.value.pop() - tvStore.setAlistData(alistData.value) + if (!alistUrl.value) { + ElMessage.warning('请先选择 Alist 服务器') + return + } + try { + let res = await $fetch(`${alistUrl.value}/api/fs/list`, { + method: 'POST', + body: params + }) + if (res.code === 200) { + alistData.value = res.data + tvStore.setAlistData(res.data) + } else { + ElMessage.error(res.message || '获取文件列表失败') + if (alistData.value && alistData.value.length > 0) { + alistData.value.pop() + tvStore.setAlistData(alistData.value) + } + } + } catch (error) { + console.error('getFsList error:', error) + ElMessage.error('网络请求失败,请检查网络连接') } } const getFsGet = async (params) => { - if (!alistUrl.value) return - let res = await $fetch(`${alistUrl.value}/api/fs/get`, { - method: 'POST', - body: params - }) - - if (res.code === 200) { - let sign = res.data.sign; - let alistPathTemp = [] - - alistPath.value.forEach((item, index) => { - alistPathTemp[index] = encodeURIComponent(item) + if (!alistUrl.value) { + ElMessage.warning('请先选择 Alist 服务器') + return + } + try { + let res = await $fetch(`${alistUrl.value}/api/fs/get`, { + method: 'POST', + body: params }) - let temp_url = alistPathTemp.join('/') + '?sign=' + sign - videoSrc.value = `${alistUrl.value}/d${temp_url}` - loadHLS(`${alistUrl.value}/d${temp_url}`); - } else { - alistData.value.pop() - tvStore.setAlistData(alistData.value) + + if (res.code === 200) { + let sign = res.data.sign; + let alistPathTemp = [] + + alistPath.value.forEach((item, index) => { + alistPathTemp[index] = encodeURIComponent(item) + }) + let temp_url = alistPathTemp.join('/') + '?sign=' + sign + videoSrc.value = `${alistUrl.value}/d${temp_url}` + loadHLS(`${alistUrl.value}/d${temp_url}`); + } else { + ElMessage.error(res.message || '获取文件信息失败') + if (alistData.value && alistData.value.length > 0) { + alistData.value.pop() + tvStore.setAlistData(alistData.value) + } + } + } catch (error) { + console.error('getFsGet error:', error) + ElMessage.error('网络请求失败,请检查网络连接') } } const handleClickAlist = (item, index) => { - if (item.is_dir) { - console.log('this is is dir') - // 如果是文件夹 + // 进入文件夹时重置播放状态 + videoPlayStatus.value = false if (currentIsDir.value) { alistPath.value.push(item.name) } else { @@ -297,8 +351,7 @@ const handleClickAlist = (item, index) => { alistPath.value.push(item.name) } currentIsDir.value = true - // 在这里进行深拷贝 - const currentPath = [...alistPath.value]; // 或使用 JSON.parse(JSON.stringify(alistPath.value)) 进行深拷贝 + const currentPath = [...alistPath.value] tvStore.setAlistPath(currentPath) tvStore.setAlistCurrentPlayIndex(0) getFsList({ @@ -325,20 +378,25 @@ const handleClickAlist = (item, index) => { }) } } -const handleBackAlist = () => { +const handleBackAlist = async () => { + if (alistPath.value.length <= 1 && alistPath.value[0] === '') { + return + } alistPath.value.pop() currentIsDir.value = true - // console.log(alistPath.value) - // tvStore.setAlistPath(alistPath.value) - getFsList({ + // 同步更新 store 中的路径 + tvStore.setAlistPath([...alistPath.value]) + // 重置播放状态 + videoPlayStatus.value = false + // 获取上级目录数据 + await getFsList({ page: 1, password: "", - path: alistPath.value.join('/'), + path: alistPath.value.join('/') || '/', per_page: 0, refresh: false }) } - const getAlists = async () => { try { let res = await $fetch("/api/alist/get", { @@ -361,6 +419,33 @@ const handleClickAlistUrl = (item) => { tvStore.setAlistUrl(item.link) } +const handleHomeAlist = () => { + if (!alistUrl.value) { + ElMessage.warning('请先选择 Alist 服务器') + return + } + if (channelCategory.value !== 3) { + channelCategory.value = 3 + } + // 关闭设置面板 + alistSettingShow.value = false + tvStore.setAlistSettingShow(false) + // 重置路径和数据 + alistPath.value = [''] + currentIsDir.value = true + alistData.value = [] + tvStore.setAlistPath(['']) + tvStore.setAlistData([]) + // 获取根目录数据 + getFsList({ + page: 1, + password: "", + path: '/', + per_page: 0, + refresh: false + }) +} + // 页面挂载和销毁 onMounted(() => { // 获取视频源 @@ -414,244 +499,980 @@ onBeforeUnmount(() => { \ No newline at end of file diff --git a/stores/tv.ts b/stores/tv.ts index cdad37d..554ceeb 100644 --- a/stores/tv.ts +++ b/stores/tv.ts @@ -35,6 +35,7 @@ export const useTvStore = defineStore('tv', { } }, persist: { - storage: persistedState.localStorage + storage: persistedState.localStorage, + paths: ['tvCategory', 'alistUrl', 'alistPath', 'alistCurrentPlayIndex', 'alistData'] }, }) \ No newline at end of file