feat: 添加内容可见性字段和过滤选项,优化内容列表查询功能

This commit is contained in:
2026-01-06 10:04:50 +08:00
parent 1d53d9560e
commit 31d6192816
3 changed files with 39 additions and 3 deletions

View File

@@ -72,6 +72,7 @@ type CreatorContentItem struct {
VideoCount int `json:"video_count"`
AudioCount int `json:"audio_count"`
Status string `json:"status"`
Visibility string `json:"visibility"`
CreatedAt string `json:"created_at"`
IsPinned bool `json:"is_pinned"`
IsPurchased bool `json:"is_purchased"`
@@ -89,8 +90,9 @@ type AssetDTO struct {
type CreatorContentListFilter struct {
requests.Pagination
Status *string `query:"status"`
Genre *string `query:"genre"`
Status *string `query:"status"`
Visibility *string `query:"visibility"`
Genre *string `query:"genre"`
Key *string `query:"key"`
Keyword *string `query:"keyword"`
}

View File

@@ -121,6 +121,12 @@ func (s *creator) ListContents(
if filter.Status != nil && *filter.Status != "" {
q = q.Where(tbl.Status.Eq(consts.ContentStatus(*filter.Status)))
}
if filter.Visibility != nil && *filter.Visibility != "" {
q = q.Where(tbl.Visibility.Eq(consts.ContentVisibility(*filter.Visibility)))
}
if filter.Visibility != nil && *filter.Visibility != "" {
q = q.Where(tbl.Visibility.Eq(consts.ContentVisibility(*filter.Visibility)))
}
if filter.Genre != nil && *filter.Genre != "" {
val := *filter.Genre
if cn, ok := genreMap[val]; ok {
@@ -208,6 +214,7 @@ func (s *creator) ListContents(
VideoCount: videoCount,
AudioCount: audioCount,
Status: string(item.Status),
Visibility: string(item.Visibility),
CreatedAt: item.CreatedAt.Format("2006-01-02 15:04"),
IsPinned: item.IsPinned,
IsPurchased: false,

View File

@@ -18,6 +18,14 @@
<option v-for="opt in statusOptions" :key="opt.key" :value="opt.key">{{ opt.value }}</option>
</select>
</div>
<div class="flex items-center gap-2">
<span class="text-sm font-bold text-slate-500">可见性:</span>
<select v-model="filterVisibility"
class="h-9 px-3 rounded border border-slate-200 text-sm focus:border-primary-500 outline-none bg-white cursor-pointer min-w-[100px]">
<option value="all">全部</option>
<option v-for="opt in visibilityOptions" :key="opt.key" :value="opt.key">{{ opt.value }}</option>
</select>
</div>
<div class="flex items-center gap-2">
<span class="text-sm font-bold text-slate-500">曲种:</span>
<select v-model="filterGenre"
@@ -77,6 +85,9 @@
</div>
<!-- Status Badge -->
<div class="flex items-center gap-2 ml-4">
<span class="text-[10px] px-1.5 py-0.5 rounded border border-slate-200 text-slate-500 bg-slate-50" v-if="item.visibility">
{{ getVisibilityLabel(item.visibility) }}
</span>
<span v-if="item.status === 'blocked'" class="text-red-500 text-xs flex items-center gap-1 cursor-help"
title="已被封禁">
<i class="pi pi-info-circle"></i> 封禁
@@ -173,10 +184,16 @@ const toast = useToast();
const confirm = useConfirm();
const contents = ref([]);
const filterStatus = ref('all');
const filterVisibility = ref('all');
const filterGenre = ref('all');
const filterKey = ref('all');
const searchKeyword = ref('');
const statusOptions = ref([]);
const visibilityOptions = [
{ key: 'public', value: '公开' },
{ key: 'tenant_only', value: '仅会员' },
{ key: 'private', value: '私有' }
];
const genreOptions = ref([]);
const keys = ['C大调', 'D大调', 'E大调', 'F大调', 'G大调', 'A大调', 'B大调', '降E大调'];
@@ -196,6 +213,7 @@ const fetchContents = async () => {
try {
const params = {};
if (filterStatus.value !== 'all') params.status = filterStatus.value;
if (filterVisibility.value !== 'all') params.visibility = filterVisibility.value;
if (filterGenre.value !== 'all') params.genre = filterGenre.value;
if (filterKey.value !== 'all') params.key = filterKey.value;
if (searchKeyword.value) params.keyword = searchKeyword.value;
@@ -212,7 +230,7 @@ onMounted(() => {
fetchContents();
});
watch([filterStatus, filterGenre, filterKey], () => {
watch([filterStatus, filterVisibility, filterGenre, filterKey], () => {
fetchContents();
});
@@ -225,6 +243,15 @@ const getGenreLabel = (key) => {
return opt ? opt.value : key;
};
const getVisibilityLabel = (vis) => {
const map = {
'public': '公开',
'tenant_only': '仅会员',
'private': '私有'
};
return map[vis] || vis;
};
const statusStyle = (status) => {
// Map backend status to UI style. Labels should ideally come from backend option value/label map if needed,
// but for style/color mapping we can keep it here or use a helper.