修复:编辑重复日程缺范围选择;同步并发不再误报失败
问题1(用户反馈):删除重复日程有"仅这一次/此次及以后/全部"三选项,编辑却没有。
根因:save() 把 validate() 与 chosenBook() 检查放在 isSeriesOccurrence() **之前**,
任一不满足即提前 return,永远到不了范围选择弹层;delete 路径则是先判范围。
修法:
- save() 把"重复日程先选范围"提到最前(与删除路径一致),校验推迟到 doSave() 内
- chosenBook() 增加兜底:展开编辑时若该日程所属日历本不在"可写清单"里
(被标记只读/写权限探测失败),用该日程自己的 calKey/href 构造目标;
initPage 里还会用 CalendarDataBridge.lookupBook 把它补进选择列表(带真实名称/颜色)
- 新增 original 原始行快照:doSave 会就地改写 this.event 的 calKey/startTime,
而 EXDATE/UNTIL/拆系列必须依据原值 —— 否则范围计算用错系列
- applySeriesEdit 的 one/future 分支在改写当前行后,用 EventDb.restoreRowById 还原原行,
避免原系列残留幽灵行
- 加保存判定日志(脱敏)便于诊断
问题2(用户反馈):同步进行中再点手动同步/账号管理确定,提示"同步失败"造成误解。
根因:互斥锁抛的是普通 Error,三个调用点统一按"失败"提示。
修法:
- SyncEngine 新增 SyncBusyError 专用类型 + isSyncing/isAnySyncing 查询;
锁命中时抛 SyncBusyError,且 catch 不再把它包成普通 Error
- Index.syncSingle / AccountsPage.syncSingleAccount:命中→提示
"有同步任务正在进行中,请耐心等待",不显示失败
- Index.syncAll:命中记为 busySkipped(不算失败),全部被跳过时也只提示等待
This commit is contained in:
@@ -7,7 +7,7 @@ import { geoLocationManager } from '@kit.LocationKit';
|
||||
import { BusinessError, pasteboard } from '@kit.BasicServicesKit';
|
||||
import { DavAccount, AccountStore, CalSource, TYPE_CALDAV } from '../common/AccountStore';
|
||||
import { DisplayEvent, CalendarDataService } from '../common/CalendarDataService';
|
||||
import { SyncEngine } from '../common/SyncEngine';
|
||||
import { SyncEngine, SyncBusyError } from '../common/SyncEngine';
|
||||
import { LogUtil } from '../common/LogUtil';
|
||||
import { LunarUtil } from '../common/LunarUtil';
|
||||
import { CardDataService } from '../common/CardDataService';
|
||||
@@ -584,6 +584,12 @@ struct Index {
|
||||
this.getUIContext().getPromptAction()
|
||||
.showToast({ message: `「${acc.name}」同步完成` });
|
||||
} catch (err) {
|
||||
// ⭐ 已有同步在进行中 → 提示"请耐心等待",不报"失败"
|
||||
if (err instanceof SyncBusyError) {
|
||||
this.getUIContext().getPromptAction()
|
||||
.showToast({ message: '有同步任务正在进行中,请耐心等待' });
|
||||
return;
|
||||
}
|
||||
const e = err as BusinessError;
|
||||
this.getUIContext().getPromptAction()
|
||||
.showToast({ message: `同步失败:${e.message}` });
|
||||
@@ -633,6 +639,8 @@ struct Index {
|
||||
await ScreenKeeper.acquire(context as common.UIAbilityContext);
|
||||
let ok: number = 0;
|
||||
let failMsg: string = '';
|
||||
// ⭐ 是否因为"已有同步在进行"而被跳过(这不算失败,只提示等待)
|
||||
let busySkipped: boolean = false;
|
||||
// 备份模式:先把系统本地日历导入目标日历本(幂等),再随正常同步推送上服务器
|
||||
try {
|
||||
await SystemCalendarImport.importIfNeeded(context);
|
||||
@@ -654,6 +662,11 @@ struct Index {
|
||||
acc.lastSyncTime = this.formatNow();
|
||||
ok++;
|
||||
} catch (err) {
|
||||
// ⭐ 并发被互斥锁拦下:不是失败,只是"已有同步在跑",稍后自动同步会覆盖,直接略过
|
||||
if (err instanceof SyncBusyError) {
|
||||
busySkipped = true;
|
||||
continue;
|
||||
}
|
||||
const e = err as BusinessError;
|
||||
failMsg = e.message;
|
||||
}
|
||||
@@ -684,6 +697,10 @@ struct Index {
|
||||
if (failMsg !== '') {
|
||||
this.getUIContext().getPromptAction()
|
||||
.showToast({ message: ok > 0 ? `同步完成 ${ok} 个,失败:${failMsg}` : `同步失败:${failMsg}` });
|
||||
} else if (busySkipped && ok === 0) {
|
||||
// 全部账号都因"已有同步在进行"被跳过 → 只提示等待,不说失败
|
||||
this.getUIContext().getPromptAction()
|
||||
.showToast({ message: '有同步任务正在进行中,请耐心等待' });
|
||||
} else if (ok > 0 && manual) {
|
||||
this.getUIContext().getPromptAction()
|
||||
.showToast({ message: `同步完成(${ok} 个账号)` });
|
||||
|
||||
Reference in New Issue
Block a user