From 172380272264d906cddfd125c3a65e5a9e5caf58 Mon Sep 17 00:00:00 2001 From: Rogee Date: Tue, 6 Jan 2026 15:28:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E6=8E=92=E5=BA=8F=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=86=85=E5=AE=B9=E5=88=97=E8=A1=A8=E6=9F=A5=E8=AF=A2=E5=92=8C?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E7=8A=B6=E6=80=81=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/http/v1/creator.go | 3 +- backend/app/http/v1/dto/creator.go | 5 +- backend/app/services/creator.go | 37 +++++++- .../portal/src/views/creator/ContentsView.vue | 88 ++++++++++++++++++- 4 files changed, 122 insertions(+), 11 deletions(-) diff --git a/backend/app/http/v1/creator.go b/backend/app/http/v1/creator.go index 84e80d4..268fe38 100644 --- a/backend/app/http/v1/creator.go +++ b/backend/app/http/v1/creator.go @@ -2,6 +2,7 @@ package v1 import ( "quyun/v2/app/http/v1/dto" + "quyun/v2/app/requests" "quyun/v2/app/services" "quyun/v2/database/models" @@ -75,7 +76,7 @@ func (c *Creator) ListContents( ctx fiber.Ctx, user *models.User, filter *dto.CreatorContentListFilter, -) ([]dto.CreatorContentItem, error) { +) (*requests.Pager, error) { return services.Creator.ListContents(ctx, user.ID, filter) } diff --git a/backend/app/http/v1/dto/creator.go b/backend/app/http/v1/dto/creator.go index d53b9c1..c64c837 100644 --- a/backend/app/http/v1/dto/creator.go +++ b/backend/app/http/v1/dto/creator.go @@ -93,8 +93,9 @@ type CreatorContentListFilter struct { Status *string `query:"status"` Visibility *string `query:"visibility"` Genre *string `query:"genre"` - Key *string `query:"key"` - Keyword *string `query:"keyword"` + Key *string `query:"key"` + Keyword *string `query:"keyword"` + Sort *string `query:"sort"` } type CreatorOrderListFilter struct { diff --git a/backend/app/services/creator.go b/backend/app/services/creator.go index 7cd1719..87c4b31 100644 --- a/backend/app/services/creator.go +++ b/backend/app/services/creator.go @@ -8,6 +8,7 @@ import ( "quyun/v2/app/errorx" creator_dto "quyun/v2/app/http/v1/dto" + "quyun/v2/app/requests" "quyun/v2/database/fields" "quyun/v2/database/models" "quyun/v2/pkg/consts" @@ -109,7 +110,7 @@ func (s *creator) ListContents( ctx context.Context, userID int64, filter *creator_dto.CreatorContentListFilter, -) ([]creator_dto.CreatorContentItem, error) { +) (*requests.Pager, error) { tid, err := s.getTenantID(ctx, userID) if err != nil { return nil, err @@ -143,8 +144,32 @@ func (s *creator) ListContents( q = q.Where(tbl.Title.Like("%" + *filter.Keyword + "%")) } + // Pagination + filter.Pagination.Format() + total, err := q.Count() + if err != nil { + return nil, errorx.ErrDatabaseError.WithCause(err) + } + var list []*models.Content - err = q.Order(tbl.ID.Desc()). + + // Sorting + sort := "latest" + if filter.Sort != nil && *filter.Sort != "" { + sort = *filter.Sort + } + switch sort { + case "oldest": + q = q.Order(tbl.ID.Asc()) + case "views": + q = q.Order(tbl.Views.Desc()) + case "likes": + q = q.Order(tbl.Likes.Desc()) + default: + q = q.Order(tbl.ID.Desc()) + } + + err = q.Offset(int(filter.Pagination.Offset())).Limit(int(filter.Pagination.Limit)). UnderlyingDB(). Preload("ContentAssets"). Preload("ContentAssets.Asset"). @@ -220,9 +245,13 @@ func (s *creator) ListContents( IsPurchased: false, }) } - return data, nil -} + return &requests.Pager{ + Pagination: filter.Pagination, + Total: total, + Items: data, + }, nil +} func (s *creator) CreateContent(ctx context.Context, userID int64, form *creator_dto.ContentCreateForm) error { tid, err := s.getTenantID(ctx, userID) if err != nil { diff --git a/frontend/portal/src/views/creator/ContentsView.vue b/frontend/portal/src/views/creator/ContentsView.vue index e2e1318..e309818 100644 --- a/frontend/portal/src/views/creator/ContentsView.vue +++ b/frontend/portal/src/views/creator/ContentsView.vue @@ -10,6 +10,7 @@
+
状态:
+ +
+ 排序: + +
+ + +
+ +
+
+
+
+
+
+
+
+
+
+ + +
+
+ +
+

暂无内容

+

您还没有发布任何内容,快去创作吧!

+ + 立即发布 + +
+ -
+
+
@@ -176,6 +215,7 @@ import { useRouter } from 'vue-router'; import { useToast } from 'primevue/usetoast'; import { useConfirm } from 'primevue/useconfirm'; import ConfirmDialog from 'primevue/confirmdialog'; +import Paginator from 'primevue/paginator'; import { commonApi } from '../../api/common'; import { creatorApi } from '../../api/creator'; @@ -183,10 +223,12 @@ const router = useRouter(); const toast = useToast(); const confirm = useConfirm(); const contents = ref([]); +const loading = ref(false); const filterStatus = ref('all'); const filterVisibility = ref('all'); const filterGenre = ref('all'); const filterKey = ref('all'); +const filterSort = ref('latest'); const searchKeyword = ref(''); const statusOptions = ref([]); const visibilityOptions = [ @@ -194,7 +236,16 @@ const visibilityOptions = [ { key: 'tenant_only', value: '仅会员' }, { key: 'private', value: '私有' } ]; +const sortOptions = [ + { key: 'latest', value: '最新发布' }, + { key: 'oldest', value: '最早发布' }, + { key: 'views', value: '最多浏览' }, + { key: 'likes', value: '最多点赞' } +]; const genreOptions = ref([]); +const totalRecords = ref(0); +const rows = ref(10); +const first = ref(0); const keys = ['C大调', 'D大调', 'E大调', 'F大调', 'G大调', 'A大调', 'B大调', '降E大调']; const fetchOptions = async () => { @@ -210,30 +261,59 @@ const fetchOptions = async () => { }; const fetchContents = async () => { + loading.value = true; try { - const params = {}; + const params = { + page: (first.value / rows.value) + 1, + limit: rows.value + }; 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 (filterSort.value !== 'latest') params.sort = filterSort.value; if (searchKeyword.value) params.keyword = searchKeyword.value; const res = await creatorApi.listContents(params); - contents.value = res || []; + if (res && res.items) { + contents.value = res.items; + totalRecords.value = res.total; + } else { + contents.value = []; + totalRecords.value = 0; + } } catch (e) { console.error(e); + } finally { + loading.value = false; } }; +const onPage = (event) => { + first.value = event.first; + rows.value = event.rows; + fetchContents(); +}; + onMounted(() => { fetchOptions(); fetchContents(); }); -watch([filterStatus, filterVisibility, filterGenre, filterKey], () => { +watch([filterStatus, filterVisibility, filterGenre, filterKey, filterSort], () => { fetchContents(); }); +const handleResetFilters = () => { + filterStatus.value = 'all'; + filterVisibility.value = 'all'; + filterGenre.value = 'all'; + filterKey.value = 'all'; + filterSort.value = 'latest'; + searchKeyword.value = ''; + fetchContents(); +}; + const handleSearch = () => { fetchContents(); };