|
|
@@ -34,7 +34,10 @@
|
|
|
v-for="sortOption in sortOptions"
|
|
|
:key="sortOption.value"
|
|
|
class="sort-chip"
|
|
|
- :class="{ 'sort-chip-active': selectedSort === sortOption.value }"
|
|
|
+ :class="{
|
|
|
+ 'sort-chip-active': selectedSort === sortOption.value,
|
|
|
+ 'sort-chip-free': sortOption.value === 'free',
|
|
|
+ }"
|
|
|
@click="selectSort(sortOption.value)"
|
|
|
>
|
|
|
{{ sortOption.label }}
|
|
|
@@ -57,6 +60,7 @@
|
|
|
cover-class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
|
|
|
/>
|
|
|
<div
|
|
|
+ v-if="selectedSort !== 'free'"
|
|
|
class="absolute bottom-2 right-2 bg-black/70 text-white text-xs px-2 py-1 rounded"
|
|
|
>
|
|
|
{{ formatDuration(video.duration) }}
|
|
|
@@ -68,7 +72,10 @@
|
|
|
<h3 class="text-sm font-medium text-white/90 line-clamp-2 mb-1">
|
|
|
{{ video.name }}
|
|
|
</h3>
|
|
|
- <p class="text-xs text-white/50 truncate">
|
|
|
+ <p
|
|
|
+ v-if="selectedSort !== 'free'"
|
|
|
+ class="text-xs text-white/50 truncate"
|
|
|
+ >
|
|
|
{{ formatNumber(video.view) }} 次观看 ·
|
|
|
{{ formatNumber(video.like) }} 点赞
|
|
|
</p>
|
|
|
@@ -107,7 +114,7 @@
|
|
|
</div>
|
|
|
|
|
|
<!-- 分页组件 -->
|
|
|
- <div v-if="totalPages > 1" class="py-6">
|
|
|
+ <div v-if="totalPages > 1 && selectedSort !== 'free'" class="py-6">
|
|
|
<!-- 桌面端:完整分页 -->
|
|
|
<div class="hidden sm:block">
|
|
|
<!-- 上一页、页码、下一页 -->
|
|
|
@@ -360,6 +367,9 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
+ <!-- 登录弹窗 -->
|
|
|
+ <LoginDialog v-model="showLoginDialog" @login-success="onLoginSuccess" />
|
|
|
</section>
|
|
|
</template>
|
|
|
|
|
|
@@ -368,7 +378,9 @@ import { ref, onMounted, onBeforeUnmount, watch, nextTick } from "vue";
|
|
|
import { useRouter, useRoute } from "vue-router";
|
|
|
import { searchVideoByTags, searchVideoByKeyword } from "@/services/api";
|
|
|
import { videoMenus as fixedVideoMenus } from "@/data/videoMenus";
|
|
|
+import { freeVideos } from "@/data/freeVideo";
|
|
|
import VideoJSPlayer from "@/components/VideoJSPlayer.vue";
|
|
|
+import LoginDialog from "@/components/LoginDialog.vue";
|
|
|
import { useUserStore } from "@/store/user";
|
|
|
import { VipLevel } from "@/types/vip";
|
|
|
|
|
|
@@ -415,6 +427,7 @@ const sortOptions = ref([
|
|
|
{ value: "time", label: "最新" },
|
|
|
{ value: "view", label: "热门" },
|
|
|
{ value: "like", label: "点赞" },
|
|
|
+ { value: "free", label: "试看" },
|
|
|
]);
|
|
|
const selectedSort = ref<string>("time");
|
|
|
|
|
|
@@ -425,6 +438,16 @@ const showAllTags = ref(false);
|
|
|
const isSearchMode = ref(false);
|
|
|
const currentSearchKeyword = ref("");
|
|
|
|
|
|
+// 登录弹窗
|
|
|
+const showLoginDialog = ref(false);
|
|
|
+
|
|
|
+// 处理登录成功
|
|
|
+const onLoginSuccess = async () => {
|
|
|
+ // 登录成功后刷新用户信息
|
|
|
+ await userStore.sync();
|
|
|
+ console.log("登录成功,用户信息已更新");
|
|
|
+};
|
|
|
+
|
|
|
// 格式化时长
|
|
|
const formatDuration = (duration: string | number): string => {
|
|
|
const seconds = parseInt(String(duration));
|
|
|
@@ -506,6 +529,13 @@ const selectMenu = async (hash: string) => {
|
|
|
// 选择排序方式
|
|
|
const selectSort = async (sort: string) => {
|
|
|
selectedSort.value = sort;
|
|
|
+
|
|
|
+ // 如果是免费视频,直接显示免费视频列表
|
|
|
+ if (sort === "free") {
|
|
|
+ showFreeVideos();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
// 重新查询当前显示的内容
|
|
|
if (isSearchMode.value) {
|
|
|
// 如果是搜索模式,重新执行搜索
|
|
|
@@ -524,6 +554,18 @@ const toggleTags = () => {
|
|
|
showAllTags.value = !showAllTags.value;
|
|
|
};
|
|
|
|
|
|
+// 显示免费视频
|
|
|
+const showFreeVideos = () => {
|
|
|
+ loading.value = false;
|
|
|
+ videoList.value = freeVideos;
|
|
|
+ totalPages.value = 1;
|
|
|
+ totalCount.value = freeVideos.length;
|
|
|
+ currentPage.value = 1;
|
|
|
+ // 清除搜索模式
|
|
|
+ isSearchMode.value = false;
|
|
|
+ currentSearchKeyword.value = "";
|
|
|
+};
|
|
|
+
|
|
|
// 搜索功能
|
|
|
const handleSearch = async (keyword: string, page = 1) => {
|
|
|
if (!keyword.trim()) {
|
|
|
@@ -578,7 +620,26 @@ const playVideo = (video: any) => {
|
|
|
|
|
|
const vipLevel = userStore.getVipLevel();
|
|
|
|
|
|
- if (vipLevel === VipLevel.GUEST || vipLevel === VipLevel.FREE) {
|
|
|
+ // 如果是试看视频,检查登录状态
|
|
|
+ if (selectedSort.value === "free" || video.id?.startsWith("free-")) {
|
|
|
+ // 检查用户是否已登录
|
|
|
+ if (!userStore.token) {
|
|
|
+ // 未登录,显示登录弹窗
|
|
|
+ showLoginDialog.value = true;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 已登录,跳转到试看视频播放页
|
|
|
+ router.push({
|
|
|
+ name: "VideoPlayer",
|
|
|
+ params: { id: video.id },
|
|
|
+ query: {
|
|
|
+ cover: video.cover,
|
|
|
+ m3u8: video.m3u8,
|
|
|
+ name: video.name,
|
|
|
+ isFree: "true",
|
|
|
+ },
|
|
|
+ });
|
|
|
+ } else if (vipLevel === VipLevel.GUEST || vipLevel === VipLevel.FREE) {
|
|
|
// guest和free用户通过URL参数传递cover和m3u8,同时包含视频ID
|
|
|
router.push({
|
|
|
name: "VideoPlayer",
|
|
|
@@ -760,4 +821,34 @@ onBeforeUnmount(() => {
|
|
|
.sort-chip-active {
|
|
|
@apply bg-emerald-500/20 text-emerald-400 border-emerald-400/30;
|
|
|
}
|
|
|
+
|
|
|
+.sort-chip-free {
|
|
|
+ @apply relative overflow-hidden;
|
|
|
+ box-shadow: 0 0 10px rgba(16, 185, 129, 0.3);
|
|
|
+}
|
|
|
+
|
|
|
+.sort-chip-free::before {
|
|
|
+ content: "";
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: -100%;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ background: linear-gradient(
|
|
|
+ 90deg,
|
|
|
+ transparent,
|
|
|
+ rgba(255, 255, 255, 0.4),
|
|
|
+ transparent
|
|
|
+ );
|
|
|
+ animation: sparkle 1.5s ease-in-out infinite;
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes sparkle {
|
|
|
+ 0% {
|
|
|
+ left: -100%;
|
|
|
+ }
|
|
|
+ 100% {
|
|
|
+ left: 100%;
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|