Files
quyun-v2/frontend/portal/src/views/user/LibraryView.vue

110 lines
4.9 KiB
Vue

<script setup>
import { ref, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import { userApi } from '../../api/user';
import { tenantPath } from '../../utils/tenant';
const route = useRoute();
const tenantRoute = (path) => tenantPath(path, route);
const libraryItems = ref([]);
const loading = ref(true);
const fetchLibrary = async () => {
try {
const res = await userApi.getLibrary();
libraryItems.value = res || [];
} catch (e) {
console.error('Fetch library failed', e);
} finally {
loading.value = false;
}
};
onMounted(() => {
fetchLibrary();
});
const getTypeIcon = (type) => {
switch(type) {
case 'video': return 'pi-video';
case 'audio': return 'pi-volume-up';
default: return 'pi-file';
}
};
const getStatusLabel = (item) => {
// 根据后端返回的字段判断,假设后端有是否过期的逻辑或字段
if (item.status === 'unpublished') return '已下架';
if (item.expired) return '已过期';
return '永久有效';
};
</script>
<template>
<div class="bg-white rounded-xl shadow-sm border border-slate-100 min-h-[600px] p-8">
<div class="flex items-center justify-between mb-8">
<h1 class="text-2xl font-bold text-slate-900">已购内容</h1>
<div class="flex gap-4">
<div class="relative">
<i class="pi pi-search absolute left-3 top-1/2 -translate-y-1/2 text-slate-400"></i>
<input type="text" placeholder="搜索已购内容..." class="h-10 pl-9 pr-4 rounded-lg border border-slate-200 text-sm focus:border-primary-500 focus:outline-none w-48 transition-all focus:w-64">
</div>
</div>
</div>
<!-- Content List (Vertical Stack) -->
<div class="space-y-6">
<div
v-for="item in libraryItems"
:key="item.id"
@click="item.status === 'published' ? $router.push(tenantRoute(`/contents/${item.id}`)) : null"
class="group relative bg-white border border-slate-200 rounded-xl overflow-hidden hover:shadow-md transition-all hover:border-primary-200 flex flex-col sm:flex-row"
:class="item.status === 'published' ? 'cursor-pointer active:scale-[0.99]' : 'opacity-75 cursor-not-allowed'"
>
<!-- Cover -->
<div class="w-full sm:w-64 aspect-video bg-slate-100 relative overflow-hidden flex-shrink-0">
<img :src="item.cover" class="w-full h-full object-cover transition-transform duration-500 group-hover:scale-105" :class="{ 'grayscale opacity-70': item.status !== 'published' }">
<!-- Type Icon -->
<div class="absolute bottom-2 left-2 w-8 h-8 bg-black/60 rounded-full flex items-center justify-center text-white backdrop-blur-sm">
<i class="pi" :class="getTypeIcon(item.type)"></i>
</div>
</div>
<!-- Info -->
<div class="p-6 flex flex-col flex-1 min-w-0">
<div class="flex items-start justify-between gap-4 mb-2">
<h3 class="font-bold text-slate-900 text-lg sm:text-xl line-clamp-2 group-hover:text-primary-600 transition-colors">{{ item.title }}</h3>
<span class="flex-shrink-0 px-2 py-1 bg-green-100 text-green-700 text-xs font-bold rounded">{{ getStatusLabel(item) }}</span>
</div>
<div class="flex items-center gap-3 text-sm text-slate-500 mb-4">
<img :src="item.author_avatar || `https://api.dicebear.com/7.x/avataaars/svg?seed=${item.author_id}`" class="w-6 h-6 rounded-full">
<span class="font-medium text-slate-700">{{ item.author_name }}</span>
<span class="w-1 h-1 bg-slate-300 rounded-full"></span>
<span>{{ item.create_time }} 发布</span>
</div>
<!-- Action -->
<div class="mt-auto pt-4 border-t border-slate-50 flex items-center justify-end">
<button v-if="item.status === 'published'" class="px-6 py-2 bg-primary-600 text-white text-base font-bold rounded-lg hover:bg-primary-700 transition-colors shadow-sm shadow-primary-200">
立即阅读
</button>
<button v-else class="px-6 py-2 bg-slate-100 text-slate-400 text-base font-bold rounded-lg cursor-not-allowed">
暂不可看
</button>
</div>
</div>
</div>
<!-- Empty State -->
<div v-if="!loading && libraryItems.length === 0" class="flex flex-col items-center justify-center py-20">
<div class="w-20 h-20 bg-slate-50 rounded-full flex items-center justify-center mb-4"><i class="pi pi-book text-3xl text-slate-300"></i></div>
<p class="text-slate-500">暂无已购内容</p>
<router-link :to="tenantRoute('/')" class="mt-4 text-primary-600 font-medium hover:underline">去发现好内容</router-link>
</div>
</div>
</div>
</template>