feat: 添加内容可见性字段和过滤选项,优化内容列表查询功能
This commit is contained in:
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user