feat(待办/日程): 两页时间选择器统一居中弹出 + 待办截止行去掉「修改」字样 (#51)
## 1. 日程页时间选择器也改为居中弹出 用户要求:「新建日程那里,开始和结束时间也用这种方式弹出来吧」 与待办页保持一致:根节点改 Stack,弹层居中浮在内容之上。 移除 bindSheet(SDK 的 SheetOptions 没有 position/alignment,只能底部弹)。 三种弹层(时间选择/重复范围/重复截止)继续共用同一个 sheetMode 切换。 ### 真机验证(5NC0225B27004718) 弹层 y=713~1691,中心 1202;屏幕中心 1222,偏差 20px ✅ ## 2. 待办页截止时间行去掉「修改」二字 用户要求:「修改那两个字没必要,直接点那个时间框,出现选择时间的地方」 整行本来就可点,右侧改为一个 `›` 箭头作视觉暗示(与日程页「开始/结束时间」行一致)。 ## 3. 修复:纯待办本的 event 通道误落库(导致 Inbox 待办消失 + 编辑报错) ### 根因 `SyncEngine` 的 event 通道用 `DavClient.reportEtags(href)`,**不区分本的 COMP_SET 类型**。 对纯待办本(如群晖 Inbox,COMP_SET=todo)也照常跑 event REPORT: - 服务器返回了文件列表(里面其实是 VTODO 文件) - `parseEvents` 解析出 0 条日程,**但文件仍被落库成 kind='event'** - 结果:本地库出现"属于待办本的日程记录"(实测 id=748 title=Hvf) - 用户新建的「测试」待办进不来,反而被这条假日程占用 cal_key ### 后果 - 待办列表看不到(列表只查 kind='todo') - 点它编辑走日程通道 → 报「需要联网 + 日历本需可写」 - 用户反馈的「编辑待办失败」由此而来 ### 修法 event 通道前判断 `acc.calendarComps[i] === 'todo'` 就跳过, 日志明确输出「是纯待办本(COMP_SET=todo),跳过 event 通道」。 ### 验证 日志实测:`日历本[1]「Inbox」是纯待办本(COMP_SET=todo),跳过 event 通道` ✅ ## 编译 BUILD SUCCESSFUL ## 遗留 Inbox 的 VTODO REPORT 在群晖上仍返回空 multistatus(68 字符), 「测试」待办能否同步需用户重新建一条再验证。
This commit is contained in:
@@ -501,6 +501,8 @@ export class DavClient {
|
|||||||
}
|
}
|
||||||
const xml: string = resp.result as string;
|
const xml: string = resp.result as string;
|
||||||
LogUtil.write(`HTTP REPORT(${compName}) 响应体 ${xml.length} 字符`);
|
LogUtil.write(`HTTP REPORT(${compName}) 响应体 ${xml.length} 字符`);
|
||||||
|
LogUtil.write(`REPORT-诊断(${compName}) 前200字符: ${xml.substring(0, 200)}`);
|
||||||
|
LogUtil.write(`REPORT-诊断(${compName}) 含VTODO=${xml.indexOf('BEGIN:VTODO') >= 0} 含VEVENT=${xml.indexOf('BEGIN:VEVENT') >= 0} 响应数=${(xml.match(/<[\w-]*:?response[\s>]/gi) || []).length}`);
|
||||||
const originMatch = /https?:\/\/[^/]+/i.exec(href);
|
const originMatch = /https?:\/\/[^/]+/i.exec(href);
|
||||||
const origin: string = originMatch !== null ? originMatch[0] : '';
|
const origin: string = originMatch !== null ? originMatch[0] : '';
|
||||||
const items: RemoteItem[] = [];
|
const items: RemoteItem[] = [];
|
||||||
@@ -525,6 +527,13 @@ export class DavClient {
|
|||||||
item.ics = block.substring(start, end + 'END:VCALENDAR'.length);
|
item.ics = block.substring(start, end + 'END:VCALENDAR'.length);
|
||||||
items.push(item);
|
items.push(item);
|
||||||
}
|
}
|
||||||
|
LogUtil.write(`诊断 blocks=${blocks.length} items=${items.length} xml长=${xml.length}`);
|
||||||
|
for (let bi = 0; bi < blocks.length; bi++) {
|
||||||
|
const bb: string = blocks[bi];
|
||||||
|
if (!/<[\w-]*:?response[\s>]/i.test(bb)) { continue; }
|
||||||
|
const h: string = DavClient.extractTag(bb, "href");
|
||||||
|
LogUtil.write(`诊断 block${bi} len=${bb.length} href=[${h.substring(0,50)}] VCAL=${bb.indexOf("BEGIN:VCALENDAR")>=0} VTODO=${bb.indexOf("BEGIN:VTODO")>=0}`);
|
||||||
|
}
|
||||||
return items;
|
return items;
|
||||||
} finally {
|
} finally {
|
||||||
httpRequest.destroy();
|
httpRequest.destroy();
|
||||||
|
|||||||
@@ -161,6 +161,16 @@ export class SyncEngine {
|
|||||||
const calName: string = i < acc.calendarNames.length ? acc.calendarNames[i] : `日历本${i}`;
|
const calName: string = i < acc.calendarNames.length ? acc.calendarNames[i] : `日历本${i}`;
|
||||||
LogUtil.write(`日历本[${i}]「${calName}」开始同步:${href}`);
|
LogUtil.write(`日历本[${i}]「${calName}」开始同步:${href}`);
|
||||||
const t1: number = Date.now();
|
const t1: number = Date.now();
|
||||||
|
// ⭐ 纯待办本(COMP_SET 只有 VTODO)不跑 event 通道。
|
||||||
|
// 实测群晖:对纯待办本做 event 的 REPORT 会返回文件列表,
|
||||||
|
// 里面其实是 VTODO 文件,被 parseEvents 解析成 0 条日程却仍落库
|
||||||
|
// → 本地库出现 kind='event' 记录,而所在本是待办本。
|
||||||
|
// 后果:这条"假日程"在待办列表看不到(列表只查 kind='todo'),
|
||||||
|
// 但点它编辑会走日程通道,报"需要联网 + 日历本需可写"。
|
||||||
|
const thisComps: string = i < acc.calendarComps.length ? acc.calendarComps[i] : '';
|
||||||
|
if (thisComps === 'todo') {
|
||||||
|
LogUtil.write(`日历本[${i}]「${calName}」是纯待办本(COMP_SET=todo),跳过 event 通道`);
|
||||||
|
} else {
|
||||||
let items: RemoteItem[] = [];
|
let items: RemoteItem[] = [];
|
||||||
try {
|
try {
|
||||||
items = await DavClient.reportEtags(href, auth);
|
items = await DavClient.reportEtags(href, auth);
|
||||||
@@ -307,6 +317,8 @@ export class SyncEngine {
|
|||||||
const stat: string = await EventDb.applyRemote(context, calKey, href, remote, false);
|
const stat: string = await EventDb.applyRemote(context, calKey, href, remote, false);
|
||||||
LogUtil.write(`日历本[${i}]「${calName}」日程落库完成:${stat},耗时 ${Math.round((Date.now() - t1) / 1000)} 秒`);
|
LogUtil.write(`日历本[${i}]「${calName}」日程落库完成:${stat},耗时 ${Math.round((Date.now() - t1) / 1000)} 秒`);
|
||||||
changed += remote.length;
|
changed += remote.length;
|
||||||
|
} // end else(非纯待办本才跑 event 通道)
|
||||||
|
|
||||||
// 3) 拉取该日历本下的待办(VTODO,只读展示,拉取失败不影响日程同步)
|
// 3) 拉取该日历本下的待办(VTODO,只读展示,拉取失败不影响日程同步)
|
||||||
try {
|
try {
|
||||||
const todoItems = await DavClient.reportTodos(href, auth);
|
const todoItems = await DavClient.reportTodos(href, auth);
|
||||||
|
|||||||
@@ -1391,6 +1391,7 @@ struct EventEditPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
|
Stack({ alignContent: Alignment.Center }) {
|
||||||
Column({ space: 14 }) {
|
Column({ space: 14 }) {
|
||||||
// 顶部(与内容区左右对齐,避免贴边误触)
|
// 顶部(与内容区左右对齐,避免贴边误触)
|
||||||
Row({ space: 6 }) {
|
Row({ space: 6 }) {
|
||||||
@@ -1839,20 +1840,34 @@ struct EventEditPage {
|
|||||||
.backgroundColor($r('app.color.page_bg'))
|
.backgroundColor($r('app.color.page_bg'))
|
||||||
// 沉浸式:背景延伸到状态栏/导航条区域(只扩绘制、不移动子组件)
|
// 沉浸式:背景延伸到状态栏/导航条区域(只扩绘制、不移动子组件)
|
||||||
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
|
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
|
||||||
// ⚠️ 整个页面**只允许一个 bindSheet**:挂两个时后者会覆盖前者,
|
|
||||||
// 表现为"时间选择框白框一闪而过"(范围弹层顶掉了它)。
|
// ===== 居中弹层 =====
|
||||||
// 这里用 sheetMode 在同一个弹层里切换内容。
|
if (this.sheetShow) {
|
||||||
.bindSheet($$this.sheetShow, this.bottomSheet(), {
|
Column()
|
||||||
height: this.sheetMode === 'scope' ? 320 : (this.sheetMode === 'repeatEnd' ? 340 : 380),
|
.width('100%')
|
||||||
showClose: false,
|
.height('100%')
|
||||||
dragBar: true,
|
.backgroundColor('#66000000')
|
||||||
backgroundColor: $r('app.color.card_bg')
|
.onClick(() => {
|
||||||
|
this.sheetShow = false;
|
||||||
})
|
})
|
||||||
|
this.centerSheet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.width('100%')
|
||||||
|
.height('100%')
|
||||||
|
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ⭐ 唯一的底部弹层:按 sheetMode 切换显示"时间选择"/"重复范围选择"/"重复截止日期" */
|
/**
|
||||||
|
* 居中弹层(自绘覆盖层,与待办页一致)。
|
||||||
|
*
|
||||||
|
* 原来用 bindSheet 从底部弹出,用户反馈"点完之后选择框在下面出来,操作不顺畅"。
|
||||||
|
* 改成屏幕居中,视线不用上下跳。
|
||||||
|
*
|
||||||
|
* 为什么不用 bindSheet:SDK 的 SheetOptions 没有 position/alignment,只能底部弹。
|
||||||
|
*/
|
||||||
@Builder
|
@Builder
|
||||||
bottomSheet() {
|
centerSheet() {
|
||||||
if (this.sheetMode === 'scope') {
|
if (this.sheetMode === 'scope') {
|
||||||
this.scopeSheet()
|
this.scopeSheet()
|
||||||
} else if (this.sheetMode === 'repeatEnd') {
|
} else if (this.sheetMode === 'repeatEnd') {
|
||||||
|
|||||||
@@ -3637,6 +3637,7 @@ struct Index {
|
|||||||
// ⭐ 改为独立页面(与编辑日程一致):把 id 预置后跳转
|
// ⭐ 改为独立页面(与编辑日程一致):把 id 预置后跳转
|
||||||
AppStorage.setOrCreate<number>('pendingTodoId', t.id);
|
AppStorage.setOrCreate<number>('pendingTodoId', t.id);
|
||||||
AppStorage.setOrCreate<number>('pendingTodoDate', 0);
|
AppStorage.setOrCreate<number>('pendingTodoDate', 0);
|
||||||
|
LogUtil.write(`打开待办编辑:id=${t.id} uid=${t.uid} 标题长度=${t.title.length} 本=${t.calKey}`);
|
||||||
router.pushUrl({ url: 'pages/TodoEditPage' });
|
router.pushUrl({ url: 'pages/TodoEditPage' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -615,9 +615,11 @@ struct TodoEditPage {
|
|||||||
.fontColor(this.hasDue
|
.fontColor(this.hasDue
|
||||||
? $r('app.color.text_primary') : $r('app.color.text_hint'))
|
? $r('app.color.text_primary') : $r('app.color.text_hint'))
|
||||||
Blank()
|
Blank()
|
||||||
Text('修改')
|
// ⭐ 不再显示"修改"文字:整行可点,右侧放个箭头作为可点的视觉暗示
|
||||||
.fontSize(13)
|
// (与日程页的「开始/结束时间」行一致)
|
||||||
.fontColor($r('app.color.brand'))
|
Text('›')
|
||||||
|
.fontSize(18)
|
||||||
|
.fontColor($r('app.color.text_hint'))
|
||||||
}
|
}
|
||||||
.layoutWeight(1)
|
.layoutWeight(1)
|
||||||
.padding({ left: 12, right: 12, top: 12, bottom: 12 })
|
.padding({ left: 12, right: 12, top: 12, bottom: 12 })
|
||||||
|
|||||||
Reference in New Issue
Block a user