]> acesimba.cloud Git - words.git/commitdiff
fix: 支持进度撤销-服务端删除已确认进度回写本地; 删除G54复习1
authorroot <root@localhost.localdomain>
Tue, 18 Aug 2026 13:21:42 +0000 (21:21 +0800)
committerroot <root@localhost.localdomain>
Tue, 18 Aug 2026 13:21:42 +0000 (21:21 +0800)
- 新增 deleteProgress(); sync pull 在拉取成功后, 对本地非 dirty 且服务端已不存在的进度执行本地删除
  仅当 serverEvents 非空时执行, 防止服务端异常空响应误删; 绝不删 dirty(未推送)记录
- 删除 study_logs 中 G54 review1(id 401), 该进度记为未执行; 下次同步自动从本地移除

backend/db/bcd.db
frontend/src/db.js
frontend/src/sync.js

index da4027c10f43ed2e3d215d7291dfb237cddc3485..0c595cd6882368c0d7f236c6154a5a38efc36cbd 100644 (file)
Binary files a/backend/db/bcd.db and b/backend/db/bcd.db differ
index 9eccef7176f5e9cb94116c531830f3384f8cb896..325fcbbeb667ed714d7eb91ff39363827ccc3a15 100644 (file)
@@ -112,6 +112,12 @@ export async function clearDirty(group_id, op_type) {
     });
 }
 
+// 删除某条进度(用于服务端已删除记录回写本地, 实现撤销/未执行)
+export async function deleteProgress(group_id, op_type) {
+    const key = `${group_id}:${op_type}`;
+    return singleReq('progress', 'readwrite', s => s.delete(key));
+}
+
 // ---------- meta store ----------
 
 export async function getMeta(key) {
index a7c30ca49d43dbb346ff193243ea9c9b038e3787..d349a2e10e7c563ed3e4b7ab9bdc8eb522d2403b 100644 (file)
@@ -1,12 +1,12 @@
 // 离线优先 + 自动同步 统一入口
-// æ\95°æ\8d®è§\84å\88\99 (å¸\83å°\94å¹¶é\9b\86): (group,op) ä»»ä¸\80æ\96¹å®\8cæ\88\90å\8d³å®\8cæ\88\90; ä¸\8då\88 æ\9c¬å\9c°ã\80\81ä¸\8dæ¯\94æ\97¶é\97´
+// æ\95°æ\8d®è§\84å\88\99 (å¸\83å°\94å¹¶é\9b\86): (group,op) ä»»ä¸\80æ\96¹å®\8cæ\88\90å\8d³å®\8cæ\88\90; äº\91端å\88 é\99¤å·²ç¡®è®¤è¿\9b度ä¼\9aå\9b\9eå\86\99æ\9c¬å\9c°(æ\92¤é\94\80)
 // dirty = "这条本地完成记录尚未确认上传到云端"
 // syncNow: 上传本地 dirty → 拉云端并集合并 → 更新 lastSyncAt → 重算 learnable
 // triggerAutoSync: 幂等并发锁, 供首页/联网恢复/完成学习 调用, 失败时置 failed
 
 import { api } from './api';
 import {
-    getDirtyProgress, clearDirty, getAllProgress, putProgress,
+    getDirtyProgress, clearDirty, getAllProgress, putProgress, deleteProgress,
     putWords, setMeta, getMeta, setLearnableGroups, getAllWordsFromIDB, getWordsCount,
 } from './db';
 
@@ -78,6 +78,18 @@ export async function syncNow() {
         }
     }
 
+    // 阶段2b: 服务端已删除(且本地已确认/非 dirty)的进度, 本地同步删除。
+    // 仅在成功拉取到非空集合时才执行, 避免服务端异常返回空时误删本地进度;
+    // 仅删非 dirty 记录(本地未推送完成的进度绝不删, 保护离线工作)。
+    if (serverEvents.length > 0) {
+        const serverKeys = new Set(serverEvents.map(e => `${e.group_id}:${e.op_type}`));
+        for (const p of localAll) {
+            if (!p.dirty && !serverKeys.has(p.key)) {
+                await deleteProgress(p.group_id, p.op_type);
+            }
+        }
+    }
+
     // 阶段3: 首次 warmup 词库 (仅 IDB 空时, 避免每次重拉 1852 词)
     if ((await getWordsCount()) === 0) {
         const allWords = await api.getAllWords();