删除 CalDAV 账号时一并清除其系统日历镜像本
问题:在 App 里删除一个 CalDAV 账号后,之前镜像进系统日历的日历本 (synccalendar.mirror.<accId>-<hash> 账户) 仍留在系统日历里,形成幽灵账户。 真机实测确认:账号 1789564608312 已删,其名下 13 个镜像账户仍在(KEEP)。 根因: - AccountsPage.confirmDeleteAccount 只清账号配置+本地库+设置,完全不碰系统日历; - 自动兜底也失效:SystemCalendarMirror.syncNow 在解析不到任何选中本时提前 return, 删完账号后正是此状态,purgeOrphans 永不执行。 修复: - SystemCalendarMirror.removeByAccount(accId):按 'mirror.<accId>-' 前缀删除该账号全部 镜像账户(兼容历史 '<accId>_' 桶名),逐个独立 try/catch + 清空日程降级; 绝不按 displayName 匹配 —— 不同账号下的同名日历本不会误删;同步清快照与选中项设置。 - AccountsPage 删除账号时先 removeByAccount(必须在改账号配置前,否则 bookId 解析不出)。 - EditAccountPage 取消勾选日历本时删除其镜像账户(用 href 算稳定 bookId)。 - SettingsPage 账号库重置时 removeAll。 - syncNow 提前 return 前加 purgeOrphanAccountMirrors 兜底,带安全阀(账号列表为空即跳过, 防读失败误删全量)。
This commit is contained in:
@@ -10,6 +10,7 @@ import { EventDb } from '../common/EventDb';
|
||||
import { LogUtil } from '../common/LogUtil';
|
||||
import { AppSettings } from '../common/AppSettings';
|
||||
import { ScreenKeeper } from '../common/ScreenKeeper';
|
||||
import { SystemCalendarMirror } from '../common/SystemCalendarMirror';
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
@@ -142,13 +143,24 @@ struct AccountsPage {
|
||||
});
|
||||
}
|
||||
|
||||
/** 执行删除:账号配置 + 该账号全部本地日程/待办 */
|
||||
/** 执行删除:账号配置 + 该账号全部本地日程/待办 + 该系统日历中该账号的全部镜像日历本 */
|
||||
private async confirmDeleteAccount(acc: DavAccount): Promise<void> {
|
||||
const context = this.getUIContext().getHostContext();
|
||||
if (context === undefined) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// ⭐ 先清系统日历里属于**本账号**的镜像日历本(按 bookId 里的 accId 前缀匹配,
|
||||
// 绝不按显示名 → 不同账号的同名日历本不会误删)。
|
||||
// 必须在改账号配置**之前**做:一旦账号配置被删,bookId 就再也解析不出来,
|
||||
// 那些幽灵账户就永远清不掉了(这正是本次要修的 bug)。
|
||||
let mirrored: number = 0;
|
||||
try {
|
||||
mirrored = await SystemCalendarMirror.removeByAccount(context, acc.id);
|
||||
} catch (err) {
|
||||
// 系统日历清理失败不阻断账号删除(用户至少能删掉账号)
|
||||
LogUtil.write(`删除账号 ${acc.id}:清理系统日历镜像失败 ${(err as BusinessError).message}`);
|
||||
}
|
||||
this.accounts = this.accounts.filter((a: DavAccount): boolean => a.id !== acc.id);
|
||||
// force=true:删除最后一个账号时列表为空是合法场景,允许覆盖
|
||||
await AccountStore.saveAll(context, this.accounts, true);
|
||||
@@ -156,7 +168,11 @@ struct AccountsPage {
|
||||
await EventDb.deleteAccountEvents(context, acc.id);
|
||||
await AppSettings.cleanupAccountSettings(context, acc.id);
|
||||
this.getUIContext().getPromptAction()
|
||||
.showToast({ message: `「${acc.name}」已删除` });
|
||||
.showToast({
|
||||
message: mirrored > 0
|
||||
? `「${acc.name}」已删除,并清除系统日历中 ${mirrored} 个镜像日历本`
|
||||
: `「${acc.name}」已删除`
|
||||
});
|
||||
} catch (err) {
|
||||
const e = err as BusinessError;
|
||||
this.getUIContext().getPromptAction()
|
||||
|
||||
@@ -242,6 +242,21 @@ struct EditAccountPage {
|
||||
const pruned: number = await EventDb.pruneByHrefs(context, target.id, removedHrefs);
|
||||
LogUtil.write(`编辑账号保存:取消勾选/已失效 ${removedHrefs.length} 个日历本,清理本地日程 ${pruned} 行`);
|
||||
}
|
||||
// ⭐ 被取消勾选的日历本,其系统日历镜像账户也要一并删掉(否则取消同步后系统日历仍有幽灵账户)。
|
||||
// 此时账号配置即将被改写、listBooks 已解析不到它,故用 href 直接算稳定 bookId(与镜像侧同算法)。
|
||||
// ⚠️ 用稳定 bookId 删 —— 不同账号下有同名日历本时,bookId 里带 accId 前缀,绝不会删错。
|
||||
for (let oi: number = 0; oi < oldHrefs.length; oi++) {
|
||||
const oh: string = oldHrefs[oi];
|
||||
if (newHrefSet.has(oh)) {
|
||||
continue;
|
||||
}
|
||||
const bookId: string = SystemCalendarMirror.bookIdOf(target.id, oh, `${target.id}_${oi}`);
|
||||
try {
|
||||
await SystemCalendarMirror.removeById(context, bookId);
|
||||
} catch (err) {
|
||||
// 镜像账户删除失败不阻断保存(下次镜像前的孤儿清理还会兜底)
|
||||
}
|
||||
}
|
||||
const remapPairs: Array<[string, string]> = [];
|
||||
for (let oi: number = 0; oi < oldHrefs.length; oi++) {
|
||||
const oldNorm: string = DavClient.normalizeHref(oldHrefs[oi]);
|
||||
|
||||
@@ -682,9 +682,20 @@ struct SettingsPage {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// ⭐ 账号库整体重置 = 所有账号都没了 → 系统日历里的全部镜像账户也应一并清除
|
||||
// (否则会留下一堆无主的幽灵日历本,且再无人能对应回账号)。
|
||||
// 未授权/无镜像时返回 0,不影响重置本身。
|
||||
let mirrored: number = 0;
|
||||
try {
|
||||
mirrored = await SystemCalendarMirror.removeAll(this.context);
|
||||
} catch (err) {
|
||||
// 清理失败不阻断重置
|
||||
}
|
||||
await AccountStore.resetVault(this.context);
|
||||
this.getUIContext().getPromptAction().showToast({
|
||||
message: '账号库已重置,请重新添加账号'
|
||||
message: mirrored > 0
|
||||
? `账号库已重置,并清除系统日历中 ${mirrored} 个镜像日历本`
|
||||
: '账号库已重置,请重新添加账号'
|
||||
});
|
||||
} catch (err) {
|
||||
this.getUIContext().getPromptAction().showToast({
|
||||
|
||||
Reference in New Issue
Block a user