fix(日历本): 按 COMP_SET 类型分别列出 —— 待办只给待办本,日程只给日历本

上一个提交把"全部可写本"铺开,导致新建待办时连纯日历本(娱乐/生活/工作/家庭)
也列出来,新建日程时又把纯待办本列出来。用户选错类型时服务器会拒绝写入,
或写进去但永远不在对应列表显示。

## 依据
`DavAccount.calendarComps[i]` 早就在库里存着服务器 COMP_SET 声明:
  'event'   只有 VEVENT
  'todo'    只有 VTODO
  'both'    两者都支持
  'unknown' 未声明(旧数据)

但 `CalSource` 没透传它,界面层拿不到类型,只能按"可写"一刀切。

## 改动
- `CalSource` 增加 `comps` 字段
- `CalendarDataService.loadSources` 从 `acc.calendarComps[i]` 透传(空串归 'unknown')
- 待办侧(`Index.openTodoCreator`):排除 `comps === 'event'`
- 日程侧(`EventEditPage.CalendarDataBridge.loadWritableDavSources`):排除 `comps === 'todo'`

**'unknown' 两端都保留**:旧数据没有 COMP_SET 信息,武断排除会让老用户
升级后发现日历本"消失"。

## 真机验证(5NC0225B27004718)

服务器实际类型(PROPFIND 实测):

| 本 | COMP_SET | 待办列表 | 日程列表 |
|---|---|---|---|
| 娱乐 / 生活 / 工作 / 家庭 | VEVENT | 不显示 | 显示 |
| Inbox / 家庭计划 / 工作任务 / 个人成长 | VTODO | 显示 | 不显示 |

改后实测:
- 新建待办 → 只列「群晖:Inbox / 家庭计划 / 工作任务 / 个人成长」4 个 ✅
- 新建日程 → 只列「群晖 · 娱乐 / 生活 / 工作 / 家庭」4 个 ✅

两端的本数量都从 8 降到 4,与服务器声明完全一致。

## 编译
`BUILD SUCCESSFUL`
This commit is contained in:
2026-11-03 23:04:00 +08:00
parent ca97ec7fcd
commit 2bb620a6ed
4 changed files with 23 additions and 0 deletions
@@ -77,6 +77,14 @@ export class CalSource {
source: string = 'dav'; // 'dav' | 'system' | 'local' source: string = 'dav'; // 'dav' | 'system' | 'local'
visible: boolean = true; visible: boolean = true;
writable: boolean = true; // 只读日历本中的日程只能查看详情,不能编辑 writable: boolean = true; // 只读日历本中的日程只能查看详情,不能编辑
/**
* 本支持哪些组件(来自服务器 COMP_SET 声明):
* 'event' 纯日历本(新建日程可选,新建待办不可选)
* 'todo' 纯待办本(反过来)
* 'both' 两者都可
* 'unknown' 服务器未声明 → 两边都按可用处理(旧数据兼容)
*/
comps: string = 'unknown';
} }
/** 与 UI 无关的调色板 */ /** 与 UI 无关的调色板 */
@@ -117,6 +117,9 @@ export class CalendarDataService {
const detected: boolean = acc.calendarWritable.length > i const detected: boolean = acc.calendarWritable.length > i
? acc.calendarWritable[i] !== '0' : true; ? acc.calendarWritable[i] !== '0' : true;
s.writable = detected && !manualKeys.includes(s.calKey); s.writable = detected && !manualKeys.includes(s.calKey);
// 透传本支持的类型(新建待办/日程时据此过滤,避免把待办写进纯日历本)
s.comps = i < acc.calendarComps.length && acc.calendarComps[i] !== ''
? acc.calendarComps[i] : 'unknown';
sources.push(s); sources.push(s);
} }
} }
@@ -2159,6 +2159,13 @@ class CalendarDataBridge {
if (!detected || manualKeys.includes(`${acc.id}_${i}`)) { if (!detected || manualKeys.includes(`${acc.id}_${i}`)) {
continue; continue;
} }
// ⭐ 只列**能放日程**的本:纯待办本(COMP_SET 只有 VTODO)写不进 VEVENT。
// 'both' / 'unknown' 保留,理由同 Index.openTodoCreator。
const comp: string = i < acc.calendarComps.length && acc.calendarComps[i] !== ''
? acc.calendarComps[i] : 'unknown';
if (comp === 'todo') {
continue;
}
const s = new CalSourceWithHref(); const s = new CalSourceWithHref();
s.calKey = `${acc.id}_${i}`; s.calKey = `${acc.id}_${i}`;
let name: string = i < acc.calendarNames.length ? acc.calendarNames[i] : ''; let name: string = i < acc.calendarNames.length ? acc.calendarNames[i] : '';
+5
View File
@@ -3174,6 +3174,11 @@ struct Index {
if (!s.writable || s.source !== 'dav') { if (!s.writable || s.source !== 'dav') {
continue; continue;
} }
// ⭐ 只列**能放待办**的本:纯日历本(COMP_SET 只有 VEVENT)写不进 VTODO。
// 'both' / 'unknown' 都保留 —— unknown 是服务器未声明或旧数据,不能武断排除。
if (s.comps === 'event') {
continue;
}
// calKey 形如 "<accountId>_<index>" // calKey 形如 "<accountId>_<index>"
const us: number = s.calKey.lastIndexOf('_'); const us: number = s.calKey.lastIndexOf('_');
if (us <= 0) { if (us <= 0) {