diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 5a98071..6028e76 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -125,12 +125,16 @@ function App() { } if (editingCategory) { await categoryApi.update(editingCategory.id, payload) + // 乐观更新:直接修改列表中的项 + setCategories(categories.map(c => c.id === editingCategory.id ? { ...c, ...payload } : c)) } else { - await categoryApi.create(payload) + const res = await categoryApi.create(payload) + // 乐观更新:添加到列表 + const newCat = res.data + setCategories([...categories, newCat]) } setCategoryForm({ name: '', icon: 'folder', color: '#667eea', sort_order: 0 }) setEditingCategory(null) - loadData() } catch (e) { console.error(e) } finally { setSaving(false) } @@ -138,11 +142,18 @@ function App() { const deleteCategory = async (id) => { if (!confirm('确定删除该分类?该分类下的网站将变为未分类状态。')) return + // 乐观删除:先从UI移除 + const catName = categories.find(c => c.id === id)?.name + setCategories(categories.filter(c => c.id !== id)) + // 网站也更新为未分类 + setWebsites(websites.map(s => s.category_id === id ? { ...s, category_id: null, category: null } : s)) + if (selectedCategory === id) setSelectedCategory(null) try { await categoryApi.delete(id) - if (selectedCategory === id) setSelectedCategory(null) + } catch (e) { + // 失败则恢复 loadData() - } catch (e) {} + } } // 保存网站 @@ -151,13 +162,17 @@ function App() { setSaving(true) try { const payload = { ...websiteForm, category_id: websiteForm.category_id || null } + const catName = categories.find(c => c.id === websiteForm.category_id)?.name if (modal.data) { await websiteApi.update(modal.data.id, payload) + // 乐观更新 + setWebsites(websites.map(s => s.id === modal.data.id ? { ...s, ...payload, category: catName ? { name: catName } : null } : s)) } else { - await websiteApi.create(payload) + const res = await websiteApi.create(payload) + const newSite = { ...res.data, category: catName ? { name: catName } : null } + setWebsites([...websites, newSite]) } closeModal() - loadData() } catch (e) {} finally { setSaving(false) } @@ -165,10 +180,13 @@ function App() { const handleDeleteWebsite = async (id) => { if (!confirm('确定删除?')) return + // 乐观删除 + setWebsites(websites.filter(s => s.id !== id)) try { await websiteApi.delete(id) + } catch (e) { loadData() - } catch (e) {} + } } const toggleFavorite = async (site) => {