fix: purchase ui
This commit is contained in:
@@ -173,6 +173,12 @@ func (ctl *posts) Play(ctx fiber.Ctx, id int64, user *model.Users) (*PlayUrl, er
|
||||
// Url: "https://github.com/mediaelement/mediaelement-files/raw/refs/heads/master/big_buck_bunny.mp4",
|
||||
// }, nil
|
||||
|
||||
preview := false
|
||||
bought, err := models.Users.HasBought(ctx.Context(), user.ID, id)
|
||||
if !bought || err != nil {
|
||||
preview = true
|
||||
}
|
||||
|
||||
log.Infof("Fetching play URL for post ID: %d", id)
|
||||
post, err := models.Posts.GetByID(ctx.Context(), id)
|
||||
if err != nil {
|
||||
@@ -181,12 +187,6 @@ func (ctl *posts) Play(ctx fiber.Ctx, id int64, user *model.Users) (*PlayUrl, er
|
||||
}
|
||||
go models.Posts.IncrViewCount(ctx.Context(), post.ID)
|
||||
|
||||
preview := false
|
||||
bought, err := models.Users.HasBought(ctx.Context(), user.ID, post.ID)
|
||||
if !bought || err != nil {
|
||||
preview = true
|
||||
}
|
||||
|
||||
for _, asset := range post.Assets.Data {
|
||||
if asset.Type == "video/mp4" && asset.Metas != nil && asset.Metas.Short == preview {
|
||||
media, err := models.Medias.GetByID(ctx.Context(), asset.Media)
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
<script setup>
|
||||
import { postApi } from '@/api/postApi'
|
||||
import ArticleListItem from '@/components/ArticleListItem.vue'
|
||||
import { useIntersectionObserver } from '@vueuse/core'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { onMounted, onUnmounted, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import Player, { Events, I18N } from 'xgplayer'
|
||||
import 'xgplayer/dist/index.min.css'
|
||||
import ZH from 'xgplayer/es/lang/zh-cn'
|
||||
import MobilePreset from 'xgplayer/es/presets/mobile'
|
||||
|
||||
// 启用中文
|
||||
I18N.use(ZH)
|
||||
|
||||
const router = useRouter()
|
||||
const purchasedArticles = ref([])
|
||||
@@ -11,6 +17,8 @@ const loadingTrigger = ref(null)
|
||||
const loading = ref(false)
|
||||
const hasMore = ref(true)
|
||||
const currentPage = ref(1)
|
||||
const activeArticle = ref(null)
|
||||
const player = ref(null)
|
||||
const limit = 10
|
||||
|
||||
const fetchArticles = async () => {
|
||||
@@ -34,6 +42,56 @@ const fetchArticles = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const initializePlayer = async (source) => {
|
||||
try {
|
||||
player.value = new Player({
|
||||
id: 'player',
|
||||
url: source,
|
||||
autoplay: true,
|
||||
// poster: article.head_images[0],
|
||||
marginControls: true,
|
||||
width: '100%',
|
||||
fitVideoSize: 'fixWidth',
|
||||
videoFillMode: 'fill',
|
||||
fluid: true,
|
||||
presets: [MobilePreset],
|
||||
playsinline: true,
|
||||
playbackRate: [0.5, 0.75, 1],
|
||||
})
|
||||
|
||||
player.value.on(Events.ERROR, (error) => {
|
||||
alert(`视频播放失败: ${error.errorCode} ${error.message}`)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error("Failed to load video:", error)
|
||||
alert("视频加载失败")
|
||||
}
|
||||
}
|
||||
|
||||
const playArticle = async (article) => {
|
||||
try {
|
||||
if (activeArticle.value && activeArticle.value.id === article.id) {
|
||||
return
|
||||
}
|
||||
|
||||
const { data } = await postApi.play(article.id)
|
||||
if (!data.url) {
|
||||
alert("视频地址不存在")
|
||||
return
|
||||
}
|
||||
activeArticle.value = article
|
||||
|
||||
if (!player.value) {
|
||||
await initializePlayer(data.url)
|
||||
} else {
|
||||
await player.value.playNext({ url: data.url })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to load video:", error)
|
||||
alert("视频加载失败")
|
||||
}
|
||||
}
|
||||
|
||||
useIntersectionObserver(
|
||||
loadingTrigger,
|
||||
([{ isIntersecting }]) => {
|
||||
@@ -47,27 +105,39 @@ useIntersectionObserver(
|
||||
}
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
fetchArticles()
|
||||
onMounted(async () => {
|
||||
await fetchArticles()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (player.value) {
|
||||
player.value.destroy()
|
||||
player.value = null
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-full flex flex-col">
|
||||
<div class="flex-none bg-white border-b border-gray-200 z-50 shadow">
|
||||
<div class="p-4">
|
||||
<h2 class="text-lg font-medium text-gray-800">已购买</h2>
|
||||
</div>
|
||||
<div class="h-full flex flex-col bg-gray-100">
|
||||
<!-- 固定的播放器区域 -->
|
||||
<div class="flex-none">
|
||||
<div id="player"></div>
|
||||
</div>
|
||||
|
||||
<!-- 可滚动的列表区域 -->
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<div class="p-4">
|
||||
<div class="p-2">
|
||||
<div v-if="purchasedArticles.length === 0 && !loading" class="text-center text-gray-500 py-8">
|
||||
暂无已购买
|
||||
</div>
|
||||
|
||||
<div v-for="article in purchasedArticles" :key="article.id" class="mb-4">
|
||||
<ArticleListItem :article="{ ...article, bought: true }" />
|
||||
<div v-for="article in purchasedArticles" :key="article.id" @click="playArticle(article)" :class="['flex items-center shadow p-4 bg-white rounded mb-2 cursor-pointer hover:bg-gray-50',
|
||||
{ 'border-2 border-orange-500': activeArticle?.id === article.id }]">
|
||||
<span class="p-1 bg-sky-500 rounded-full"></span>
|
||||
|
||||
<div class="ml-3 flex-1 min-w-0">
|
||||
<h3 class="font-medium text-gray-800 line-clamp-2">{{ article.title }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ref="loadingTrigger" class="py-4 text-center" v-show="hasMore || loading">
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user