feat: 优化图片加载和展示功能
- 新增 SmartImage 组件优化图片加载体验 - 新增 ImageGrid 组件支持多图布局展示 - 新增 imageHelper 工具函数 - 优化 PostCard 帖子卡片图片展示 - 优化消息页面 SegmentRenderer - 优化日程页面 ScheduleScreen - 优化上传服务 uploadService
This commit is contained in:
@@ -145,6 +145,8 @@ export const ScheduleScreen: React.FC = () => {
|
||||
const [startWeekInput, setStartWeekInput] = useState(String(currentWeek));
|
||||
const [endWeekInput, setEndWeekInput] = useState(String(TOTAL_WEEKS));
|
||||
const weekScrollRef = useRef<ScrollView | null>(null);
|
||||
// 组件卸载状态标记,用于防止组件卸载后仍调用 setState
|
||||
const isMountedRef = useRef(true);
|
||||
|
||||
// 设置弹窗状态
|
||||
const [isSettingsModalVisible, setIsSettingsModalVisible] = useState(false);
|
||||
@@ -153,6 +155,13 @@ export const ScheduleScreen: React.FC = () => {
|
||||
const [syncUsername, setSyncUsername] = useState('');
|
||||
const [syncPassword, setSyncPassword] = useState('');
|
||||
const [isSyncing, setIsSyncing] = useState(false);
|
||||
|
||||
// 组件卸载时设置标记
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
isMountedRef.current = false;
|
||||
};
|
||||
}, []);
|
||||
const todayColumnIndex = getTodayColumnIndex();
|
||||
// currentWeek === 1 对应今天所在的真实周(offset 0),其他周不高亮今日列
|
||||
const isViewingCurrentWeek = currentWeek === 1;
|
||||
@@ -463,14 +472,31 @@ export const ScheduleScreen: React.FC = () => {
|
||||
style: 'destructive' as const,
|
||||
onPress: async () => {
|
||||
try {
|
||||
// 删除所有相关课程
|
||||
for (const relatedCourse of relatedCourses) {
|
||||
await scheduleService.deleteCourse(relatedCourse.id);
|
||||
// 使用 Promise.allSettled 批量删除,即使部分失败也能继续
|
||||
const results = await Promise.allSettled(
|
||||
relatedCourses.map(course => scheduleService.deleteCourse(course.id))
|
||||
);
|
||||
|
||||
// 统计成功和失败的数量
|
||||
const fulfilledCount = results.filter(r => r.status === 'fulfilled').length;
|
||||
const rejectedCount = results.filter(r => r.status === 'rejected').length;
|
||||
|
||||
// 只移除成功删除的课程
|
||||
const successfullyDeletedIds = new Set(
|
||||
relatedCourses
|
||||
.filter((_, index) => results[index].status === 'fulfilled')
|
||||
.map(c => c.id)
|
||||
);
|
||||
setCourses(prev => prev.filter(c => !successfullyDeletedIds.has(c.id)));
|
||||
|
||||
if (rejectedCount > 0) {
|
||||
Alert.alert(
|
||||
'部分删除成功',
|
||||
`成功删除 ${fulfilledCount} 节课程,${rejectedCount} 节删除失败,请重试`
|
||||
);
|
||||
} else {
|
||||
Alert.alert('成功', `已删除 ${fulfilledCount} 节课程`);
|
||||
}
|
||||
// 从本地状态中移除
|
||||
const relatedIds = new Set(relatedCourses.map(c => c.id));
|
||||
setCourses(prev => prev.filter(c => !relatedIds.has(c.id)));
|
||||
Alert.alert('成功', `已删除 ${relatedCourses.length} 节课程`);
|
||||
} catch (error) {
|
||||
console.error('批量删除课程失败:', error);
|
||||
Alert.alert('删除失败', '请稍后重试');
|
||||
@@ -755,14 +781,17 @@ export const ScheduleScreen: React.FC = () => {
|
||||
]}
|
||||
onPress={async () => {
|
||||
if (!syncUsername.trim() || !syncPassword.trim()) return;
|
||||
|
||||
|
||||
setIsSyncing(true);
|
||||
try {
|
||||
const result = await scheduleService.syncSchedule({
|
||||
username: syncUsername.trim(),
|
||||
password: syncPassword.trim(),
|
||||
});
|
||||
|
||||
|
||||
// 检查组件是否已卸载
|
||||
if (!isMountedRef.current) return;
|
||||
|
||||
if (result.success) {
|
||||
Alert.alert(
|
||||
'同步成功',
|
||||
@@ -787,9 +816,15 @@ export const ScheduleScreen: React.FC = () => {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('同步课表失败:', error);
|
||||
Alert.alert('同步失败', '网络错误,请稍后重试');
|
||||
// 检查组件是否已卸载
|
||||
if (isMountedRef.current) {
|
||||
Alert.alert('同步失败', '网络错误,请稍后重试');
|
||||
}
|
||||
} finally {
|
||||
setIsSyncing(false);
|
||||
// 检查组件是否已卸载
|
||||
if (isMountedRef.current) {
|
||||
setIsSyncing(false);
|
||||
}
|
||||
}
|
||||
}}
|
||||
activeOpacity={0.8}
|
||||
|
||||
Reference in New Issue
Block a user