修复了重复日历第一次不显示的问题。
This commit is contained in:
@@ -153,11 +153,14 @@ export class CalendarDataService {
|
|||||||
rows.push(m);
|
rows.push(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 单次覆盖实例(RECURRENCE-ID 独立行):展开时跳过对应发生,避免重复
|
// 单次覆盖实例(RECURRENCE-ID 独立行):展开时跳过对应发生,避免重复。
|
||||||
|
// 注意:①排除键必须带 calKey(同一系列可能出现在多个日历本);
|
||||||
|
// ②只有"可见日历本"的覆盖行才参与排除——历史孤儿行(旧账号迁移残留)
|
||||||
|
// 自己不显示,却会把主事件的对应发生排除掉,导致"第一次不显示"
|
||||||
const overrideKeys: string[] = [];
|
const overrideKeys: string[] = [];
|
||||||
for (const e of rows) {
|
for (const e of rows) {
|
||||||
if (e.rrule === '' && e.recurring) {
|
if (e.rrule === '' && e.recurring && visibleKeys.includes(e.calKey)) {
|
||||||
overrideKeys.push(`${e.uid}_${e.startTime}`);
|
overrideKeys.push(`${e.calKey}_${e.uid}_${e.startTime}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let occTotal: number = 0;
|
let occTotal: number = 0;
|
||||||
@@ -181,7 +184,8 @@ export class CalendarDataService {
|
|||||||
}
|
}
|
||||||
const occs: number[] = RruleUtil.expand(e.rrule, e.startTime, start, end, exNums, 1500);
|
const occs: number[] = RruleUtil.expand(e.rrule, e.startTime, start, end, exNums, 1500);
|
||||||
if (occs.length > 0) {
|
if (occs.length > 0) {
|
||||||
times = occs.filter((occ: number): boolean => !overrideKeys.includes(`${e.uid}_${occ}`));
|
times = occs.filter((occ: number): boolean =>
|
||||||
|
!overrideKeys.includes(`${e.calKey}_${e.uid}_${occ}`));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const occ of times) {
|
for (const occ of times) {
|
||||||
|
|||||||
@@ -121,13 +121,15 @@ export class CardDataService {
|
|||||||
const end: number = start + 60 * 86400000;
|
const end: number = start + 60 * 86400000;
|
||||||
const sources = await CalendarDataService.loadSources(context);
|
const sources = await CalendarDataService.loadSources(context);
|
||||||
const events: DisplayEvent[] = await CalendarDataService.loadEvents(context, start, end, sources);
|
const events: DisplayEvent[] = await CalendarDataService.loadEvents(context, start, end, sources);
|
||||||
// 1) 过滤已结束超过 1 小时的;2) 按天分组,组内全天在前、有时间按开始时间排序;
|
// 1) 过滤:保留"今天 0 点以来"的日程(今天已结束的也显示,否则重复日程的
|
||||||
|
// 第一次发生会被隐藏,表现为"第一次不显示、第二次及以后显示");
|
||||||
|
// 2) 按天分组,组内全天在前、有时间按开始时间排序;
|
||||||
// 3) 平铺输出并给每组第一条打 showDate 标记(日期头只跟在自己日期前面)
|
// 3) 平铺输出并给每组第一条打 showDate 标记(日期头只跟在自己日期前面)
|
||||||
// 跨天日程:已开始未结束的归到"今天"、按全天显示,不再从开始那天重复显示
|
// 跨天日程:已开始未结束的归到"今天"、按全天显示,不再从开始那天重复显示
|
||||||
const upcoming: DisplayEvent[] = events
|
|
||||||
.filter((e: DisplayEvent): boolean => e.endTime >= now.getTime() - 3600000);
|
|
||||||
|
|
||||||
const todayKey: number = CardDataService.startOfDay(now.getTime());
|
const todayKey: number = CardDataService.startOfDay(now.getTime());
|
||||||
|
const upcoming: DisplayEvent[] = events
|
||||||
|
.filter((e: DisplayEvent): boolean => e.endTime >= todayKey);
|
||||||
|
|
||||||
const dayKey = (ms: number): number => CardDataService.startOfDay(ms);
|
const dayKey = (ms: number): number => CardDataService.startOfDay(ms);
|
||||||
const spansDays = (e: DisplayEvent): boolean =>
|
const spansDays = (e: DisplayEvent): boolean =>
|
||||||
dayKey(e.endTime) > dayKey(e.startTime);
|
dayKey(e.endTime) > dayKey(e.startTime);
|
||||||
|
|||||||
@@ -368,8 +368,8 @@ export class EventDb {
|
|||||||
await store.insert('events', EventDb.toBucket(e));
|
await store.insert('events', EventDb.toBucket(e));
|
||||||
added++;
|
added++;
|
||||||
} else if (found.etag !== r.etag || found.rrule !== r.rrule || found.exdate !== r.exdate
|
} else if (found.etag !== r.etag || found.rrule !== r.rrule || found.exdate !== r.exdate
|
||||||
|| found.reminder !== r.reminder) {
|
|| found.reminder !== r.reminder || found.recurring !== r.recurring) {
|
||||||
// 更新(rrule/exdate 变化也更新,兼容老数据回填)
|
// 更新(rrule/exdate/recurring 变化也更新,兼容老数据回填)
|
||||||
found.title = r.title;
|
found.title = r.title;
|
||||||
found.description = r.description;
|
found.description = r.description;
|
||||||
found.location = r.location;
|
found.location = r.location;
|
||||||
@@ -417,6 +417,26 @@ export class EventDb {
|
|||||||
await store.delete(predicates);
|
await store.delete(predicates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理孤儿行:calKey 既不是本机日历(local)、也不属于任何现有账号(accId_ 前缀)的历史残留数据。
|
||||||
|
* 典型来源:账号删除重建、日历重选后序号变化遗留的旧 calKey(如 `_13`、`acc1789274273124_0_13`)。
|
||||||
|
* 这些行会参与重复日程的 override 排除计算,导致重复日程的第一次发生不显示,必须物理删除。
|
||||||
|
* 匹配规则为前缀包含(NOT LIKE 'accId_%' 的 AND 组合),宁可少删不会误删有效数据。
|
||||||
|
*/
|
||||||
|
static async pruneOrphanCalKeys(context: common.Context, accIds: string[]): Promise<number> {
|
||||||
|
const store = await EventDb.getDb(context);
|
||||||
|
const predicates = new relationalStore.RdbPredicates('events');
|
||||||
|
predicates.notEqualTo('cal_key', 'local');
|
||||||
|
for (const id of accIds) {
|
||||||
|
if (id === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
predicates.and().notLike('cal_key', `${id}_%`);
|
||||||
|
}
|
||||||
|
const removed: number = await store.delete(predicates);
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重新勾选日历本后清理失效数据:
|
* 重新勾选日历本后清理失效数据:
|
||||||
* 删除该账号下 calKey 不在有效列表中的本地日程/待办(calKey = accId_序号,重选后序号会变)
|
* 删除该账号下 calKey 不在有效列表中的本地日程/待办(calKey = accId_序号,重选后序号会变)
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ export class IcsUtil {
|
|||||||
current.description = IcsUtil.unescape(value);
|
current.description = IcsUtil.unescape(value);
|
||||||
} else if (propName === 'LOCATION') {
|
} else if (propName === 'LOCATION') {
|
||||||
current.location = IcsUtil.unescape(value);
|
current.location = IcsUtil.unescape(value);
|
||||||
} else if (propName === 'RRULE' || propName === 'RECURREIENCE-ID') {
|
} else if (propName === 'RRULE' || propName === 'RECURRENCE-ID') {
|
||||||
current.recurring = true;
|
current.recurring = true;
|
||||||
if (propName === 'RRULE') {
|
if (propName === 'RRULE') {
|
||||||
current.rrule = value;
|
current.rrule = value;
|
||||||
|
|||||||
@@ -108,6 +108,13 @@ export class RruleUtil {
|
|||||||
if (targets.length === 0) {
|
if (targets.length === 0) {
|
||||||
targets.push(base.getDay());
|
targets.push(base.getDay());
|
||||||
}
|
}
|
||||||
|
// RFC 5545:DTSTART 始终是第一次发生——即使它的星期不在 BYDAY 中
|
||||||
|
// (例如周二创建的"每周一重复"日程,第一次是周二那次,必须显示)
|
||||||
|
if (byday.length > 0 && !targets.includes(base.getDay())) {
|
||||||
|
if (!accept(dtstart)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
const anchorWeek: number = RruleUtil.weekStartMs(dtstart);
|
const anchorWeek: number = RruleUtil.weekStartMs(dtstart);
|
||||||
let dayMs: number = baseZeroMs;
|
let dayMs: number = baseZeroMs;
|
||||||
let guard: number = 0;
|
let guard: number = 0;
|
||||||
@@ -129,6 +136,13 @@ export class RruleUtil {
|
|||||||
let y: number = base.getFullYear();
|
let y: number = base.getFullYear();
|
||||||
let m: number = base.getMonth();
|
let m: number = base.getMonth();
|
||||||
let guard: number = 0;
|
let guard: number = 0;
|
||||||
|
// RFC 5545:DTSTART 始终是第一次发生——即使它的日期不在 BYMONTHDAY 中
|
||||||
|
if (bymonthday.length > 0 &&
|
||||||
|
!bymonthday.some((v: number): boolean => v === base.getDate())) {
|
||||||
|
if (!accept(dtstart)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
while (guard < 1500) {
|
while (guard < 1500) {
|
||||||
guard++;
|
guard++;
|
||||||
const monthFirst: number = new Date(y, m, 1).getTime();
|
const monthFirst: number = new Date(y, m, 1).getTime();
|
||||||
|
|||||||
@@ -201,4 +201,23 @@ export class SyncEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理孤儿日程行:calKey 不属于任何现有账号(accId_ 前缀)也不是本机日历(local)的历史残留。
|
||||||
|
* 典型如账号重建/日历重选后遗留的 `_13`、`acc1789274273124_0_13` 等,
|
||||||
|
* 这些行会参与重复日程的 override 排除计算,导致重复日程第一次发生不显示。
|
||||||
|
* 建议在所有账号同步完成后调用。
|
||||||
|
*/
|
||||||
|
static async pruneOrphanRows(context: common.Context, accounts: DavAccount[]): Promise<void> {
|
||||||
|
try {
|
||||||
|
const accIds: string[] = accounts.map((a: DavAccount): string => a.id);
|
||||||
|
const removed: number = await EventDb.pruneOrphanCalKeys(context, accIds);
|
||||||
|
if (removed > 0) {
|
||||||
|
LogUtil.write(`清理孤儿日程行:${removed} 条(calKey 不属于任何现有账号)`);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
const e = err as BusinessError;
|
||||||
|
LogUtil.write(`清理孤儿日程行失败(忽略):${e.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -76,6 +76,7 @@ struct AccountsPage {
|
|||||||
if (acc.type === TYPE_CALDAV) {
|
if (acc.type === TYPE_CALDAV) {
|
||||||
await SyncEngine.withTimeout(
|
await SyncEngine.withTimeout(
|
||||||
SyncEngine.syncAccount(context as common.UIAbilityContext, acc), 120000);
|
SyncEngine.syncAccount(context as common.UIAbilityContext, acc), 120000);
|
||||||
|
await SyncEngine.pruneOrphanRows(context, this.accounts);
|
||||||
}
|
}
|
||||||
acc.itemCount = acc.calendarHrefs.length;
|
acc.itemCount = acc.calendarHrefs.length;
|
||||||
acc.lastSyncTime = this.formatNow();
|
acc.lastSyncTime = this.formatNow();
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// 混合展示 DAV 与系统日历;每分钟自动同步;可"回到今天"
|
// 混合展示 DAV 与系统日历;每分钟自动同步;可"回到今天"
|
||||||
import { router } from '@kit.ArkUI';
|
import { router } from '@kit.ArkUI';
|
||||||
import { common } from '@kit.AbilityKit';
|
import { common } from '@kit.AbilityKit';
|
||||||
import { BusinessError } from '@kit.BasicServicesKit';
|
import { BusinessError, pasteboard } from '@kit.BasicServicesKit';
|
||||||
import { DavAccount, AccountStore, CalSource, TYPE_CALDAV } from '../common/AccountStore';
|
import { DavAccount, AccountStore, CalSource, TYPE_CALDAV } from '../common/AccountStore';
|
||||||
import { DisplayEvent, CalendarDataService } from '../common/CalendarDataService';
|
import { DisplayEvent, CalendarDataService } from '../common/CalendarDataService';
|
||||||
import { SyncEngine } from '../common/SyncEngine';
|
import { SyncEngine } from '../common/SyncEngine';
|
||||||
@@ -12,6 +12,9 @@ import { LunarUtil } from '../common/LunarUtil';
|
|||||||
import { CardDataService } from '../common/CardDataService';
|
import { CardDataService } from '../common/CardDataService';
|
||||||
import { ReminderService } from '../common/ReminderService';
|
import { ReminderService } from '../common/ReminderService';
|
||||||
import { AppSettings } from '../common/AppSettings';
|
import { AppSettings } from '../common/AppSettings';
|
||||||
|
import { EventDb, LocalEvent } from '../common/EventDb';
|
||||||
|
import { RruleUtil } from '../common/RruleUtil';
|
||||||
|
import { IcsUtil } from '../common/IcsUtil';
|
||||||
|
|
||||||
/** 月视图单元格 */
|
/** 月视图单元格 */
|
||||||
class MonthCell {
|
class MonthCell {
|
||||||
@@ -284,6 +287,7 @@ struct Index {
|
|||||||
}
|
}
|
||||||
await SyncEngine.withTimeout(
|
await SyncEngine.withTimeout(
|
||||||
SyncEngine.syncAccount(context as common.UIAbilityContext, acc), 120000);
|
SyncEngine.syncAccount(context as common.UIAbilityContext, acc), 120000);
|
||||||
|
await SyncEngine.pruneOrphanRows(context, this.accounts);
|
||||||
acc.lastSyncTime = this.formatNow();
|
acc.lastSyncTime = this.formatNow();
|
||||||
await AccountStore.saveAll(context, this.accounts);
|
await AccountStore.saveAll(context, this.accounts);
|
||||||
this.getUIContext().getPromptAction()
|
this.getUIContext().getPromptAction()
|
||||||
@@ -341,6 +345,7 @@ struct Index {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await SyncEngine.settleLocalEvents(context);
|
await SyncEngine.settleLocalEvents(context);
|
||||||
|
await SyncEngine.pruneOrphanRows(context, this.accounts);
|
||||||
await AccountStore.saveAll(context, this.accounts);
|
await AccountStore.saveAll(context, this.accounts);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const e = err as BusinessError;
|
const e = err as BusinessError;
|
||||||
@@ -608,7 +613,7 @@ struct Index {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 切换视图:进入列表视图时按需加载(今天 ~ 未来2年,已结束的不显示) */
|
/** 切换视图:进入列表视图时按需加载(今天整天 ~ 未来2年,昨天之前已结束的不显示) */
|
||||||
private async handleModeSwitch(key: string): Promise<void> {
|
private async handleModeSwitch(key: string): Promise<void> {
|
||||||
this.mode = key;
|
this.mode = key;
|
||||||
if (key === 'agenda') {
|
if (key === 'agenda') {
|
||||||
@@ -630,8 +635,9 @@ struct Index {
|
|||||||
const end: number = now + 730 * 86400000;
|
const end: number = now + 730 * 86400000;
|
||||||
try {
|
try {
|
||||||
const raw: DisplayEvent[] = await CalendarDataService.loadEvents(context, start, end, this.sources);
|
const raw: DisplayEvent[] = await CalendarDataService.loadEvents(context, start, end, this.sources);
|
||||||
// 只保留未结束的(跨天进行中的保留);跨天且已开始的归到今天,与卡片一致
|
// 保留"今天 0 点以来"的全部日程:今天已结束的也显示(否则重复日程的第一次发生会被隐藏),
|
||||||
this.agendaEvents = raw.filter((e: DisplayEvent): boolean => e.endTime >= now - 3600000);
|
// 昨天及更早且已结束的不显示;跨天进行中的归到今天,与卡片一致
|
||||||
|
this.agendaEvents = raw.filter((e: DisplayEvent): boolean => e.endTime >= start);
|
||||||
this.agendaGroupsData = this.buildAgendaGroups(this.agendaEvents);
|
this.agendaGroupsData = this.buildAgendaGroups(this.agendaEvents);
|
||||||
this.agendaStale = false;
|
this.agendaStale = false;
|
||||||
LogUtil.write(`列表视图加载:${this.agendaEvents.length} 条(今天~未来2年),分组 ${this.agendaGroupsData.length} 组`);
|
LogUtil.write(`列表视图加载:${this.agendaEvents.length} 条(今天~未来2年),分组 ${this.agendaGroupsData.length} 组`);
|
||||||
@@ -752,6 +758,9 @@ struct Index {
|
|||||||
}
|
}
|
||||||
.width('100%')
|
.width('100%')
|
||||||
.padding({ left: 20, right: 20, top: 6 })
|
.padding({ left: 20, right: 20, top: 6 })
|
||||||
|
.gesture(LongPressGesture().onAction(() => {
|
||||||
|
this.showOccurrenceDebug(this.selectedDate);
|
||||||
|
}))
|
||||||
|
|
||||||
this.eventList()
|
this.eventList()
|
||||||
}
|
}
|
||||||
@@ -759,6 +768,110 @@ struct Index {
|
|||||||
.layoutWeight(1)
|
.layoutWeight(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 调试(临时):长按月视图日期标题,检查重复日程在该日的首次发生情况 */
|
||||||
|
private async showOccurrenceDebug(dateMs: number): Promise<void> {
|
||||||
|
const context = this.getUIContext().getHostContext();
|
||||||
|
if (context === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const dayStart: number = this.startOfDay(dateMs);
|
||||||
|
const dayEnd: number = dayStart + 86400000;
|
||||||
|
const winStart: number = dayStart - 365 * 86400000;
|
||||||
|
const winEnd: number = dayEnd + 365 * 86400000;
|
||||||
|
const rows: LocalEvent[] = await EventDb.queryRange(context, winStart, winEnd);
|
||||||
|
const sources = await CalendarDataService.loadSources(context);
|
||||||
|
const visibleKeys: string[] = sources.filter((s: CalSource): boolean => s.visible)
|
||||||
|
.map((s: CalSource): string => s.calKey);
|
||||||
|
const masters = new Map<string, LocalEvent>();
|
||||||
|
const overrides = new Map<string, LocalEvent[]>();
|
||||||
|
for (const r of rows) {
|
||||||
|
if (r.rrule !== '') {
|
||||||
|
masters.set(r.uid, r);
|
||||||
|
} else {
|
||||||
|
const arr = overrides.get(r.uid);
|
||||||
|
if (arr === undefined) {
|
||||||
|
overrides.set(r.uid, [r]);
|
||||||
|
} else {
|
||||||
|
arr.push(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const p = (n: number): string => (n < 10 ? '0' + n : String(n));
|
||||||
|
const fmt = (ms: number): string => {
|
||||||
|
const d = new Date(ms);
|
||||||
|
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`;
|
||||||
|
};
|
||||||
|
const lines: string[] = [`调试 ${this.fmtDateCn(dateMs)}`, `visibleKeys=${visibleKeys.join(',')}`];
|
||||||
|
let idx: number = 0;
|
||||||
|
for (const m of masters.values()) {
|
||||||
|
if (idx >= 6) {
|
||||||
|
lines.push('…(更多系列省略)');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// 只列出与该日期相关的系列:主行开始日在该日±90天内,或展开命中该日
|
||||||
|
const exNums: number[] = [];
|
||||||
|
if (m.exdate !== '') {
|
||||||
|
for (const raw of m.exdate.split(';')) {
|
||||||
|
const t = IcsUtil.parseTime(raw, !raw.includes('T'));
|
||||||
|
if (t !== null) {
|
||||||
|
exNums.push(t.time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const occs: number[] = RruleUtil.expand(m.rrule, m.startTime, m.startTime, winEnd, exNums, 400);
|
||||||
|
const hitsDay: boolean = occs.some((o: number): boolean => o >= dayStart && o < dayEnd);
|
||||||
|
const nearStart: boolean = Math.abs(m.startTime - dayStart) <= 90 * 86400000;
|
||||||
|
if (!hitsDay && !nearStart) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
const hasFirst: boolean = occs.some((o: number): boolean => o === m.startTime);
|
||||||
|
const mVis: boolean = visibleKeys.includes(m.calKey);
|
||||||
|
lines.push(`◇ ${m.title}`);
|
||||||
|
lines.push(` uid=${m.uid.substring(0, 8)} 主行=${fmt(m.startTime)} rec=${m.recurring ? 1 : 0} calKey=${m.calKey} vis=${mVis ? 1 : 0} dirty=${m.dirty ? 1 : 0}`);
|
||||||
|
lines.push(` rrule=${m.rrule === '' ? '(空!)' : m.rrule}`);
|
||||||
|
lines.push(` exdate=${m.exdate === '' ? '无' : m.exdate}`);
|
||||||
|
lines.push(` 展开条数=${occs.length} 含首次=${hasFirst ? '是' : '否'} 首次=${occs.length > 0 ? fmt(occs[0]) : '无'} 该日发生=${hitsDay ? '是' : '否'}`);
|
||||||
|
const ovs = overrides.get(m.uid) ?? [];
|
||||||
|
if (ovs.length === 0) {
|
||||||
|
lines.push(' 覆盖实例: 无');
|
||||||
|
} else {
|
||||||
|
for (const o of ovs.slice(0, 5)) {
|
||||||
|
const oVis: boolean = visibleKeys.includes(o.calKey);
|
||||||
|
lines.push(` 覆盖: ${fmt(o.startTime)}~${fmt(o.endTime)} rec=${o.recurring ? 1 : 0} calKey=${o.calKey} vis=${oVis ? 1 : 0} dirty=${o.dirty ? 1 : 0}`);
|
||||||
|
}
|
||||||
|
if (ovs.length > 5) {
|
||||||
|
lines.push(` 覆盖共 ${ovs.length} 条`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lines.length <= 2) {
|
||||||
|
lines.push('(该日期附近没有重复主事件)');
|
||||||
|
}
|
||||||
|
const text: string = lines.join('\n').substring(0, 3500);
|
||||||
|
this.getUIContext().showAlertDialog({
|
||||||
|
title: '重复日程调试',
|
||||||
|
message: text,
|
||||||
|
autoCancel: true,
|
||||||
|
alignment: DialogAlignment.Center,
|
||||||
|
primaryButton: {
|
||||||
|
value: '复制',
|
||||||
|
action: (): void => {
|
||||||
|
const data = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, text);
|
||||||
|
pasteboard.getSystemPasteboard().setData(data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
secondaryButton: {
|
||||||
|
value: '关闭',
|
||||||
|
action: (): void => {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
// 调试失败不影响主流程
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 周视图整周切换(左滑下一周、右滑上一周);跨月时自动重载数据 */
|
/** 周视图整周切换(左滑下一周、右滑上一周);跨月时自动重载数据 */
|
||||||
private switchWeek(delta: number): void {
|
private switchWeek(delta: number): void {
|
||||||
this.selectedDate += delta * 7 * 86400000;
|
this.selectedDate += delta * 7 * 86400000;
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export default class SyncWorkAbility extends WorkSchedulerExtensionAbility {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
await SyncEngine.settleLocalEvents(context);
|
await SyncEngine.settleLocalEvents(context);
|
||||||
|
await SyncEngine.pruneOrphanRows(context, accounts);
|
||||||
// 同步后刷新卡片 + 重建提醒,保证后台同步的成果直接可见
|
// 同步后刷新卡片 + 重建提醒,保证后台同步的成果直接可见
|
||||||
await CardDataService.pushToAllForms(context);
|
await CardDataService.pushToAllForms(context);
|
||||||
await ReminderService.refreshReminders(context);
|
await ReminderService.refreshReminders(context);
|
||||||
|
|||||||
Reference in New Issue
Block a user