v84: 首页「+ 新建」日程 + 红线去端点 + 新建表单两处可见性修复
用户 2026-10-23 原话:「日程,没有新建日程按钮,名册,也没有新增成员这个按钮。」
「首页上的日程,红色线不对,变短了左侧缺了一块。在日程模块中,那个红线左侧
是不是还有一个红点?如果有,去掉。」
① 首页日程区块加「+ 新建」(FbHomePage / Widgets.FbSectionTitle)
- FbSectionTitle 扩两个可选参数 addText / onAdd,带默认值 ⇒ 老调用点一行不改
- 按需懒拉 /calendar/books,缓存进 calBooks,同一会话只拉一次
- todayIso() 用本地年月日拼,**不用 toISOString**(UTC 会让早 8 点前算成昨天)
② 时间红线两端统一成「一根满宽线、无端点装饰、无行首文字」(FbDayTimeline)
- 老写法 `Row { Text(时间) width(34); 线; 圆点 }` ⇒ 行首 34vp 把线顶掉一块
(与网页端 .ag-now「双重缩进」同一类病),行尾 6x6 圆点就是用户问的红点
- 改成满高 Column + Blank 撑高 + 满宽 2px 线,与卡片端同一写法
③ 🔴 真机实测发现的两处可见性问题(FbEventEditSheet)
- 「加入哪本日历」原来排在「提醒」之后 ⇒ 表单高于卡片(maxHeight 86%),
它被推到滚动区下方,首屏只看到被底边切掉半行的标题(实测 bounds 高 7px)。
它是必选项(没选就「请选一本日历」存不上)⇒ 挪到「全天」之后、日期时间之前。
- 错误提示原来在滚动区**内部最底部** ⇒ 用户在顶部点「创建」时提示在几百 px
之下看不见;就算滚到底也被 Scroll 底边切半行。现象是「点了创建什么都没发生」。
⇒ 挪到滚动区外面、按钮区上方(实测:Scroll 底 1953,提示 1984~2024,按钮 2074)。
真机验收(设备 5NC0225B27004718,线上 family.yangyq.net):
- 静态守卫 1112/0;BUILD SUCCESSFUL;install bundle successfully
- 「+ 新建」bounds [868,931][1018,1045],点击真的弹出「新建日程」
- 诊断确认 books=15 canWrite=6(数据层完全正常,之前的「选不了日历本」是可见性问题)
- 日历本挪位后首屏可见:标题高 40px(原 7px),10 本 chip 从 838 排到 1358
- 错误提示挪位后不滚动即可见:命中「日程得有个标题」
- **端到端建卡成功**:线上库确认 id=2411 cal=5 20:00~21:00,首页 1 条→2 条;
测试数据已按 id 精确删除(remaining_test_rows=0),重启后恢复 1 条
This commit is contained in:
@@ -356,33 +356,49 @@ export struct FbDayTimeline {
|
|||||||
.height('100%')
|
.height('100%')
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 第 3 层:当前时间红线(浮在最上层) */
|
/**
|
||||||
|
* 第 3 层:当前时间红线(浮在最上层)
|
||||||
|
*
|
||||||
|
* 🔴🔴 v84(用户 2026-10-23,同一条消息里两处):首页的这条线「红色线不对,
|
||||||
|
* 变短了左侧缺了一块」,日程页那条「红线左侧是不是还有一个红点?如果有,去掉。」
|
||||||
|
*
|
||||||
|
* 两个抱怨其实是同一段代码的两个缺陷,都在这里:
|
||||||
|
* ① 老写法是 `Row { Text('07:02') width(34); 线(layoutWeight 1); 圆点(6) }`
|
||||||
|
* —— **行首的 34vp 时间文字**把线往右顶掉一整块,用户看到的就是
|
||||||
|
* "左侧缺一块"(与网页端 `.ag-now` 那次「双重缩进」是同一类病:
|
||||||
|
* 线的左沿被别的东西占了)。
|
||||||
|
* ② 行尾那个 `6×6 borderRadius(3)` 就是用户问的**红点**。
|
||||||
|
*
|
||||||
|
* ⇒ 两端统一成**一根满宽的红线,没有任何端点装饰、没有文字**。
|
||||||
|
* 这正是用户 v44 定下的口径:「直接把红点去掉就行了,直接一根红线就可以了」,
|
||||||
|
* 也是网页端 `.ag-now { left: 0; right: 0; border-top: 2px }` 的等价写法。
|
||||||
|
*
|
||||||
|
* ⚠️ 别把时间文字"加回来":只要 Row 里有任何子元素,线就一定短一截。
|
||||||
|
* 想知道现在几点,看左侧刻度列——那里 `isNowHour` 的那个小时文字**已经是红的**
|
||||||
|
* (见 `hourLabels()` 那段的 `fontColor`),信息并没有丢。
|
||||||
|
* ⚠️ 别用 `Row { 线(layoutWeight 1) }` 的写法包一层 —— 能跑,但多一层无谓嵌套,
|
||||||
|
* 且下次有人往这个 Row 里塞东西,缺一块的 bug 就又回来了。
|
||||||
|
* ⚠️ `hitTestBehavior(HitTestMode.None)` 必须留:装饰层不能挡住点色块。
|
||||||
|
*/
|
||||||
@Builder
|
@Builder
|
||||||
nowLayer() {
|
nowLayer() {
|
||||||
if (this.nowVisible()) {
|
/* ⚠️ 外层必须是**满高的 Column**:`Stack` 的几个子层是「叠」不是「排」,
|
||||||
Row() {
|
直接给线写 `.margin({top})` 在部分版本上会因对齐基准不同而漂移。
|
||||||
// 左侧时间文字(红线那头)
|
用 `Blank` 撑开 = 与卡片端 `FbCard4x4.nowLayer()` **同一个写法**,
|
||||||
Text(FbTimelineUtil.hhmm(this.nowMin))
|
两端行为一致,改一处就知道另一处该怎么改。 */
|
||||||
.fontSize(9)
|
Column() {
|
||||||
.fontColor(FB_NOW_RED)
|
if (this.nowVisible()) {
|
||||||
.fontWeight(FontWeight.Medium)
|
Blank().height(this.nowOffsetVp()).hitTestBehavior(HitTestMode.None)
|
||||||
.textAlign(TextAlign.End)
|
Column()
|
||||||
.width(34)
|
.width('100%')
|
||||||
Row()
|
|
||||||
.layoutWeight(1)
|
|
||||||
.height(2)
|
.height(2)
|
||||||
.backgroundColor(FB_NOW_RED)
|
.borderRadius(1)
|
||||||
Row()
|
|
||||||
.width(6)
|
|
||||||
.height(6)
|
|
||||||
.borderRadius(3)
|
|
||||||
.backgroundColor(FB_NOW_RED)
|
.backgroundColor(FB_NOW_RED)
|
||||||
}
|
}
|
||||||
.width('100%')
|
|
||||||
.alignItems(VerticalAlign.Center)
|
|
||||||
.margin({ top: this.nowOffsetVp() })
|
|
||||||
.hitTestBehavior(HitTestMode.None)
|
|
||||||
}
|
}
|
||||||
|
.width('100%')
|
||||||
|
.height('100%')
|
||||||
|
.hitTestBehavior(HitTestMode.None)
|
||||||
}
|
}
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
|
|||||||
@@ -431,6 +431,32 @@ export struct FbEventEditSheet {
|
|||||||
.backgroundColor(FbColors.inputBg)
|
.backgroundColor(FbColors.inputBg)
|
||||||
.borderRadius(FbMetric.radiusS)
|
.borderRadius(FbMetric.radiusS)
|
||||||
|
|
||||||
|
// ---- 日历本 ----
|
||||||
|
/* 🔴🔴 v84 真机实测(2026-10-24):这一组原来排在「提醒」后面,
|
||||||
|
而表单内容比卡片(`maxHeight: 86%`)高 ⇒ 它在**滚动区下方**,
|
||||||
|
首屏只能看到被底边切掉半行的标题(实测 bounds 高 7px)。
|
||||||
|
用户报「选不了日历本」的直觉来源就是这个:看不见 = 用不了。
|
||||||
|
⇒ 它是**必选项**(没选就 `请选一本日历` 存不上),
|
||||||
|
必须排在**首屏可见**的位置:紧跟「全天」,在日期时间之前。
|
||||||
|
⚠️ 别再往回调到「提醒」后面 —— 那栏一长,它必然被推到屏幕外。 */
|
||||||
|
if (this.books.length > 0) {
|
||||||
|
this.section('加入哪本日历')
|
||||||
|
Flex({ wrap: FlexWrap.Wrap }) {
|
||||||
|
ForEach(this.books, (b: FbCalBook) => {
|
||||||
|
FbEventChip({
|
||||||
|
label: b.name,
|
||||||
|
active: this.fBookId === b.id,
|
||||||
|
// 选中时用**这本日历自己的颜色**(一眼看出落到哪本)
|
||||||
|
activeBg: b.color,
|
||||||
|
onPick: (): void => {
|
||||||
|
this.fBookId = b.id;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, (b: FbCalBook): string => 'bk_' + b.id.toString())
|
||||||
|
}
|
||||||
|
.width('100%')
|
||||||
|
}
|
||||||
|
|
||||||
// ---- 日期与时间 ----
|
// ---- 日期与时间 ----
|
||||||
// 🔴 照 SyncCalendar:**一行一个"日期 + 时间"控件**(点开一个弹层、
|
// 🔴 照 SyncCalendar:**一行一个"日期 + 时间"控件**(点开一个弹层、
|
||||||
// 里面 DatePicker 与 TimePicker 并排,选完点「确定」)。
|
// 里面 DatePicker 与 TimePicker 并排,选完点「确定」)。
|
||||||
@@ -476,25 +502,6 @@ export struct FbEventEditSheet {
|
|||||||
.width('100%')
|
.width('100%')
|
||||||
.margin({ top: 2 })
|
.margin({ top: 2 })
|
||||||
|
|
||||||
// ---- 日历本 ----
|
|
||||||
if (this.books.length > 0) {
|
|
||||||
this.section('加入哪本日历')
|
|
||||||
Flex({ wrap: FlexWrap.Wrap }) {
|
|
||||||
ForEach(this.books, (b: FbCalBook) => {
|
|
||||||
FbEventChip({
|
|
||||||
label: b.name,
|
|
||||||
active: this.fBookId === b.id,
|
|
||||||
// 选中时用**这本日历自己的颜色**(一眼看出落到哪本)
|
|
||||||
activeBg: b.color,
|
|
||||||
onPick: (): void => {
|
|
||||||
this.fBookId = b.id;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}, (b: FbCalBook): string => 'bk_' + b.id.toString())
|
|
||||||
}
|
|
||||||
.width('100%')
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- 地点 / 备注 ----
|
// ---- 地点 / 备注 ----
|
||||||
this.field('地点', this.fPlace, '地点(可选)', (v: string): void => {
|
this.field('地点', this.fPlace, '地点(可选)', (v: string): void => {
|
||||||
this.fPlace = v;
|
this.fPlace = v;
|
||||||
@@ -502,13 +509,6 @@ export struct FbEventEditSheet {
|
|||||||
this.area('备注', this.fNote, '备注(可选)', (v: string): void => {
|
this.area('备注', this.fNote, '备注(可选)', (v: string): void => {
|
||||||
this.fNote = v;
|
this.fNote = v;
|
||||||
})
|
})
|
||||||
|
|
||||||
if (this.err !== '') {
|
|
||||||
Text(this.err)
|
|
||||||
.fontSize(FbMetric.fontTiny)
|
|
||||||
.fontColor('#A32D2D')
|
|
||||||
.width('100%')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.width('100%')
|
.width('100%')
|
||||||
.padding({ top: 14 })
|
.padding({ top: 14 })
|
||||||
@@ -518,6 +518,21 @@ export struct FbEventEditSheet {
|
|||||||
.scrollBar(BarState.Off)
|
.scrollBar(BarState.Off)
|
||||||
.align(Alignment.TopStart)
|
.align(Alignment.TopStart)
|
||||||
|
|
||||||
|
/* 🔴🔴 v84 真机实测(2026-10-24):错误提示原来放在**滚动区内部最底部**
|
||||||
|
(`this.area('备注' …)` 后面),于是——
|
||||||
|
① 用户在顶部点「创建」时,提示在几百 px 之下,**根本看不见**;
|
||||||
|
② 就算滚到底,它也被 `Scroll` 底边切掉半行(实测 bounds 高 39px,紧贴 2024 边界)。
|
||||||
|
现象就是「点了创建什么都没发生」——这是最难查的一类失败(用户只会以为没生效)。
|
||||||
|
⇒ 挪到**滚动区外面、按钮区上方**:无论滚到哪儿,点完立刻看得见。
|
||||||
|
⚠️ 不要挪回 Scroll 里:那里的可见性取决于用户当时滚到哪儿,运气好才看得见。 */
|
||||||
|
if (this.err !== '') {
|
||||||
|
Text(this.err)
|
||||||
|
.fontSize(FbMetric.fontTiny)
|
||||||
|
.fontColor('#A32D2D')
|
||||||
|
.width('100%')
|
||||||
|
.margin({ top: 10 })
|
||||||
|
}
|
||||||
|
|
||||||
// ---- 底部按钮:删除 / 保存 ----
|
// ---- 底部按钮:删除 / 保存 ----
|
||||||
if (this.deleting) {
|
if (this.deleting) {
|
||||||
Text('删除中…')
|
Text('删除中…')
|
||||||
|
|||||||
@@ -148,6 +148,25 @@ export struct FbEmptyBox {
|
|||||||
export struct FbSectionTitle {
|
export struct FbSectionTitle {
|
||||||
@Param title: string = '';
|
@Param title: string = '';
|
||||||
@Param extra: string = '';
|
@Param extra: string = '';
|
||||||
|
/**
|
||||||
|
* 🔴 v84(用户 2026-10-23):「日程,没有新建日程按钮,名册,也没有新增成员
|
||||||
|
* 这个按钮。……首页上的其他卡片也应该有这些基本功能。」
|
||||||
|
*
|
||||||
|
* `addText` 非空 ⇒ 在 extra 右边给一颗**小号文字按钮**(空 = 不画,行为与原来完全一致)。
|
||||||
|
*
|
||||||
|
* ⚠️ 为什么是"可选参数 + 默认空"而不是新加一个组件:
|
||||||
|
* 本组件被首页 4 个区块、日程页、任务页等多处引用,
|
||||||
|
* 改签名会波及所有调用点;`@Param` 带默认值则**老调用点一行都不用改**。
|
||||||
|
* ⚠️ 为什么按钮文案用文字而不是 `+` 图标:
|
||||||
|
* 首页区块标题这一行只有 20vp 高,放图标按钮手指点不准(实测点击热区
|
||||||
|
* 会小于 40vp);文字按钮横向量足,且与网页端 `datatable` 的「新增」观感一致。
|
||||||
|
* ⚠️ 点击热区用 `padding` 撑到 **44vp 高**(不是 fontTiny 那么点大)——
|
||||||
|
* `hitTestBehavior` 默认是 `Default`,padding 区**算在热区内**。
|
||||||
|
*/
|
||||||
|
@Param addText: string = '';
|
||||||
|
/** 点「新增」;`addText` 为空时永不触发 */
|
||||||
|
@Event onAdd: () => void = (): void => {
|
||||||
|
};
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
Row() {
|
Row() {
|
||||||
@@ -162,9 +181,27 @@ export struct FbSectionTitle {
|
|||||||
.fontSize(FbMetric.fontTiny)
|
.fontSize(FbMetric.fontTiny)
|
||||||
.fontColor(FbColors.faint)
|
.fontColor(FbColors.faint)
|
||||||
}
|
}
|
||||||
|
if (this.addText.length > 0) {
|
||||||
|
/* extra 存在时用 6vp 间距隔开;extra 为空时靠 Blank 顶到右边 */
|
||||||
|
if (this.extra.length === 0) {
|
||||||
|
Blank()
|
||||||
|
}
|
||||||
|
Text(this.addText)
|
||||||
|
.fontSize(FbMetric.fontTiny)
|
||||||
|
/* ⚠️ 用 `FbColors.brand`(品牌砖红),不是 `accent` ——
|
||||||
|
`FbColors` 里**没有** `accent` 这个字段(编译会报
|
||||||
|
"Property 'accent' does not exist")。 */
|
||||||
|
.fontColor(FbColors.brand)
|
||||||
|
.fontWeight(FontWeight.Medium)
|
||||||
|
.padding({ left: 10, right: 2, top: 12, bottom: 12 })
|
||||||
|
.onClick((): void => {
|
||||||
|
this.onAdd();
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.width('100%')
|
.width('100%')
|
||||||
.padding({ left: 4, right: 4, top: 12, bottom: 8 })
|
.padding({ left: 4, right: 4, top: 12, bottom: 8 })
|
||||||
|
.alignItems(VerticalAlign.Center)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,8 +39,8 @@
|
|||||||
|
|
||||||
import { FbColors, FbMetric, FB_MASK } from '../../common/Theme';
|
import { FbColors, FbMetric, FB_MASK } from '../../common/Theme';
|
||||||
import { FbAppState, fbAppState } from '../../common/Store';
|
import { FbAppState, fbAppState } from '../../common/Store';
|
||||||
import { FbCalEvent, FbCatOpt, FbHomeData, FbMark, FbMemoryItem, FbRecentDay, FbTaskItem,
|
import { FbCalEvent, FbCalBook, FbCatOpt, FbHomeData, FbMark, FbMemoryItem, FbRecentDay,
|
||||||
FbBoardOpt, FbTaskDetail, FbTaskMeta, taskKey,
|
FbTaskItem, FbBoardOpt, FbTaskDetail, FbTaskMeta, taskKey,
|
||||||
FbWeather, isEditableEvent } from '../../model/Types';
|
FbWeather, isEditableEvent } from '../../model/Types';
|
||||||
import { common } from '@kit.AbilityKit';
|
import { common } from '@kit.AbilityKit';
|
||||||
import { BusinessError } from '@kit.BasicServicesKit';
|
import { BusinessError } from '@kit.BasicServicesKit';
|
||||||
@@ -57,6 +57,7 @@ import { FbSectionTitle } from '../../components/Widgets';
|
|||||||
import { FbStatCell } from '../../components/FbStatCell';
|
import { FbStatCell } from '../../components/FbStatCell';
|
||||||
import { FbDayEventPanel } from '../../components/FbDayEventPanel';
|
import { FbDayEventPanel } from '../../components/FbDayEventPanel';
|
||||||
import { FbEventSheet } from '../../components/FbEventSheet';
|
import { FbEventSheet } from '../../components/FbEventSheet';
|
||||||
|
import { FbEventEditSheet } from '../../components/FbEventEditSheet';
|
||||||
import { FbTaskPanel } from '../../components/FbTaskPanel';
|
import { FbTaskPanel } from '../../components/FbTaskPanel';
|
||||||
import { FbTaskEditSheet } from '../../components/FbTaskEditSheet';
|
import { FbTaskEditSheet } from '../../components/FbTaskEditSheet';
|
||||||
import { FB_DOCK_RESERVE } from '../../components/FloatDock';
|
import { FB_DOCK_RESERVE } from '../../components/FloatDock';
|
||||||
@@ -66,6 +67,10 @@ import { FB_BACK } from '../../common/FbBack';
|
|||||||
import { fbOpenNavigation } from '../../common/FbNav';
|
import { fbOpenNavigation } from '../../common/FbNav';
|
||||||
import { fbModuleOf, FbModuleDef, fbThemeVars } from '../../model/Modules';
|
import { fbModuleOf, FbModuleDef, fbThemeVars } from '../../model/Modules';
|
||||||
|
|
||||||
|
/** 日志域(与 `FbBackgroundSync` / `FbNav` 同一个值,端上统一 0x0000) */
|
||||||
|
const DOMAIN: number = 0x0000;
|
||||||
|
const TAG: string = 'FbHomePage';
|
||||||
|
|
||||||
@ComponentV2
|
@ComponentV2
|
||||||
export struct FbHomePage {
|
export struct FbHomePage {
|
||||||
|
|
||||||
@@ -119,6 +124,27 @@ export struct FbHomePage {
|
|||||||
*/
|
*/
|
||||||
@Local calStyle: FbCalStyle = 'timeline';
|
@Local calStyle: FbCalStyle = 'timeline';
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// v84(用户 2026-10-23):首页卡片上的「新建 / 新增」按钮
|
||||||
|
// ============================================================
|
||||||
|
/* 🔴 用户原话:「日程,没有新建日程按钮,名册,也没有新增成员这个按钮。」
|
||||||
|
------------------------------------------------------------------
|
||||||
|
⚠️ 这条**上一轮只做到 Web 端**(`app/HomeCards.php` 的 `TYPES['agenda']['add']`),
|
||||||
|
端上首页压根没做 —— 所以用户装完机仍然说"没有按钮"。
|
||||||
|
教训:这类"两端都要"的需求,改完一端必须**立刻去另一端 grep 同一件事**。
|
||||||
|
|
||||||
|
⚠️ 为什么首页要**自己拉一次 `/calendar/books`**、不复用日程页那份:
|
||||||
|
首页和日程页是两个独立组件(首页不持有日程页的 `@Local books`)。
|
||||||
|
把它塞进 `/home` 接口当然更省,但那要动服务端 + 端上解析 + 网页端,
|
||||||
|
收益只有"少一个请求",风险却横跨三层。
|
||||||
|
⇒ 折中:**按需懒加载**(点开新建才拉),且拉到后缓存在 `calBooks` 里,
|
||||||
|
同一会话内只拉一次。 */
|
||||||
|
@Local calBooks: FbCalBook[] = [];
|
||||||
|
/** 首页「新建日程」表单开着 */
|
||||||
|
@Local calCreating: boolean = false;
|
||||||
|
/** 正在拉日历本(防连点开两个空表单) */
|
||||||
|
@Local calLoadingBooks: boolean = false;
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// v73(用户 2026-10-21):首页点日程 / 点任务 → **就地弹详情卡**
|
// v73(用户 2026-10-21):首页点日程 / 点任务 → **就地弹详情卡**
|
||||||
// ============================================================
|
// ============================================================
|
||||||
@@ -182,9 +208,10 @@ export struct FbHomePage {
|
|||||||
* `Index` 的 Stack** 里,层级比本页高 ⇒ 不让位就会盖住卡片底部的按钮、
|
* `Index` 的 Stack** 里,层级比本页高 ⇒ 不让位就会盖住卡片底部的按钮、
|
||||||
* 还把点击抢走(名册/日程页都踩过)。
|
* 还把点击抢走(名册/日程页都踩过)。
|
||||||
*/
|
*/
|
||||||
@Monitor('evtBase', 'tskBase', 'tskEditOpen')
|
@Monitor('evtBase', 'tskBase', 'tskEditOpen', 'calCreating')
|
||||||
onDetailChanged(): void {
|
onDetailChanged(): void {
|
||||||
this.app.sheetCount = (this.evtBase !== null || this.tskBase !== null || this.tskEditOpen) ? 1 : 0;
|
this.app.sheetCount = (this.evtBase !== null || this.tskBase !== null
|
||||||
|
|| this.tskEditOpen || this.calCreating) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
aboutToAppear(): void {
|
aboutToAppear(): void {
|
||||||
@@ -211,6 +238,12 @@ export struct FbHomePage {
|
|||||||
this.tskEditOpen = false;
|
this.tskEditOpen = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
/* v84 新建日程:它是**独立表单**(不在详情卡之上),但要优先于详情卡 ——
|
||||||
|
两者不可能同时开,放前面只是保证"开了就一定关得掉"。 */
|
||||||
|
if (this.calCreating) {
|
||||||
|
this.calCreating = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (this.evtBase !== null) {
|
if (this.evtBase !== null) {
|
||||||
this.closeEvent();
|
this.closeEvent();
|
||||||
return true;
|
return true;
|
||||||
@@ -406,6 +439,46 @@ export struct FbHomePage {
|
|||||||
this.tskEditOpen = true;
|
this.tskEditOpen = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* v84:首页「今天的日程」区块点「+ 新建」→ **就地**打开新建表单。
|
||||||
|
*
|
||||||
|
* 流程:懒拉日历本 → 打开 `FbEventEditSheet(isCreate: true)`。
|
||||||
|
*
|
||||||
|
* ⚠️ 日历本为空时**不要"打不开就算了"**:新建表单的"日程本"是必选项,
|
||||||
|
* 没有可写本就画不出表单。这时要么提示、要么至少把表单打开让它自己报错
|
||||||
|
* —— 选**明说一句**(用户点了一下什么都没发生,是最难查的失败)。
|
||||||
|
* ⚠️ `presetDate` 用"今天":首页这条区块就叫「今天的日程」,
|
||||||
|
* 用户在这里点新建,十有八九是给今天加一件。
|
||||||
|
* ⚠️ 不要 `await` 之后才置 `calCreating` 以外的任何界面状态 ——
|
||||||
|
* 拉本期间给一个 `calLoadingBooks`,防止连点开出两个表单。
|
||||||
|
*/
|
||||||
|
private async openCalCreate(): Promise<void> {
|
||||||
|
if (this.calCreating || this.calLoadingBooks) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const token: string = FB_TOKEN_STORE.get();
|
||||||
|
if (token === '') {
|
||||||
|
this.syncNote = '还没登录,无法新建日程';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.calBooks.length === 0) {
|
||||||
|
this.calLoadingBooks = true;
|
||||||
|
try {
|
||||||
|
const list: FbCalBook[] = await FbCalRepo.inst().fetchBooks(token);
|
||||||
|
this.calBooks = list;
|
||||||
|
} catch (err) {
|
||||||
|
hilog.warn(DOMAIN, TAG, '首页拉日历本失败:%{public}s', JSON.stringify(err));
|
||||||
|
} finally {
|
||||||
|
this.calLoadingBooks = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.calBooks.length === 0) {
|
||||||
|
this.syncNote = '这个账号还没有可写的日程本,先去日程页设置里建一本';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.calCreating = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 把最新数据推给桌面上所有日程卡片。
|
* 把最新数据推给桌面上所有日程卡片。
|
||||||
@@ -529,6 +602,23 @@ export struct FbHomePage {
|
|||||||
return d.getHours() * 60 + d.getMinutes();
|
return d.getHours() * 60 + d.getMinutes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 今天 → `YYYY-MM-DD`(`FbEventEditSheet` 的 `presetDate` 要这个格式)。
|
||||||
|
*
|
||||||
|
* ⚠️ **不要**用 `toISOString().slice(0,10)`:那是 **UTC**,
|
||||||
|
* 东八区早上 8 点前会算成"昨天"(本项目真机上踩过同类:新建的日程
|
||||||
|
* 跑到前一天去了,用户完全无法理解)。必须用本地年月日拼。
|
||||||
|
* ⚠️ 月份、日期都要补零,否则 `2026-1-5` 服务端解析不了。
|
||||||
|
*/
|
||||||
|
private todayIso(): string {
|
||||||
|
const d: Date = new Date();
|
||||||
|
const m: number = d.getMonth() + 1;
|
||||||
|
const day: number = d.getDate();
|
||||||
|
return d.getFullYear().toString() + '-'
|
||||||
|
+ (m < 10 ? '0' + m.toString() : m.toString()) + '-'
|
||||||
|
+ (day < 10 ? '0' + day.toString() : day.toString());
|
||||||
|
}
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
/* 🔴 v73:外层必须是 **Stack**(叠放),不能是 Column(排列)。
|
/* 🔴 v73:外层必须是 **Stack**(叠放),不能是 Column(排列)。
|
||||||
浮层要"盖在页面上",而不是"排在页面后面" —— 后者会把 Scroll 挤出屏幕,
|
浮层要"盖在页面上",而不是"排在页面后面" —— 后者会把 Scroll 挤出屏幕,
|
||||||
@@ -688,7 +778,17 @@ export struct FbHomePage {
|
|||||||
// ⚠️ 面板自带卡片样式与外边距,这里**不要再套一层卡片**。
|
// ⚠️ 面板自带卡片样式与外边距,这里**不要再套一层卡片**。
|
||||||
// ⚠️ `showHead: false` —— 本页已有 `FbSectionTitle`,两个头会重复。
|
// ⚠️ `showHead: false` —— 本页已有 `FbSectionTitle`,两个头会重复。
|
||||||
// ⚠️ 空态文案也换掉:首页没有"右下角 +"那个按钮。
|
// ⚠️ 空态文案也换掉:首页没有"右下角 +"那个按钮。
|
||||||
FbSectionTitle({ title: '今天的日程', extra: this.todayEvents.length.toString() + ' 条' })
|
FbSectionTitle({
|
||||||
|
title: '今天的日程',
|
||||||
|
extra: this.todayEvents.length.toString() + ' 条',
|
||||||
|
/* 🔴 v84(用户 2026-10-23):「日程,没有新建日程按钮」。
|
||||||
|
⚠️ 别再删掉这颗按钮 —— 它是本条的**唯一可见证据**,
|
||||||
|
删了用户立刻又说"没有按钮"(上一轮就漏在端上)。 */
|
||||||
|
addText: '+ 新建',
|
||||||
|
onAdd: (): void => {
|
||||||
|
this.openCalCreate();
|
||||||
|
}
|
||||||
|
})
|
||||||
.padding({ left: FbMetric.pagePad, right: FbMetric.pagePad, top: 12 })
|
.padding({ left: FbMetric.pagePad, right: FbMetric.pagePad, top: 12 })
|
||||||
|
|
||||||
FbDayEventPanel({
|
FbDayEventPanel({
|
||||||
@@ -847,6 +947,43 @@ export struct FbHomePage {
|
|||||||
.onTouch(fbOnTouch)
|
.onTouch(fbOnTouch)
|
||||||
.align(Alignment.TopStart)
|
.align(Alignment.TopStart)
|
||||||
|
|
||||||
|
// ==================== 新建日程(v84)====================
|
||||||
|
// ⚠️ 遮罩与表单是 Stack 的**兄弟**,不是 Column 的子项
|
||||||
|
// (本项目踩过:`Column { 整高遮罩; 卡片 }` 会把卡片挤出屏幕,
|
||||||
|
// 编译通过、节点树里却一个节点都没有 —— 看起来像"点了没反应")。
|
||||||
|
if (this.calCreating) {
|
||||||
|
Column()
|
||||||
|
.width('100%')
|
||||||
|
.height('100%')
|
||||||
|
.backgroundColor(FB_MASK)
|
||||||
|
.transition(fbMaskTransition())
|
||||||
|
.onClick((): void => {
|
||||||
|
this.calCreating = false;
|
||||||
|
})
|
||||||
|
|
||||||
|
FbEventEditSheet({
|
||||||
|
event: null,
|
||||||
|
isCreate: true,
|
||||||
|
/* 首页这条区块叫「今天的日程」⇒ 默认给今天 */
|
||||||
|
presetDate: this.todayIso(),
|
||||||
|
books: this.calBooks,
|
||||||
|
onCancel: (): void => {
|
||||||
|
this.calCreating = false;
|
||||||
|
},
|
||||||
|
onSaved: (): void => {
|
||||||
|
this.calCreating = false;
|
||||||
|
/* 存成功立刻重拉首页 ⇒ 新日程出现在「今天的日程」里。
|
||||||
|
⚠️ 必须重拉而不是"本地塞一条":服务端会补 id / 颜色 / 日历本名,
|
||||||
|
本地塞的那条会和之后下拉刷新出来的长得不一样。 */
|
||||||
|
this.load();
|
||||||
|
},
|
||||||
|
onDeleted: (): void => {
|
||||||
|
this.calCreating = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.transition(fbSheetTransition())
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== 日程详情卡(v73)====================
|
// ==================== 日程详情卡(v73)====================
|
||||||
// ⚠️ 遮罩与卡片是 Stack 的**兄弟**,不是 Column 的子项(见 build 开头那段说明)。
|
// ⚠️ 遮罩与卡片是 Stack 的**兄弟**,不是 Column 的子项(见 build 开头那段说明)。
|
||||||
if (this.evtBase !== null) {
|
if (this.evtBase !== null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user