fix feed empty list rendering

This commit is contained in:
leonincs
2026-04-23 19:00:02 +08:00
parent 89c281c8f0
commit d7a0e2a6b7
10 changed files with 112 additions and 16 deletions

View File

@@ -37,6 +37,7 @@ func (f *FeedHandler) ListLatest(c *gin.Context) {
c.JSON(500, gin.H{"error": err.Error()})
return
}
feedItems.VideoList = nonNilFeedVideoItems(feedItems.VideoList)
c.JSON(200, feedItems)
}
@@ -85,6 +86,7 @@ func (f *FeedHandler) ListLikesCount(c *gin.Context) {
c.JSON(500, gin.H{"error": err.Error()})
return
}
feedItems.VideoList = nonNilFeedVideoItems(feedItems.VideoList)
c.JSON(200, feedItems)
}
@@ -110,6 +112,7 @@ func (f *FeedHandler) ListByFollowing(c *gin.Context) {
c.JSON(500, gin.H{"error": err.Error()})
return
}
feedItems.VideoList = nonNilFeedVideoItems(feedItems.VideoList)
c.JSON(200, feedItems)
}
@@ -160,5 +163,13 @@ func (f *FeedHandler) ListByPopularity(c *gin.Context) {
c.JSON(500, gin.H{"error": err.Error()})
return
}
resp.VideoList = nonNilFeedVideoItems(resp.VideoList)
c.JSON(200, resp)
}
func nonNilFeedVideoItems(items []FeedVideoItem) []FeedVideoItem {
if items == nil {
return []FeedVideoItem{}
}
return items
}

View File

@@ -1,6 +1,7 @@
package social
import (
"feedsystem_video_go/internal/account"
"feedsystem_video_go/internal/middleware/jwt"
"net/http"
@@ -89,6 +90,9 @@ func (h *SocialHandler) GetAllFollowers(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
if followers == nil {
followers = []*account.Account{}
}
c.JSON(http.StatusOK, GetAllFollowersResponse{Followers: followers})
}
@@ -114,5 +118,8 @@ func (h *SocialHandler) GetAllVloggers(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
if vloggers == nil {
vloggers = []*account.Account{}
}
c.JSON(http.StatusOK, GetAllVloggersResponse{Vloggers: vloggers})
}

View File

@@ -90,5 +90,8 @@ func (h *CommentHandler) GetAllComments(c *gin.Context) {
c.JSON(400, gin.H{"error": err.Error()})
return
}
if comments == nil {
comments = []Comment{}
}
c.JSON(200, comments)
}

View File

@@ -106,5 +106,8 @@ func (lh *LikeHandler) ListMyLikedVideos(c *gin.Context) {
c.JSON(500, gin.H{"error": err.Error()})
return
}
if videos == nil {
videos = []Video{}
}
c.JSON(200, videos)
}

View File

@@ -207,6 +207,9 @@ func (vh *VideoHandler) ListByAuthorID(c *gin.Context) {
c.JSON(400, gin.H{"error": err.Error()})
return
}
if videos == nil {
videos = []Video{}
}
c.JSON(200, videos)
}

View File

