Initial commit

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
谢宇宁
2026-10-26 17:51:31 +07:00
co-authored by Claude Opus 5.5
commit 61d0a11dfa
371 changed files with 35836 additions and 0 deletions
+104
View File
@@ -0,0 +1,104 @@
import { pickVideoCardTags } from "@/components/common/card-tags";
import { genres, regions, sorts, type Genre, type Region, type ShortDramaItem, type Sort } from "@/components/short-drama/data";
import { formatHeat } from "@/components/ranking/data";
import type { VideoCategoryListItem, VideoListItem, VideoListResp } from "@/lib/api/types";
export const VIDEO_PAGE_SIZE = 30;
export const videoSorts = sorts;
export type VideoSort = Sort;
export function videoSortType(sort: VideoSort): 1 | 2 {
return sort === "latest" ? 2 : 1;
}
export function mapVideoListItem(item: VideoListItem): ShortDramaItem | null {
if (item.type === 2) {
return {
kind: "ad",
id: `ad-${item.advertiseId || item.id || item.link || "unknown"}`,
title: (item.title || "").trim() || "广告",
subtitle: "",
cover: (item.coverImg || "").trim(),
href: (item.link || "").trim() || undefined,
};
}
if (!item.id) return null;
const slug = (item.slug || "").trim();
return {
kind: "drama",
id: String(item.id),
slug: slug || undefined,
title: (item.title || "").trim() || "未命名",
subtitle: "",
tags: pickVideoCardTags(item),
heat: formatHeat(item.watchNum),
episodes: "",
cover: (item.coverImg || "").trim(),
};
}
export type VideoListResult = {
items: ShortDramaItem[];
page: number;
pageSize: number;
totalCount: number;
totalPages: number;
sort: VideoSort;
categories: VideoCategoryListItem[];
categorySlug?: string;
};
export function buildVideoList(
data: VideoListResp | null | undefined,
sort: VideoSort,
fallbackPage = 1,
fallbackPageSize = VIDEO_PAGE_SIZE,
options?: { categories?: VideoCategoryListItem[]; categorySlug?: string },
): VideoListResult {
const page = data?.pageNum || fallbackPage;
const pageSize = data?.pageSize || fallbackPageSize;
const totalCount = data?.totalCount || 0;
const items = (data?.list ?? [])
.map(mapVideoListItem)
.filter((item): item is ShortDramaItem => Boolean(item));
return {
items,
page,
pageSize,
totalCount,
totalPages: Math.max(1, Math.ceil(totalCount / pageSize) || 1),
sort,
categories: options?.categories ?? [],
categorySlug: options?.categorySlug,
};
}
/** @deprecated 本地 mock,供「更多」等未接接口页面临时使用 */
const adSlots = new Set([5, 11, 17, 24, 25]);
export function getVideos(genre: Genre, sort: Sort, page: number, region: Region = "全部"): ShortDramaItem[] {
const seed = `${genres.indexOf(genre)}-${sorts.indexOf(sort)}-${regions.indexOf(region)}-${page}`;
return Array.from({ length: VIDEO_PAGE_SIZE }, (_, index): ShortDramaItem => {
const id = `video-${seed}-${index}`;
const cover = "";
if (adSlots.has(index)) {
return { kind: "ad", id, title: "广告文案", subtitle: "我是副标题", cover };
}
return {
kind: "drama",
id,
title: "有恩必报",
subtitle: "权谋交锋爱意藏在局中",
tags: [{ name: genre === "全部" ? "标签" : genre }],
heat: "25.8万 热度",
episodes: "30集",
badge: "original",
cover,
};
});
}