fix: purchase ui

This commit is contained in:
Rogee
2025-05-14 20:39:36 +08:00
parent 308da6113e
commit 6876d8bcd7
3 changed files with 89 additions and 19 deletions

View File

@@ -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)

View File

@@ -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