feat(portal): implement creator content management list with filters and status tracking
This commit is contained in:
@@ -1,6 +1,161 @@
|
||||
<template>
|
||||
<div class="p-8">
|
||||
<h1 class="text-2xl font-bold mb-4">Creator Contents</h1>
|
||||
<p class="text-slate-400">(List of contents)</p>
|
||||
<div class="flex items-center justify-between mb-8">
|
||||
<h1 class="text-2xl font-bold text-slate-900">内容管理</h1>
|
||||
<router-link to="/creator/contents/new" class="px-6 py-2.5 bg-primary-600 text-white rounded-lg font-bold hover:bg-primary-700 transition-colors shadow-sm shadow-primary-200 cursor-pointer active:scale-95 flex items-center gap-2">
|
||||
<i class="pi pi-plus"></i> 发布新内容
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
<!-- Filters -->
|
||||
<div class="bg-white rounded-xl shadow-sm border border-slate-100 p-4 mb-6 flex flex-wrap gap-4 items-center">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm font-bold text-slate-500">状态:</span>
|
||||
<select v-model="filterStatus" class="h-9 px-3 rounded border border-slate-200 text-sm focus:border-primary-500 outline-none bg-white cursor-pointer">
|
||||
<option value="all">全部</option>
|
||||
<option value="published">已发布</option>
|
||||
<option value="audit">审核中</option>
|
||||
<option value="rejected">已驳回</option>
|
||||
<option value="draft">草稿箱</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm font-bold text-slate-500">曲种:</span>
|
||||
<select v-model="filterGenre" class="h-9 px-3 rounded border border-slate-200 text-sm focus:border-primary-500 outline-none bg-white cursor-pointer">
|
||||
<option value="all">全部</option>
|
||||
<option value="京剧">京剧</option>
|
||||
<option value="昆曲">昆曲</option>
|
||||
<option value="越剧">越剧</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="ml-auto 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-9 pl-9 pr-4 rounded border border-slate-200 text-sm focus:border-primary-500 outline-none w-48 transition-all focus:w-64">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Content List -->
|
||||
<div class="space-y-4">
|
||||
<div v-for="item in filteredList" :key="item.id" class="bg-white rounded-xl shadow-sm border border-slate-100 p-5 flex gap-6 hover:shadow-md transition-shadow group relative">
|
||||
|
||||
<!-- Cover -->
|
||||
<div class="w-40 h-[90px] bg-slate-100 rounded-lg flex-shrink-0 overflow-hidden relative">
|
||||
<img :src="item.cover" class="w-full h-full object-cover">
|
||||
<div class="absolute inset-0 bg-black/50 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<router-link :to="`/creator/contents/new`" class="text-white text-xs font-bold border border-white px-3 py-1 rounded hover:bg-white hover:text-black transition-colors">编辑</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Info -->
|
||||
<div class="flex-1 min-w-0 flex flex-col justify-between">
|
||||
<div>
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs px-1.5 py-0.5 border rounded text-slate-500">[{{ item.genre }}]</span>
|
||||
<h3 class="font-bold text-slate-900 text-lg truncate hover:text-primary-600 cursor-pointer transition-colors">{{ item.title }}</h3>
|
||||
</div>
|
||||
<!-- Status Badge -->
|
||||
<div class="flex items-center gap-2">
|
||||
<span v-if="item.status === 'rejected'" class="text-red-500 text-xs flex items-center gap-1 cursor-help" title="点击查看原因">
|
||||
<i class="pi pi-info-circle"></i> {{ item.rejectReason }}
|
||||
</span>
|
||||
<span class="px-2.5 py-1 rounded text-xs font-bold" :class="statusStyle(item.status).bg + ' ' + statusStyle(item.status).text">
|
||||
{{ statusStyle(item.status).label }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-6 text-sm text-slate-500">
|
||||
<span v-if="item.price > 0" class="text-red-600 font-bold">¥ {{ item.price }}</span>
|
||||
<span v-else class="text-green-600 font-bold">免费</span>
|
||||
<span><i class="pi pi-eye mr-1"></i> {{ item.views }}</span>
|
||||
<span><i class="pi pi-thumbs-up mr-1"></i> {{ item.likes }}</span>
|
||||
<span>{{ item.date }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="flex items-center gap-4 pt-3 border-t border-slate-50 mt-2">
|
||||
<button class="text-sm text-slate-500 hover:text-primary-600 font-medium cursor-pointer"><i class="pi pi-file-edit mr-1"></i> 编辑</button>
|
||||
<button v-if="item.status === 'published'" class="text-sm text-slate-500 hover:text-orange-600 font-medium cursor-pointer"><i class="pi pi-arrow-down mr-1"></i> 下架</button>
|
||||
<button v-if="item.status === 'offline'" class="text-sm text-slate-500 hover:text-green-600 font-medium cursor-pointer"><i class="pi pi-arrow-up mr-1"></i> 上架</button>
|
||||
<button class="text-sm text-slate-500 hover:text-red-600 font-medium ml-auto cursor-pointer"><i class="pi pi-trash mr-1"></i> 删除</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
|
||||
const filterStatus = ref('all');
|
||||
const filterGenre = ref('all');
|
||||
|
||||
const list = ref([
|
||||
{
|
||||
id: 1,
|
||||
title: '《锁麟囊》春秋亭 (程砚秋)',
|
||||
genre: '京剧',
|
||||
cover: 'https://images.unsplash.com/photo-1514306191717-452ec28c7f31?ixlib=rb-1.2.1&auto=format&fit=crop&w=300&q=60',
|
||||
status: 'published',
|
||||
price: 9.9,
|
||||
views: '12.5k',
|
||||
likes: 850,
|
||||
date: '2025-12-24'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '昆曲《牡丹亭》游园惊梦',
|
||||
genre: '昆曲',
|
||||
cover: 'https://images.unsplash.com/photo-1557683316-973673baf926?ixlib=rb-1.2.1&auto=format&fit=crop&w=300&q=60',
|
||||
status: 'audit',
|
||||
price: 0,
|
||||
views: '-',
|
||||
likes: '-',
|
||||
date: '2025-12-25'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '越剧《红楼梦》葬花',
|
||||
genre: '越剧',
|
||||
cover: 'https://images.unsplash.com/photo-1469571486292-0ba58a3f068b?ixlib=rb-1.2.1&auto=format&fit=crop&w=300&q=60',
|
||||
status: 'rejected',
|
||||
rejectReason: '封面图清晰度不足',
|
||||
price: 19.9,
|
||||
views: '-',
|
||||
likes: '-',
|
||||
date: '2025-12-23'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: '未命名的草稿',
|
||||
genre: '京剧',
|
||||
cover: '',
|
||||
status: 'draft',
|
||||
price: 0,
|
||||
views: '-',
|
||||
likes: '-',
|
||||
date: '2025-12-26'
|
||||
}
|
||||
]);
|
||||
|
||||
const filteredList = computed(() => {
|
||||
return list.value.filter(item => {
|
||||
const matchStatus = filterStatus.value === 'all' || item.status === filterStatus.value;
|
||||
const matchGenre = filterGenre.value === 'all' || item.genre === filterGenre.value;
|
||||
return matchStatus && matchGenre;
|
||||
});
|
||||
});
|
||||
|
||||
const statusStyle = (status) => {
|
||||
switch(status) {
|
||||
case 'published': return { bg: 'bg-green-50', text: 'text-green-600', label: '已发布' };
|
||||
case 'audit': return { bg: 'bg-orange-50', text: 'text-orange-600', label: '审核中' };
|
||||
case 'rejected': return { bg: 'bg-red-50', text: 'text-red-600', label: '已驳回' };
|
||||
case 'draft': return { bg: 'bg-slate-100', text: 'text-slate-500', label: '草稿' };
|
||||
default: return { bg: 'bg-slate-100', text: 'text-slate-500', label: '未知' };
|
||||
}
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user