列表骨架屏

This commit is contained in:
juguohong
2025-08-24 19:58:00 +08:00
parent cda1a4b7cc
commit 58bacb3a47
13 changed files with 532 additions and 249 deletions

View File

@@ -1,93 +1,85 @@
import { TennisMatch } from '../store/listStore'
import { TennisMatch } from "../store/listStore";
// 模拟网络延迟
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
// 模拟API响应格式
interface ApiResponse<T> {
code: number
message: string
data: T
timestamp: number
code: number;
message: string;
data: T;
timestamp: number;
}
// 模拟网球比赛数据
const mockTennisMatches: TennisMatch[] = [
{
id: '1',
title: '周一晚场浦东新区单打约球',
dateTime: '明天(周五)下午5点 2小时',
location: '仁恒河滨花园网球场・室外',
distance: '3.5km',
id: "1",
title: "周一晚场浦东新区单打约球",
dateTime: "明天(周五)下午5点 2小时",
location: "仁恒河滨花园网球场",
distance: "3.5km",
shinei: "室内",
registeredCount: 3,
maxCount: 4,
skillLevel: '2.0 至 2.5',
matchType: '双打',
skillLevel: "2.0 至 2.5",
matchType: "双打",
images: [
'https://images.unsplash.com/photo-1554068865-24cecd4e34b8?w=200&h=200&fit=crop&crop=center',
'https://images.unsplash.com/photo-1571019613454-1cb2f99b2d8b?w=200&h=200&fit=crop&crop=center',
'https://images.unsplash.com/photo-1551698618-1dfe5d97d256?w=200&h=200&fit=crop&crop=center'
]
"https://images.unsplash.com/photo-1554068865-24cecd4e34b8?w=200&h=200&fit=crop&crop=center",
"https://images.unsplash.com/photo-1571019613454-1cb2f99b2d8b?w=200&h=200&fit=crop&crop=center",
"https://images.unsplash.com/photo-1551698618-1dfe5d97d256?w=200&h=200&fit=crop&crop=center",
],
},
{
id: '2',
title: '浦东新区单打约球',
dateTime: '明天(周五)下午5点 2小时',
location: '仁恒河滨花园网球场・室外',
distance: '3.5km',
id: "2",
title: "浦东新区单打约球",
dateTime: "明天(周五)下午5点 2小时",
location: "仁恒河滨花园网球场",
distance: "3.5km",
shinei: "室外",
registeredCount: 2,
maxCount: 4,
skillLevel: '2.0 至 2.5',
matchType: '双打',
skillLevel: "2.0 至 2.5",
matchType: "双打",
images: [
'https://images.unsplash.com/photo-1571019613454-1cb2f99b2d8b?w=200&h=200&fit=crop&crop=center',
'https://images.unsplash.com/photo-1551698618-1dfe5d97d256?w=200&h=200&fit=crop&crop=center'
]
"https://images.unsplash.com/photo-1571019613454-1cb2f99b2d8b?w=200&h=200&fit=crop&crop=center",
"https://images.unsplash.com/photo-1551698618-1dfe5d97d256?w=200&h=200&fit=crop&crop=center",
],
},
{
id: '3',
title: '黄浦区双打约球',
dateTime: '7月20日(周日)下午6点 2小时',
location: '仁恒河滨花园网球场・室外',
distance: '3.5km',
id: "3",
title: "黄浦区双打约球",
dateTime: "7月20日(周日)下午6点 2小时",
location: "仁恒河滨花园网球场",
distance: "3.5km",
registeredCount: 3,
maxCount: 4,
skillLevel: '2.0 至 2.5',
matchType: '双打',
skillLevel: "2.0 至 2.5",
matchType: "双打",
images: [
'https://images.unsplash.com/photo-1554068865-24cecd4e34b8?w=200&h=200&fit=crop&crop=center'
]
}
]
"https://images.unsplash.com/photo-1554068865-24cecd4e34b8?w=200&h=200&fit=crop&crop=center",
],
},
];
// 模拟数据变化
const generateDynamicData = (): TennisMatch[] => {
return mockTennisMatches.map(match => ({
Promise.resolve((res) => {
setTimeout(res, 3000);
});
return mockTennisMatches.map((match) => ({
...match,
// 随机更新注册人数
registeredCount: Math.min(
match.maxCount,
match.maxCount,
Math.max(0, match.registeredCount + Math.floor(Math.random() * 3) - 1)
),
// 随机更新距离
distance: `${(Math.random() * 5 + 1).toFixed(1)}km`,
// 随机更新时间
dateTime: Math.random() > 0.5 ? match.dateTime : '今天下午3点 2小时'
}))
}
// 模拟网络错误
const simulateNetworkError = (): boolean => {
// 10% 概率模拟网络错误
return Math.random() < 0.1
}
// 模拟网络超时
const simulateTimeout = (): boolean => {
// 5% 概率模拟超时
return Math.random() < 0.05
}
dateTime: Math.random() > 0.5 ? match.dateTime : "今天下午3点 2小时",
}));
};
/**
* 获取网球比赛列表
@@ -95,59 +87,21 @@ const simulateTimeout = (): boolean => {
* @returns Promise<TennisMatch[]>
*/
export const getTennisMatches = async (params?: {
page?: number
pageSize?: number
location?: string
skillLevel?: string
page?: number;
pageSize?: number;
location?: string;
skillLevel?: string;
}): Promise<TennisMatch[]> => {
try {
console.log('API调用: getTennisMatches', params)
// 模拟网络延迟 (800-1500ms)
const delayTime = 800 + Math.random() * 700
await delay(delayTime)
// 模拟网络错误
if (simulateNetworkError()) {
throw new Error('网络连接失败,请检查网络设置')
}
// 模拟超时
if (simulateTimeout()) {
throw new Error('请求超时,请稍后重试')
}
// 生成动态数据
const matches = generateDynamicData()
// 模拟分页
if (params?.page && params?.pageSize) {
const start = (params.page - 1) * params.pageSize
const end = start + params.pageSize
return matches.slice(start, end)
}
// 模拟筛选
if (params?.location) {
return matches.filter(match =>
match.location.includes(params.location!)
)
}
if (params?.skillLevel) {
return matches.filter(match =>
match.skillLevel.includes(params.skillLevel!)
)
}
console.log('API响应成功:', matches.length, '条数据')
return matches
const matches = generateDynamicData();
return matches;
} catch (error) {
console.error('API调用失败:', error)
throw error
console.error("API调用失败:", error);
throw error;
}
}
};
/**
* 刷新网球比赛数据
@@ -155,60 +109,47 @@ export const getTennisMatches = async (params?: {
*/
export const refreshTennisMatches = async (): Promise<TennisMatch[]> => {
try {
console.log('API调用: refreshTennisMatches')
// 模拟刷新延迟 (500-1000ms)
const delayTime = 500 + Math.random() * 500
await delay(delayTime)
// 模拟网络错误
if (simulateNetworkError()) {
throw new Error('刷新失败,请稍后重试')
}
// 生成新的动态数据
const matches = generateDynamicData()
console.log('API刷新成功:', matches.length, '条数据')
return matches
const matches = generateDynamicData();
return matches;
} catch (error) {
console.error('API刷新失败:', error)
throw error
console.error("API刷新失败:", error);
throw error;
}
}
};
/**
* 获取比赛详情
* @param id 比赛ID
* @returns Promise<TennisMatch | null>
*/
export const getTennisMatchDetail = async (id: string): Promise<TennisMatch | null> => {
export const getTennisMatchDetail = async (
id: string
): Promise<TennisMatch | null> => {
try {
console.log('API调用: getTennisMatchDetail', id)
console.log("API调用: getTennisMatchDetail", id);
// 模拟网络延迟
await delay(600 + Math.random() * 400)
await delay(600 + Math.random() * 400);
// 模拟网络错误
if (simulateNetworkError()) {
throw new Error('获取详情失败,请稍后重试')
throw new Error("获取详情失败,请稍后重试");
}
const match = mockTennisMatches.find(m => m.id === id)
const match = mockTennisMatches.find((m) => m.id === id);
if (!match) {
throw new Error('比赛不存在')
throw new Error("比赛不存在");
}
console.log('API获取详情成功:', match.title)
return match
console.log("API获取详情成功:", match.title);
return match;
} catch (error) {
console.error('API获取详情失败:', error)
throw error
console.error("API获取详情失败:", error);
throw error;
}
}
};
/**
* 模拟API统计信息
@@ -218,6 +159,6 @@ export const getApiStats = () => {
totalCalls: 0,
successRate: 0.95,
averageResponseTime: 800,
lastCallTime: new Date().toISOString()
}
}
lastCallTime: new Date().toISOString(),
};
};