添加Mock数据和API服务层

- 创建完整的Mock数据(非遗项目、传承人、资讯、活动等)
- 实现API服务函数(列表查询、详情获取、筛选排序等)
- 支持分页和多条件筛选功能
This commit is contained in:
Leo 2025-10-09 23:44:36 +08:00
parent cb195382eb
commit f7a1c8b580
2 changed files with 1942 additions and 0 deletions

348
src/services/api.ts Normal file
View File

@ -0,0 +1,348 @@
/**
* - API
* 使 Mock
*/
import type {
HeritageItem,
Inheritor,
NewsArticle,
Event,
Statistics,
Comment,
User,
PaginationParams,
PaginationResult,
FilterParams,
} from '@types/index'
import { mockData } from './mockData'
// 模拟网络延迟
const delay = (ms: number = 300) => new Promise((resolve) => setTimeout(resolve, ms))
// ===== 统计数据接口 =====
export const getStatistics = async (): Promise<Statistics> => {
await delay()
return mockData.statistics
}
// ===== 非遗项目接口 =====
export const getHeritageList = async (
params?: FilterParams & PaginationParams
): Promise<PaginationResult<HeritageItem>> => {
await delay()
let items = [...mockData.heritageItems]
// 应用筛选
if (params?.category) {
const categories = Array.isArray(params.category) ? params.category : [params.category]
items = items.filter((item) => categories.includes(item.category))
}
if (params?.level) {
const levels = Array.isArray(params.level) ? params.level : [params.level]
items = items.filter((item) => levels.includes(item.level))
}
if (params?.province) {
const provinces = Array.isArray(params.province) ? params.province : [params.province]
items = items.filter((item) => provinces.includes(item.province))
}
if (params?.search) {
const search = params.search.toLowerCase()
items = items.filter(
(item) =>
item.name.toLowerCase().includes(search) ||
item.description.toLowerCase().includes(search) ||
item.tags.some((tag) => tag.toLowerCase().includes(search))
)
}
// 应用排序
if (params?.sortBy) {
const order = params.sortOrder === 'desc' ? -1 : 1
items.sort((a, b) => {
const aVal = a[params.sortBy as keyof HeritageItem]
const bVal = b[params.sortBy as keyof HeritageItem]
if (typeof aVal === 'number' && typeof bVal === 'number') {
return (aVal - bVal) * order
}
return String(aVal).localeCompare(String(bVal)) * order
})
}
// 分页
const page = params?.page || 1
const pageSize = params?.pageSize || 12
const total = items.length
const totalPages = Math.ceil(total / pageSize)
const start = (page - 1) * pageSize
const end = start + pageSize
return {
data: items.slice(start, end),
total,
page,
pageSize,
totalPages,
}
}
export const getHeritageById = async (id: string): Promise<HeritageItem | null> => {
await delay()
return mockData.heritageItems.find((item) => item.id === id) || null
}
export const getFeaturedHeritage = async (limit: number = 6): Promise<HeritageItem[]> => {
await delay()
return mockData.heritageItems
.sort((a, b) => b.viewCount - a.viewCount)
.slice(0, limit)
}
// ===== 传承人接口 =====
export const getInheritorList = async (
params?: FilterParams & PaginationParams
): Promise<PaginationResult<Inheritor>> => {
await delay()
let items = [...mockData.inheritors]
// 应用筛选
if (params?.province) {
const provinces = Array.isArray(params.province) ? params.province : [params.province]
items = items.filter((item) => provinces.includes(item.province))
}
if (params?.search) {
const search = params.search.toLowerCase()
items = items.filter(
(item) =>
item.name.toLowerCase().includes(search) ||
item.bio.toLowerCase().includes(search) ||
item.title.toLowerCase().includes(search)
)
}
// 分页
const page = params?.page || 1
const pageSize = params?.pageSize || 12
const total = items.length
const totalPages = Math.ceil(total / pageSize)
const start = (page - 1) * pageSize
const end = start + pageSize
return {
data: items.slice(start, end),
total,
page,
pageSize,
totalPages,
}
}
export const getInheritorById = async (id: string): Promise<Inheritor | null> => {
await delay()
return mockData.inheritors.find((item) => item.id === id) || null
}
export const getFeaturedInheritors = async (limit: number = 4): Promise<Inheritor[]> => {
await delay()
return mockData.inheritors
.sort((a, b) => b.followers - a.followers)
.slice(0, limit)
}
// ===== 资讯接口 =====
export const getNewsList = async (
params?: FilterParams & PaginationParams
): Promise<PaginationResult<NewsArticle>> => {
await delay()
let items = [...mockData.news]
// 应用筛选
if (params?.category) {
const categories = Array.isArray(params.category) ? params.category : [params.category]
items = items.filter((item) => categories.includes(item.category))
}
if (params?.search) {
const search = params.search.toLowerCase()
items = items.filter(
(item) =>
item.title.toLowerCase().includes(search) ||
item.summary.toLowerCase().includes(search)
)
}
// 分页
const page = params?.page || 1
const pageSize = params?.pageSize || 10
const total = items.length
const totalPages = Math.ceil(total / pageSize)
const start = (page - 1) * pageSize
const end = start + pageSize
return {
data: items.slice(start, end),
total,
page,
pageSize,
totalPages,
}
}
export const getNewsById = async (id: string): Promise<NewsArticle | null> => {
await delay()
return mockData.news.find((item) => item.id === id) || null
}
export const getLatestNews = async (limit: number = 5): Promise<NewsArticle[]> => {
await delay()
return mockData.news
.sort((a, b) => new Date(b.publishDate).getTime() - new Date(a.publishDate).getTime())
.slice(0, limit)
}
// ===== 活动接口 =====
export const getEventList = async (
params?: FilterParams & PaginationParams
): Promise<PaginationResult<Event>> => {
await delay()
let items = [...mockData.events]
// 应用筛选
if (params?.type) {
const types = Array.isArray(params.type) ? params.type : [params.type]
items = items.filter((item) => types.includes(item.type))
}
if (params?.status) {
const statuses = Array.isArray(params.status) ? params.status : [params.status]
items = items.filter((item) => statuses.includes(item.status))
}
if (params?.search) {
const search = params.search.toLowerCase()
items = items.filter(
(item) =>
item.title.toLowerCase().includes(search) ||
item.description.toLowerCase().includes(search)
)
}
// 分页
const page = params?.page || 1
const pageSize = params?.pageSize || 10
const total = items.length
const totalPages = Math.ceil(total / pageSize)
const start = (page - 1) * pageSize
const end = start + pageSize
return {
data: items.slice(start, end),
total,
page,
pageSize,
totalPages,
}
}
export const getEventById = async (id: string): Promise<Event | null> => {
await delay()
return mockData.events.find((item) => item.id === id) || null
}
export const getUpcomingEvents = async (limit: number = 4): Promise<Event[]> => {
await delay()
return mockData.events
.filter((event) => event.status === 'upcoming')
.sort((a, b) => new Date(a.startDate).getTime() - new Date(b.startDate).getTime())
.slice(0, limit)
}
// ===== 评论接口 =====
export const getCommentsByTarget = async (
targetType: 'heritage' | 'inheritor' | 'news',
targetId: string
): Promise<Comment[]> => {
await delay()
return mockData.comments.filter(
(comment) => comment.targetType === targetType && comment.targetId === targetId
)
}
export const addComment = async (comment: Omit<Comment, 'id' | 'createdAt' | 'updatedAt'>): Promise<Comment> => {
await delay()
const newComment: Comment = {
...comment,
id: `cm${Date.now()}`,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
}
mockData.comments.push(newComment)
return newComment
}
// ===== 用户接口 =====
export const getUserById = async (id: string): Promise<User | null> => {
await delay()
return mockData.users.find((user) => user.id === id) || null
}
export const login = async (username: string, password: string): Promise<User | null> => {
await delay()
// Mock 登录逻辑
const user = mockData.users.find((u) => u.username === username)
return user || null
}
export const register = async (userData: Partial<User>): Promise<User> => {
await delay()
const newUser: User = {
id: `u${Date.now()}`,
username: userData.username || '',
nickname: userData.nickname || '',
avatar: userData.avatar || 'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=100',
email: userData.email || '',
favorites: [],
followedInheritors: [],
enrolledCourses: [],
registeredEvents: [],
points: 0,
level: 1,
createdAt: new Date().toISOString().split('T')[0],
}
mockData.users.push(newUser)
return newUser
}
// ===== 搜索接口 =====
export const searchAll = async (keyword: string): Promise<any> => {
await delay()
const heritages = mockData.heritageItems.filter((item) =>
item.name.toLowerCase().includes(keyword.toLowerCase()) ||
item.description.toLowerCase().includes(keyword.toLowerCase())
)
const inheritors = mockData.inheritors.filter((item) =>
item.name.toLowerCase().includes(keyword.toLowerCase()) ||
item.bio.toLowerCase().includes(keyword.toLowerCase())
)
const news = mockData.news.filter((item) =>
item.title.toLowerCase().includes(keyword.toLowerCase()) ||
item.summary.toLowerCase().includes(keyword.toLowerCase())
)
return {
heritages,
inheritors,
news,
}
}

1594
src/services/mockData.ts Normal file

File diff suppressed because it is too large Load Diff