diff --git a/src/components/business/PostCard/components/PostImages.tsx b/src/components/business/PostCard/components/PostImages.tsx index c28dbeb..75e7161 100644 --- a/src/components/business/PostCard/components/PostImages.tsx +++ b/src/components/business/PostCard/components/PostImages.tsx @@ -16,7 +16,7 @@ const PostImages: React.FC = ({ images, displayMode, onImagePre if (!images || images.length === 0) return null; // 计算图片间距和圆角 - const imageGap = isDesktop ? 12 : 8; + const imageGap = isDesktop ? 4 : 2; const imageBorderRadius = isDesktop ? borderRadius.xl : borderRadius.md; return ( diff --git a/src/components/common/ImageGrid.tsx b/src/components/common/ImageGrid.tsx index f163e8b..bf5678b 100644 --- a/src/components/common/ImageGrid.tsx +++ b/src/components/common/ImageGrid.tsx @@ -132,10 +132,10 @@ function createImageGridStyles(colors: AppColors) { aspectRatio: 1, }, gridItem2: { - width: '48%', + width: '49%', }, gridItem3: { - width: '31%', + width: '32.5%', }, masonryContainer: { flexDirection: 'row', diff --git a/src/data/repositories/PostRepository.ts b/src/data/repositories/PostRepository.ts index 54fd3d1..ebc0caf 100644 --- a/src/data/repositories/PostRepository.ts +++ b/src/data/repositories/PostRepository.ts @@ -265,10 +265,13 @@ export class PostRepository implements IPostRepository { const posts = (response.list || []).map(p => this.mapToPost(p)); // 缓存帖子 - posts.forEach(post => { + for (const post of posts) { this.saveToMemoryCache(post); - this.saveToLocalCache(post); - }); + // 不等待本地缓存写入完成,避免阻塞 UI + this.saveToLocalCache(post).catch(err => { + console.warn('[PostRepository] 缓存帖子失败:', post.id, err); + }); + } // 计算 hasMore:优先使用 has_more,否则通过 page/total_pages 计算 let hasMore = response.has_more; @@ -338,10 +341,12 @@ export class PostRepository implements IPostRepository { const posts = (response.list || []).map(p => this.mapToPost(p)); // 缓存帖子 - posts.forEach(post => { + for (const post of posts) { this.saveToMemoryCache(post); - this.saveToLocalCache(post); - }); + this.saveToLocalCache(post).catch(err => { + console.warn('[PostRepository] 缓存帖子失败:', post.id, err); + }); + } return { posts, @@ -373,10 +378,12 @@ export class PostRepository implements IPostRepository { const posts = (response.list || []).map(p => this.mapToPost(p)); // 缓存帖子 - posts.forEach(post => { + for (const post of posts) { this.saveToMemoryCache(post); - this.saveToLocalCache(post); - }); + this.saveToLocalCache(post).catch(err => { + console.warn('[PostRepository] 缓存帖子失败:', post.id, err); + }); + } return { posts, diff --git a/src/screens/create/CreatePostScreen.tsx b/src/screens/create/CreatePostScreen.tsx index b8ae737..12dc697 100644 --- a/src/screens/create/CreatePostScreen.tsx +++ b/src/screens/create/CreatePostScreen.tsx @@ -128,11 +128,11 @@ export const CreatePostScreen: React.FC = (props) => { // 响应式图片网格配置 const imagesPerRow = useResponsiveValue({ xs: 3, sm: 3, md: 4, lg: 5, xl: 6 }); - const imageGap = 8; + const imageGap = 4; const availableWidth = isWideScreen ? Math.min(width, 800) - spacing.lg * 2 : width - spacing.lg * 2; - const imageSize = (availableWidth - imageGap * (imagesPerRow - 1)) / imagesPerRow; + const imageSize = Math.floor((availableWidth - imageGap * (imagesPerRow - 1)) / imagesPerRow); const contentInputMinHeight = Math.max( isWideScreen ? 460 : 320, Math.floor(windowHeight * (isWideScreen ? 0.56 : 0.5)) @@ -896,7 +896,7 @@ function createCreatePostStyles(colors: AppColors) { flexWrap: 'wrap', paddingHorizontal: 0, paddingTop: spacing.md, - gap: 8, + gap: 4, }, imageGridItem: { borderRadius: borderRadius.md, diff --git a/src/services/database.ts b/src/services/database.ts index 276c7ff..da6116b 100644 --- a/src/services/database.ts +++ b/src/services/database.ts @@ -991,3 +991,53 @@ export const updateConversationCacheUnreadCount = async ( } }); }; + +/** + * 批量保存会话列表及其相关数据(用户、群组) + * 在单个队列操作中完成,避免多次并发数据库操作导致的 statement 生命周期问题 + */ +export const saveConversationsWithRelatedCache = async ( + conversations: ConversationResponse[], + users?: UserDTO[], + groups?: GroupResponse[] +): Promise => { + if (!conversations || conversations.length === 0) return; + + const now = new Date().toISOString(); + + await enqueueWrite(async () => { + const database = await getDb(); + + // 1. 保存会话列表 + for (const conversation of conversations) { + await database.runAsync( + `INSERT OR REPLACE INTO conversation_list_cache (id, data, updatedAt) VALUES (?, ?, ?)`, + [ + String(conversation.id), + JSON.stringify(conversation), + conversation.updated_at || now, + ] + ); + } + + // 2. 保存用户 + if (users && users.length > 0) { + for (const user of users) { + await database.runAsync( + `INSERT OR REPLACE INTO users (id, data, updatedAt) VALUES (?, ?, ?)`, + [String(user.id), JSON.stringify(user), now] + ); + } + } + + // 3. 保存群组 + if (groups && groups.length > 0) { + for (const group of groups) { + await database.runAsync( + `INSERT OR REPLACE INTO groups (id, data, updatedAt) VALUES (?, ?, ?)`, + [String(group.id), JSON.stringify(group), now] + ); + } + } + }); +}; diff --git a/src/services/messageService.ts b/src/services/messageService.ts index 4589887..1d1d485 100644 --- a/src/services/messageService.ts +++ b/src/services/messageService.ts @@ -25,9 +25,7 @@ import { getConversationCache, getConversationListCache, saveConversationCache, - saveConversationsCache, - saveGroupsCache, - saveUsersCache, + saveConversationsWithRelatedCache, updateConversationCacheUnreadCount, } from './database'; @@ -48,18 +46,14 @@ class MessageService { list: ConversationResponse[] ): Promise { if (!list.length) return; - await saveConversationsCache(list); - await saveUsersCache( - list.flatMap(conv => [ - ...(conv.participants || []), - ...(conv.last_message?.sender ? [conv.last_message.sender] : []), - ]) - ); - await saveGroupsCache( - list - .map(conv => conv.group) - .filter((group): group is NonNullable => Boolean(group)) - ); + const users = list.flatMap(conv => [ + ...(conv.participants || []), + ...(conv.last_message?.sender ? [conv.last_message.sender] : []), + ]); + const groups = list + .map(conv => conv.group) + .filter((group): group is NonNullable => Boolean(group)); + await saveConversationsWithRelatedCache(list, users, groups); } /** offset 会话列表单页:请求 + 落库 */ diff --git a/src/stores/messageManager.ts b/src/stores/messageManager.ts index 6e7cbac..5aae26e 100644 --- a/src/stores/messageManager.ts +++ b/src/stores/messageManager.ts @@ -43,9 +43,7 @@ import { saveUserCache, updateMessageStatus, deleteConversation as deleteConversationFromDb, - saveConversationsCache, - saveUsersCache, - saveGroupsCache, + saveConversationsWithRelatedCache, } from '../services/database'; import { api } from '../services/api'; import { vibrateOnMessage } from '../services/messageVibrationService'; @@ -396,24 +394,17 @@ class MessageManager { /** 与会话列表同步写入本地缓存(参与者 / 群 / 列表) */ private persistConversationListCache(): void { const list = Array.from(this.state.conversations.values()); - saveConversationsCache(list).catch(error => { + const users = list.flatMap(conv => [ + ...(conv.participants || []), + ...(conv.last_message?.sender ? [conv.last_message.sender] : []), + ]); + const groups = list + .map(conv => conv.group) + .filter((group): group is NonNullable => Boolean(group)); + + saveConversationsWithRelatedCache(list, users, groups).catch(error => { console.error('[MessageManager] 持久化会话列表失败:', error); }); - saveUsersCache( - list.flatMap(conv => [ - ...(conv.participants || []), - ...(conv.last_message?.sender ? [conv.last_message.sender] : []), - ]) - ).catch(error => { - console.error('[MessageManager] 持久化会话相关用户失败:', error); - }); - saveGroupsCache( - list - .map(conv => conv.group) - .filter((group): group is NonNullable => Boolean(group)) - ).catch(error => { - console.error('[MessageManager] 持久化会话相关群组失败:', error); - }); } private recomputeConversationTotalUnread(): void {