纪念日:生日改成只读卡、自建纪念日才可编辑 (#87)
用户 2026-11-05 四条:
1.「如果这个纪念日来自生日,我们是不能编辑的。」
2.「点击之后,像日程那样弹出一个框来显示就行:显示这个人的头像、姓名,
以及生日的『日』和日期就可以了。」
3.「如果是我们自己创建的纪念日,那么这里面就是编辑纪念日。」
4.「这个框和刚才我们编辑任务的框是一样的做法。样式、格式全部都一样。」
🔴 先说一个**会改坏用户数据的 bug**(这次一并修掉):
原来派生生日也走 FbDayEditSheet,而且传的是
editingMonth: 1, editingDay: 1 ← 写死的 1 月 1 日
结果点开任何一个生日都显示「1 月 1 日」,点保存还能把
**成员档案里的真实生日覆盖成 1 月 1 日**。
这不是样式问题,是数据损坏。
改动:
① 新增 components/FbDayBirthdaySheet.ets(派生生日的只读卡)
· 外壳用 FbSheetRing + 遮罩点击关闭 + 右上角 FbSheetClose
—— 与 FbTaskPanel / FbDayEditSheet 同一套版式(用户第 4 条)
· 左上角「生日 / 农历生日」主题色粗体 + 一行小字
「来自成员资料,不能在这里修改」——把"不能编辑"这条边界写明白,
否则用户会以为卡片坏了(用户第 1 条)
· 主体:FbAvatar(56) + 姓名(主题色粗体) + 完整日期
· 「日」做成视觉焦点:84×84 浅主题色块里放 34 号大字数字 + 「11 月」
· 右侧:还有几天 / 满 N 周岁 / 农历说明
· 底部:「要修改生日,请到「家人」里打开这位成员的资料」
—— 只读也要给出口,不然用户不知道去哪儿改
② FbHomePage 按 source 分发
birthday_solar / birthday_lunar → FbDayBirthdaySheet(只读)
custom → FbDayEditSheet(可编辑,原行为)
⚠️ 判据用 source 前缀而不是 id === 0:两者目前等价,但 source 是语义、
id 是实现细节 —— 万一以后派生条目也带 id,用 id 判会静默错。
③ 服务端 Anniversary::occurrences() 补输出
· person_name —— `birthdays()` 算出来了,但 occurrences 逐个字段挑着抄时漏了
· avatar / avatar_color —— 只读卡要画头像(key,端上拼 URL)
· day / month —— 用户要的「生日的『日』」
⚠️ 用 $a['day'] 而不是从 $date 截:农历生日的 day 是农历日
(初五 = 5),date 是换算后的公历日 —— 两者不同,用户要看"生日那天"
· birthdays() 同步补 avatar / avatar_color(它原来也没有)
④ Types / FbParse 补五个字段
personName / avatar / avatarColor / day / month
编译通过,已装真机。
This commit is contained in:
@@ -0,0 +1,288 @@
|
|||||||
|
/**
|
||||||
|
* 家书 FamilyBook · 「生日」只读卡(鸿蒙端)
|
||||||
|
*
|
||||||
|
* 🔴🔴 #87(用户 2026-11-05)四条:
|
||||||
|
* 1.「如果这个纪念日来自生日,我们是不能编辑的。」
|
||||||
|
* 2.「点击之后,像日程那样弹出一个框来显示就行:显示这个人的头像、姓名,
|
||||||
|
* 以及生日的『日』和日期就可以了。」
|
||||||
|
* 3.「如果是我们自己创建的纪念日,那么这里面就是编辑纪念日。」
|
||||||
|
* 4.「这个框和刚才我们编辑任务的框是一样的做法。样式、格式全部都一样。」
|
||||||
|
*
|
||||||
|
* ⇒ 本组件只负责 **第 1、2 条**(派生生日的只读卡)。
|
||||||
|
* 第 3 条(自建纪念日)仍走 `FbDayEditSheet`,由 `FbHomePage.openDayDetail()` 分发。
|
||||||
|
* 第 4 条 = 外壳用 `FbSheetRing` + 遮罩点击关闭 + 右上角关闭按钮,
|
||||||
|
* 与 `FbTaskPanel` / `FbDayEditSheet` 同一套版式。
|
||||||
|
*
|
||||||
|
* ⚠️ **为什么不做成"编辑表单禁用输入"**:
|
||||||
|
* 派生生日的日期来自 `persons.birthday`,改它等于改这个人的人事档案 ——
|
||||||
|
* 那件事该去「成员资料」里做,不该在纪念日卡片里顺手改。
|
||||||
|
* 做成"只读卡"把这条边界表达清楚,比"表单全灰"更不容易让人误会。
|
||||||
|
* ⚠️ **为什么不用 `FbDayEditSheet` 传空数据**:
|
||||||
|
* 之前的实现就是这样 —— 而且 `editingMonth: 1, editingDay: 1`(写死 1 月 1 日),
|
||||||
|
* 结果点开任何一个生日都显示"1 月 1 日",还能点保存把真实生日覆盖掉。
|
||||||
|
* 这是个会**改坏用户数据**的 bug,不是样式问题。
|
||||||
|
*
|
||||||
|
* ⚠️ 农历生日的「日」用的是**农历日**(`day` 字段),不是公历日期里截的那一位:
|
||||||
|
* 农历十月初五要显示「初五/5」,而 `date` 是换算出来的公历日 —— 两者不同。
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { FbColors, FbMetric, FB_MASK, fbMixWhite } from '../common/Theme';
|
||||||
|
import { FbSheetRing } from './FbSheetRing';
|
||||||
|
import { FbSheetClose } from './FbSheetClose';
|
||||||
|
import { FbAvatar } from './Widgets';
|
||||||
|
import { FbRecentDay } from '../model/Types';
|
||||||
|
import { fbImageSrc } from '../data/FbAttachQueue';
|
||||||
|
import { FB_TOKEN_STORE } from '../data/FbTokenStore';
|
||||||
|
|
||||||
|
@ComponentV2
|
||||||
|
export struct FbDayBirthdaySheet {
|
||||||
|
/** 这条纪念日(必须是派生生日:source 以 `birthday` 开头) */
|
||||||
|
@Param item: FbRecentDay | null = null;
|
||||||
|
/** 模块主题色(纪念日 = 暖橙) */
|
||||||
|
@Param accent: string = '#C2703E';
|
||||||
|
|
||||||
|
@Event onClose: () => void = (): void => {
|
||||||
|
};
|
||||||
|
|
||||||
|
private token(): string {
|
||||||
|
return FB_TOKEN_STORE.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 头像 URL。
|
||||||
|
* ⚠️ `avatar` 是 key(`avatars/xxx.jpg`),要经 `fbImageSrc` 拼成可加载地址;
|
||||||
|
* 空 key 返回空串 → `FbAvatar` 自动退回首字色块。
|
||||||
|
*/
|
||||||
|
private avatarSrc(): string {
|
||||||
|
const d: FbRecentDay | null = this.item;
|
||||||
|
if (d === null || d.avatar === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return fbImageSrc(d.avatar, this.token());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 显示名:优先 `personName`,退回从标题里去掉「的生日」后缀 */
|
||||||
|
private nameOf(): string {
|
||||||
|
const d: FbRecentDay | null = this.item;
|
||||||
|
if (d === null) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (d.personName !== '') {
|
||||||
|
return d.personName;
|
||||||
|
}
|
||||||
|
/* 兜底:标题形如「老杨 的生日」「老杨 的农历生日」,切掉后缀 */
|
||||||
|
const cut: number = d.title.indexOf(' 的');
|
||||||
|
return cut > 0 ? d.title.substring(0, cut) : d.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生日是「几号」—— 卡片正中的那个大数字。
|
||||||
|
*
|
||||||
|
* ⚠️ 优先用 `day`(用户填的那一天);为 0 才从 `date` 里截。
|
||||||
|
* 农历生日的 `day` 是农历日,与 `date` 的公历日**不一样**,
|
||||||
|
* 用户要看的是"生日那天"。
|
||||||
|
*/
|
||||||
|
private dayNum(): string {
|
||||||
|
const d: FbRecentDay | null = this.item;
|
||||||
|
if (d === null) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (d.day > 0) {
|
||||||
|
return d.day.toString();
|
||||||
|
}
|
||||||
|
const dd: number = d.date.length >= 10 ? parseInt(d.date.substring(8, 10), 10) : 0;
|
||||||
|
return dd > 0 ? dd.toString() : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 「11 月」—— 与「几号」配成「11 月 16 日」的读法 */
|
||||||
|
private monthWord(): string {
|
||||||
|
const d: FbRecentDay | null = this.item;
|
||||||
|
if (d === null) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (d.month > 0) {
|
||||||
|
return d.month.toString() + ' 月';
|
||||||
|
}
|
||||||
|
const mm: number = d.date.length >= 7 ? parseInt(d.date.substring(5, 7), 10) : 0;
|
||||||
|
return mm > 0 ? mm.toString() + ' 月' : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 完整日期 `2026 年 11 月 16 日`(下一次发生的公历日期) */
|
||||||
|
private dateLine(): string {
|
||||||
|
const d: FbRecentDay | null = this.item;
|
||||||
|
if (d === null || d.date.length < 10) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const y: number = parseInt(d.date.substring(0, 4), 10);
|
||||||
|
const m: number = parseInt(d.date.substring(5, 7), 10);
|
||||||
|
const dd: number = parseInt(d.date.substring(8, 10), 10);
|
||||||
|
return y.toString() + ' 年 ' + m.toString() + ' 月 ' + dd.toString() + ' 日';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 「还有 12 天」/「就是今天」 */
|
||||||
|
private daysWord(): string {
|
||||||
|
const d: FbRecentDay | null = this.item;
|
||||||
|
if (d === null) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (d.days === 0) {
|
||||||
|
return '就是今天';
|
||||||
|
}
|
||||||
|
return '还有 ' + d.days.toString() + ' 天';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 是农历生日吗(决定副标题写「农历生日」还是「生日」) */
|
||||||
|
private isLunar(): boolean {
|
||||||
|
const d: FbRecentDay | null = this.item;
|
||||||
|
return d !== null && d.source === 'birthday_lunar';
|
||||||
|
}
|
||||||
|
|
||||||
|
build() {
|
||||||
|
/* 根必须 Stack:全屏遮罩与卡片要**叠**(与 FbTaskPanel 同一条约定) */
|
||||||
|
Stack({ alignContent: Alignment.Center }) {
|
||||||
|
Column()
|
||||||
|
.width('100%')
|
||||||
|
.height('100%')
|
||||||
|
.backgroundColor(FB_MASK)
|
||||||
|
.onClick((): void => {
|
||||||
|
this.onClose();
|
||||||
|
})
|
||||||
|
|
||||||
|
Column() {
|
||||||
|
FbSheetRing({ radius: FbMetric.radius, ringColor: this.accent }) {
|
||||||
|
Column({ space: 0 }) {
|
||||||
|
/* ---- 顶栏:标题 + 关闭 ---- */
|
||||||
|
/* 与 FbTaskPanel.headBar 同一版式:
|
||||||
|
左上角「XX」主题色粗体 + 右上角关闭。
|
||||||
|
用户第 4 条要求"这个框和编辑任务的框一样的做法"。 */
|
||||||
|
Row({ space: 10 }) {
|
||||||
|
Column({ space: 2 }) {
|
||||||
|
Text(this.isLunar() ? '农历生日' : '生日')
|
||||||
|
.fontSize(FbMetric.fontBody)
|
||||||
|
.fontWeight(FontWeight.Bold)
|
||||||
|
.fontColor(this.accent)
|
||||||
|
/* ⚠️ 明确写出"来自成员资料,不能在这里改" ——
|
||||||
|
用户第 1 条要的就是这个边界,不写清楚他会以为是卡坏了。 */
|
||||||
|
Text('来自成员资料,不能在这里修改')
|
||||||
|
.fontSize(FbMetric.fontTiny)
|
||||||
|
.fontColor(FbColors.faint)
|
||||||
|
}
|
||||||
|
.alignItems(HorizontalAlign.Start)
|
||||||
|
.layoutWeight(1)
|
||||||
|
.flexShrink(1)
|
||||||
|
|
||||||
|
FbSheetClose({
|
||||||
|
onClose: (): void => {
|
||||||
|
this.onClose();
|
||||||
|
},
|
||||||
|
color: ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
.width('100%')
|
||||||
|
.alignItems(VerticalAlign.Center)
|
||||||
|
|
||||||
|
Divider()
|
||||||
|
.color(FbColors.line)
|
||||||
|
.margin({ top: 12, bottom: 16 })
|
||||||
|
|
||||||
|
/* ---- 主角:头像 + 姓名 + 「日」 ---- */
|
||||||
|
Row({ space: 14 }) {
|
||||||
|
FbAvatar({
|
||||||
|
name: this.nameOf(),
|
||||||
|
color: this.item !== null ? this.item.avatarColor : '',
|
||||||
|
imageUrl: this.avatarSrc(),
|
||||||
|
dia: 56,
|
||||||
|
fontSizeVp: 22
|
||||||
|
})
|
||||||
|
|
||||||
|
Column({ space: 4 }) {
|
||||||
|
Text(this.nameOf())
|
||||||
|
.fontSize(FbMetric.fontTitle)
|
||||||
|
.fontWeight(FontWeight.Bold)
|
||||||
|
.fontColor(FbColors.ink)
|
||||||
|
.maxLines(2)
|
||||||
|
.width('100%')
|
||||||
|
Text(this.dateLine())
|
||||||
|
.fontSize(FbMetric.fontSmall)
|
||||||
|
.fontColor(FbColors.muted)
|
||||||
|
.width('100%')
|
||||||
|
}
|
||||||
|
.alignItems(HorizontalAlign.Start)
|
||||||
|
.layoutWeight(1)
|
||||||
|
.flexShrink(1)
|
||||||
|
}
|
||||||
|
.width('100%')
|
||||||
|
.padding({ top: 4, bottom: 18 })
|
||||||
|
.alignItems(VerticalAlign.Center)
|
||||||
|
|
||||||
|
/* ---- 「几号」大字块 + 剩余天数 ---- */
|
||||||
|
/* 用户第 2 条:「显示…生日的『日』和日期就可以了」
|
||||||
|
⇒ 把「日」做成一个视觉焦点(大数字),日期在下面一行小字。
|
||||||
|
底色用浅一档主题色(fbMixWhite 0.91),与下拉框/胶囊同一套。 */
|
||||||
|
Row({ space: 12 }) {
|
||||||
|
Column({ space: 0 }) {
|
||||||
|
Text(this.dayNum())
|
||||||
|
.fontSize(34)
|
||||||
|
.fontWeight(FontWeight.Bold)
|
||||||
|
.fontColor(this.accent)
|
||||||
|
Text(this.monthWord())
|
||||||
|
.fontSize(FbMetric.fontTiny)
|
||||||
|
.fontColor(fbMixWhite(this.accent, 0.35))
|
||||||
|
}
|
||||||
|
.width(84)
|
||||||
|
.height(84)
|
||||||
|
.justifyContent(FlexAlign.Center)
|
||||||
|
.backgroundColor(fbMixWhite(this.accent, 0.91))
|
||||||
|
.borderRadius(FbMetric.radiusS)
|
||||||
|
|
||||||
|
Column({ space: 6 }) {
|
||||||
|
Text(this.daysWord())
|
||||||
|
.fontSize(FbMetric.fontSmall)
|
||||||
|
.fontWeight(FontWeight.Medium)
|
||||||
|
.fontColor(this.accent)
|
||||||
|
if (this.item !== null && this.item.age >= 0) {
|
||||||
|
Text('满 ' + this.item.age.toString() + ' 周岁')
|
||||||
|
.fontSize(FbMetric.fontTiny)
|
||||||
|
.fontColor(FbColors.muted)
|
||||||
|
}
|
||||||
|
if (this.isLunar()) {
|
||||||
|
/* 农历生日时「日」是农历日,与上面的公历日期不同 ——
|
||||||
|
不说明一句用户会以为"日子算错了"。 */
|
||||||
|
Text('农历日期,每年按农历换算')
|
||||||
|
.fontSize(FbMetric.fontTiny)
|
||||||
|
.fontColor(FbColors.faint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.alignItems(HorizontalAlign.Start)
|
||||||
|
.layoutWeight(1)
|
||||||
|
.flexShrink(1)
|
||||||
|
}
|
||||||
|
.width('100%')
|
||||||
|
.alignItems(VerticalAlign.Center)
|
||||||
|
|
||||||
|
/* ---- 底部:去成员资料改 ---- */
|
||||||
|
/* 用户第 1 条:「不能编辑」⇒ 不给编辑按钮,但**要给出口**:
|
||||||
|
想去改生日的人得知道该去哪儿,否则只会觉得"这卡不好用"。 */
|
||||||
|
Text('要修改生日,请到「家人」里打开这位成员的资料')
|
||||||
|
.fontSize(FbMetric.fontTiny)
|
||||||
|
.fontColor(FbColors.faint)
|
||||||
|
.width('100%')
|
||||||
|
.textAlign(TextAlign.Center)
|
||||||
|
.margin({ top: 20 })
|
||||||
|
}
|
||||||
|
.width('100%')
|
||||||
|
.padding({ left: 18, right: 18, top: 16, bottom: 18 })
|
||||||
|
.alignItems(HorizontalAlign.Start)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.width('90%')
|
||||||
|
.constraintSize({ maxHeight: '70%' })
|
||||||
|
.onClick((): void => {
|
||||||
|
/* 吃掉点击,避免穿透到底下的遮罩把自己关了 */
|
||||||
|
})
|
||||||
|
}
|
||||||
|
.width('100%')
|
||||||
|
.height('100%')
|
||||||
|
.hitTestBehavior(HitTestMode.Transparent)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -184,6 +184,9 @@ interface RawRecentDay {
|
|||||||
id?: number; date?: string; title?: string; kind?: string;
|
id?: number; date?: string; title?: string; kind?: string;
|
||||||
person_id?: number; source?: string; days?: number;
|
person_id?: number; source?: string; days?: number;
|
||||||
age?: number | null; nth?: number | null;
|
age?: number | null; nth?: number | null;
|
||||||
|
/* #87:生日只读卡要用(服务端 Anniversary::occurrences 已输出) */
|
||||||
|
person_name?: string | null; avatar?: string | null; avatar_color?: string | null;
|
||||||
|
day?: number | null; month?: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RawTaskBoard {
|
interface RawTaskBoard {
|
||||||
@@ -913,6 +916,11 @@ export function parseRecentDays(v: Object | null | undefined): FbRecentDay[] {
|
|||||||
days: n(r.days),
|
days: n(r.days),
|
||||||
age: r.age !== null && r.age !== undefined ? n(r.age) : -1,
|
age: r.age !== null && r.age !== undefined ? n(r.age) : -1,
|
||||||
nth: r.nth !== null && r.nth !== undefined ? n(r.nth) : -1,
|
nth: r.nth !== null && r.nth !== undefined ? n(r.nth) : -1,
|
||||||
|
personName: s(r.person_name),
|
||||||
|
avatar: s(r.avatar),
|
||||||
|
avatarColor: s(r.avatar_color),
|
||||||
|
day: r.day !== null && r.day !== undefined ? n(r.day) : 0,
|
||||||
|
month: r.month !== null && r.month !== undefined ? n(r.month) : 0,
|
||||||
};
|
};
|
||||||
out.push(it);
|
out.push(it);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -215,6 +215,29 @@ export interface FbRecentDay {
|
|||||||
age: number;
|
age: number;
|
||||||
/** 是第几个(自建纪念日且填了起始年才有;null = 不显示序号) */
|
/** 是第几个(自建纪念日且填了起始年才有;null = 不显示序号) */
|
||||||
nth: number;
|
nth: number;
|
||||||
|
/**
|
||||||
|
* 关联人的显示名(派生生日一定有;自建纪念日可能为空)。
|
||||||
|
*
|
||||||
|
* 🔴 #87(用户 2026-11-05):「如果这个纪念日来自生日…点击之后,
|
||||||
|
* 像日程那样弹出一个框来显示就行:显示这个人的头像、姓名,
|
||||||
|
* 以及生日的『日』和日期就可以了。」
|
||||||
|
*/
|
||||||
|
personName: string;
|
||||||
|
/** 头像 key(`avatars/xxx.jpg`;空 = 没设头像,端上退回首字色块) */
|
||||||
|
avatar: string;
|
||||||
|
/** 头像色(没头像时按它画色块) */
|
||||||
|
avatarColor: string;
|
||||||
|
/**
|
||||||
|
* 「日」—— 生日是哪一天(**用户填的那一天**)。
|
||||||
|
*
|
||||||
|
* ⚠️ 与 `date` 里截出来的"日"**可能不同**:农历生日时
|
||||||
|
* `day` 是农历日(初五 = 5),而 `date` 是换算后的公历日期。
|
||||||
|
* 用户要看的是"生日那天",所以显示这个。
|
||||||
|
* ⚠️ 0 = 没这个字段(自建纪念日的老数据),端上退回从 `date` 截。
|
||||||
|
*/
|
||||||
|
day: number;
|
||||||
|
/** 「月」—— 同理(农历生日的月份是农历月) */
|
||||||
|
month: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 首页「模块卡片」—— 一块一块的入口,带一句关键数字 */
|
/** 首页「模块卡片」—— 一块一块的入口,带一句关键数字 */
|
||||||
|
|||||||
@@ -62,6 +62,8 @@ import { FbTaskPanel } from '../../components/FbTaskPanel';
|
|||||||
import { FbTaskEditSheet } from '../../components/FbTaskEditSheet';
|
import { FbTaskEditSheet } from '../../components/FbTaskEditSheet';
|
||||||
/* v86:三张卡的新建表单 —— 全是**模块页正在用的同一个组件**,不另写。 */
|
/* v86:三张卡的新建表单 —— 全是**模块页正在用的同一个组件**,不另写。 */
|
||||||
import { FbDayEditSheet } from '../../components/FbDayEditSheet';
|
import { FbDayEditSheet } from '../../components/FbDayEditSheet';
|
||||||
|
/* #87:派生生日的只读卡(用户:「如果这个纪念日来自生日,我们是不能编辑的」) */
|
||||||
|
import { FbDayBirthdaySheet } from '../../components/FbDayBirthdaySheet';
|
||||||
import { FbPersonSheet } from '../../components/FbPersonSheet';
|
import { FbPersonSheet } from '../../components/FbPersonSheet';
|
||||||
import { FbSheetRing } from '../../components/FbSheetRing';
|
import { FbSheetRing } from '../../components/FbSheetRing';
|
||||||
import { FbMovieNewSheet } from '../../components/FbMovieNewSheet';
|
import { FbMovieNewSheet } from '../../components/FbMovieNewSheet';
|
||||||
@@ -681,6 +683,23 @@ export struct FbHomePage {
|
|||||||
this.pfDetail = null;
|
this.pfDetail = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 这条纪念日是不是「派生生日」(不能编辑的那种)。
|
||||||
|
*
|
||||||
|
* 判据用 `source` 前缀而不是 `id === 0`:
|
||||||
|
* · 派生生日:`birthday_solar` / `birthday_lunar`,服务端保证 `id = 0`;
|
||||||
|
* · 自建纪念日:`custom`,`id > 0`。
|
||||||
|
* 两个判据目前等价,但 `source` 是**语义**、`id` 是**实现细节** ——
|
||||||
|
* 万一以后派生条目也带 id(比如就想让它能点进某处),用 id 判会静默错。
|
||||||
|
*/
|
||||||
|
private isBirthdayDay(): boolean {
|
||||||
|
const d: FbRecentDay | null = this.dayDetail;
|
||||||
|
if (d === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return d.source === 'birthday_solar' || d.source === 'birthday_lunar';
|
||||||
|
}
|
||||||
|
|
||||||
/** 打开纪念日详情(#63)。 */
|
/** 打开纪念日详情(#63)。 */
|
||||||
private openDayDetail(d: FbRecentDay): void {
|
private openDayDetail(d: FbRecentDay): void {
|
||||||
this.dayDetail = d;
|
this.dayDetail = d;
|
||||||
@@ -2106,7 +2125,26 @@ export struct FbHomePage {
|
|||||||
⚠️ 复用 `FbDayEditSheet`(它就是"回填一条已有纪念日"的表单)。
|
⚠️ 复用 `FbDayEditSheet`(它就是"回填一条已有纪念日"的表单)。
|
||||||
它的保存/删除按钮在卡里,看着是"可改的详情卡",
|
它的保存/删除按钮在卡里,看着是"可改的详情卡",
|
||||||
符合用户"先看到信息"的要求。 */
|
符合用户"先看到信息"的要求。 */
|
||||||
if (this.dayDetail !== null) {
|
if (this.dayDetail !== null && this.isBirthdayDay()) {
|
||||||
|
/* 🔴🔴 #87(用户 2026-11-05):
|
||||||
|
「1. 如果这个纪念日来自生日,我们是不能编辑的。
|
||||||
|
2. 点击之后,像日程那样弹出一个框来显示就行:显示这个人的头像、姓名,
|
||||||
|
以及生日的『日』和日期就可以了。」
|
||||||
|
|
||||||
|
⚠️ **这里原来是个会改坏数据的 bug**:派生生日也走 `FbDayEditSheet`,
|
||||||
|
而且传的是 `editingMonth: 1, editingDay: 1`(写死的 1 月 1 日)。
|
||||||
|
结果点开任何一个生日都显示「1 月 1 日」,点保存还能把
|
||||||
|
**真实生日覆盖成 1 月 1 日** —— 等于把成员档案里的生日改掉了。
|
||||||
|
只读卡从根上避开这件事。 */
|
||||||
|
FbDayBirthdaySheet({
|
||||||
|
accent: this.daysAccent(),
|
||||||
|
item: this.dayDetail,
|
||||||
|
onClose: (): void => {
|
||||||
|
this.closeDayDetail();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.transition(fbSheetTransition())
|
||||||
|
} else if (this.dayDetail !== null) {
|
||||||
FbDayEditSheet({
|
FbDayEditSheet({
|
||||||
accent: this.daysAccent(),
|
accent: this.daysAccent(),
|
||||||
editingId: this.dayDetail.id,
|
editingId: this.dayDetail.id,
|
||||||
|
|||||||
Reference in New Issue
Block a user