@@ -1,8 +1,10 @@
import { postJson } from './client'
import { normalizeCommentList } from './normalize'
import type { Comment, MessageResponse } from './types'
export function listAll(videoId: number) {
return postJson<Comment[]>('/comment/listAll', { video_id: videoId })
export async function listAll(videoId: number) {
const comments = await postJson<Comment[] | null>('/comment/listAll', { video_id: videoId })
return normalizeCommentList(comments)
}
export function publish(videoId: number, content: string) {

View File

@@ -1,23 +1,28 @@
import { postJson } from './client'
import { normalizeFeedVideoList } from './normalize'
import type { ListByFollowingResponse, ListByPopularityResponse, ListLatestResponse, ListLikesCountResponse } from './types'
export function listLatest(input: { limit: number; latest_time: number }) {
return postJson<ListLatestResponse>('/feed/listLatest', input)
export async function listLatest(input: { limit: number; latest_time: number }) {
const res = await postJson<ListLatestResponse>('/feed/listLatest', input)
return { ...res, video_list: normalizeFeedVideoList(res.video_list) }
}
export function listLikesCount(input: { limit: number; likes_count_before?: number; id_before?: number }) {
export async function listLikesCount(input: { limit: number; likes_count_before?: number; id_before?: number }) {
const body: Record<string, unknown> = { limit: input.limit }
if (typeof input.likes_count_before === 'number' || typeof input.id_before === 'number') {
body.likes_count_before = input.likes_count_before ?? 0
body.id_before = input.id_before ?? 0
}
return postJson<ListLikesCountResponse>('/feed/listLikesCount', body)
const res = await postJson<ListLikesCountResponse>('/feed/listLikesCount', body)
return { ...res, video_list: normalizeFeedVideoList(res.video_list) }
}
export function listByPopularity(input: { limit: number; as_of: number; offset: number }) {
return postJson<ListByPopularityResponse>('/feed/listByPopularity', input)
export async function listByPopularity(input: { limit: number; as_of: number; offset: number }) {
const res = await postJson<ListByPopularityResponse>('/feed/listByPopularity', input)
return { ...res, video_list: normalizeFeedVideoList(res.video_list) }
}
export function listByFollowing(input: { limit: number; latest_time: number }) {
return postJson<ListByFollowingResponse>('/feed/listByFollowing', input, { authRequired: true })
export async function listByFollowing(input: { limit: number; latest_time: number }) {
const res = await postJson<ListByFollowingResponse>('/feed/listByFollowing', input, { authRequired: true })
return { ...res, video_list: normalizeFeedVideoList(res.video_list) }
}

View File

@@ -0,0 +1,57 @@
import type { Account, Comment, FeedAuthor, FeedVideoItem, Video } from './types'
export function listOrEmpty<T>(value: T[] | null | undefined): T[] {
return Array.isArray(value) ? value : []
}
export function normalizeAccount(value: Account | null | undefined): Account {
return {
id: Number(value?.id ?? 0),
username: value?.username || '匿名用户',
}
}
function normalizeAuthor(value: FeedAuthor | null | undefined): FeedAuthor {
return {
id: Number(value?.id ?? 0),
username: value?.username || '匿名用户',
}
}
export function normalizeFeedVideoItem(value: FeedVideoItem): FeedVideoItem {
return {
...value,
author: normalizeAuthor(value.author),
title: value.title || '未命名视频',
description: value.description || '',
play_url: value.play_url || '',
cover_url: value.cover_url || '',
create_time: Number(value.create_time ?? 0),
likes_count: Number(value.likes_count ?? 0),
is_liked: Boolean(value.is_liked),
}
}
export function normalizeFeedVideoList(value: FeedVideoItem[] | null | undefined): FeedVideoItem[] {
return listOrEmpty(value).map(normalizeFeedVideoItem)
}
export function normalizeVideoList(value: Video[] | null | undefined): Video[] {
return listOrEmpty(value).map((video) => ({
...video,
username: video.username || '匿名用户',
title: video.title || '未命名视频',
description: video.description || '',
play_url: video.play_url || '',
cover_url: video.cover_url || '',
likes_count: Number(video.likes_count ?? 0),
}))
}
export function normalizeCommentList(value: Comment[] | null | undefined): Comment[] {
return listOrEmpty(value).map((comment) => ({
...comment,
username: comment.username || '匿名用户',
content: comment.content || '',
}))
}

View File

@@ -1,4 +1,5 @@
import { postJson } from './client'
import { listOrEmpty, normalizeAccount } from './normalize'
import type { GetAllFollowersResponse, GetAllVloggersResponse, MessageResponse } from './types'
export function follow(vloggerId: number) {
@@ -9,18 +10,20 @@ export function unfollow(vloggerId: number) {
return postJson<MessageResponse>('/social/unfollow', { vlogger_id: vloggerId }, { authRequired: true })
}
export function getAllFollowers(vloggerId?: number) {
return postJson<GetAllFollowersResponse>(
export async function getAllFollowers(vloggerId?: number) {
const res = await postJson<GetAllFollowersResponse>(
'/social/getAllFollowers',
vloggerId ? { vlogger_id: vloggerId } : {},
{ authRequired: true },
)
return { ...res, followers: listOrEmpty(res.followers).map(normalizeAccount) }
}
export function getAllVloggers(followerId?: number) {
return postJson<GetAllVloggersResponse>(
export async function getAllVloggers(followerId?: number) {
const res = await postJson<GetAllVloggersResponse>(
'/social/getAllVloggers',
followerId ? { follower_id: followerId } : {},
{ authRequired: true },
)
return { ...res, vloggers: listOrEmpty(res.vloggers).map(normalizeAccount) }
}

View File

@@ -1,4 +1,5 @@
import { postForm, postJson } from './client'
import { normalizeVideoList } from './normalize'
import type { Video } from './types'
export function publishVideo(input: { title: string; description: string; play_url: string; cover_url: string }) {
@@ -19,8 +20,9 @@ export function uploadCover(file: File) {
return postForm<UploadResponse>('/video/uploadCover', fd, { authRequired: true })
}
export function listByAuthorId(authorId: number) {
return postJson<Video[]>('/video/listByAuthorID', { author_id: authorId })
export async function listByAuthorId(authorId: number) {
const videos = await postJson<Video[] | null>('/video/listByAuthorID', { author_id: authorId })
return normalizeVideoList(videos)
}
export function getDetail(id: number) {