From 7ee4810435690d71c3f7bf0518d03cf0b19796e5 Mon Sep 17 00:00:00 2001 From: laoyang Date: Thu, 5 Nov 2026 20:39:44 +0800 Subject: [PATCH] =?UTF-8?q?=E7=94=9F=E6=97=A5=E5=8D=A1=E9=87=8D=E6=8E=92?= =?UTF-8?q?=EF=BC=9A=E6=96=B9=E6=A1=86=E6=94=BE"=E8=BF=98=E5=89=A9?= =?UTF-8?q?=E5=87=A0=E5=A4=A9"=E3=80=81=E5=8F=B3=E4=BE=A7=E6=94=BE?= =?UTF-8?q?=E5=86=9C=E5=8E=86=E6=97=A5=E6=9C=9F=20+=20=E9=98=B3=E5=8E=86?= =?UTF-8?q?=E6=97=A5=E6=9C=9F=20(#88)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 用户 2026-11-05:「还有5天,也就是10月2号,这个不好。因为"还有5天"这个事情 比较重要,所以方形框里面应该写几天,比如还有5天就写5天;现在还有5天, 那个位置应该写上10月2日。如果是农历的话,就要写上农历十月二日。 下面还要写上阳历:换算完之后,今年阳历是多少?比如11月10日, 都放在右侧"满42周岁"这个位置。」 上一版信息分工正好是**反的**:方框里放了「日」(几号),右侧放了「还有 N 天」。 用户要的相反。 重排后: 方框(84x84 浅主题色块) = **还剩几天**(大数字)+ 下方「天」/「今天」 右侧第一行 = 日期(农历生日「农历十月初二」;其余「11月16日」) 右侧第二行 = 阳历换算(**只有农历生日才画**) 右侧第三行 = 满 N 周岁 服务端 Anniversary::occurrences() 补两个**成品文字**字段: lunar_label = 「十月初二」「闰四月初五」(农历生日才有) solar_md = 「11月10日」(今年实际发生那天的公历月日) ⚠️ 农历文字为什么不在端上拼:Lunar 有完整的月名/日名对照表 (正月/冬月/腊月、初一/廿三…),端上再抄一份必然漂移, 而且闰月(闰四月)这种特例得一起处理。 ⚠️ solar_md 用 $date(今年换算后的实际日期)而不是 $a['month']/$a['day']: 农历生日的 month/day 是**农历**月日,直接拼出来会是错的公历。 ⚠️ 公历生日时 dateSolar() 返回空串 ⇒ 不画第二行: 那时第一行已经是「11月16日」,再画一次一模一样,纯噪音。 ⚠️ days = 0(就是今天)时方框写「今」而不是「0」: 0 看着像没数据,而且底下那行写「今天」,配成「今 / 今天」很奇怪。 实测服务端输出: 高雪玉 的农历生日 days=5 lunar=十月初二 solar=11月10日 date=2026-11-10 领证纪念日 days=7 lunar=(空) solar=11月12日 date=2026-11-12 杨永全 的农历生日 days=8 lunar=十月初五 solar=11月13日 date=2026-11-13 杨永全 的生日 days=11 lunar=(空) solar=11月16日 date=2026-11-16 刘巧莲 的农历生日 days=29 lunar=十月廿六 solar=12月4日 date=2026-12-04 编译通过,已装真机。 --- .../ets/components/FbDayBirthdaySheet.ets | 121 +++++++++++------- entry/src/main/ets/data/FbParse.ets | 4 + entry/src/main/ets/model/Types.ets | 19 +++ 3 files changed, 96 insertions(+), 48 deletions(-) diff --git a/entry/src/main/ets/components/FbDayBirthdaySheet.ets b/entry/src/main/ets/components/FbDayBirthdaySheet.ets index 1bc97bd..e2bb203 100644 --- a/entry/src/main/ets/components/FbDayBirthdaySheet.ets +++ b/entry/src/main/ets/components/FbDayBirthdaySheet.ets @@ -110,35 +110,56 @@ export struct FbDayBirthdaySheet { } /** - * 生日是「几号」—— 卡片正中的那个大数字。 + * 方框里的大数字:**还剩几天**。 * - * ⚠️ 优先用 `day`(用户填的那一天);为 0 才从 `date` 里截。 - * 农历生日的 `day` 是农历日,与 `date` 的公历日**不一样**, - * 用户要看的是"生日那天"。 + * 🔴 #88(用户 2026-11-05):「"还有5天"这个事情比较重要, + * 所以方形框里面应该写几天,比如还有5天就写5天。」 + * + * ⚠️ 就是今天(days = 0)时返回「今」而不是「0」—— + * 0 看着像"没有数据",而且底下那行会写「今天」,配成「今 / 今天」很奇怪。 */ - private dayNum(): string { + private daysNum(): 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() : ''; + return d.days === 0 ? '今' : d.days.toString(); } - /** 「11 月」—— 与「几号」配成「11 月 16 日」的读法 */ - private monthWord(): string { + /** + * 右侧第一行:这条纪念日的日期写法。 + * + * · 农历生日 → 「十月初二」(服务端 `lunarLabel`) + * · 公历生日 / 自建纪念日 → 「11月16日」(服务端 `solarMd`) + * + * ⚠️ 「农历十月二日」里的「十月」+「初二」在服务端已拼成「十月初二」, + * 这里只补一个「农历」前缀把类别点明(用户原话就是这么念的)。 + */ + private datePrimary(): string { const d: FbRecentDay | null = this.item; if (d === null) { return ''; } - if (d.month > 0) { - return d.month.toString() + ' 月'; + if (d.lunarLabel !== '') { + return '农历' + d.lunarLabel; } - const mm: number = d.date.length >= 7 ? parseInt(d.date.substring(5, 7), 10) : 0; - return mm > 0 ? mm.toString() + ' 月' : ''; + return d.solarMd; + } + + /** + * 右侧第二行:阳历换算(**只有农历生日才需要**)。 + * + * 🔴 #88:「下面还要写上阳历:换算完之后,今年阳历是多少?比如11月10日」 + * + * ⚠️ 公历生日返回空串 ⇒ 不画这一行: + * 那时第一行已经是「11月16日」,再画一次一模一样,纯噪音。 + */ + private dateSolar(): string { + const d: FbRecentDay | null = this.item; + if (d === null || d.lunarLabel === '' || d.solarMd === '') { + return ''; + } + return '阳历 ' + d.solarMd; } /** 完整日期 `2026 年 11 月 16 日`(下一次发生的公历日期) */ @@ -153,19 +174,6 @@ export struct FbDayBirthdaySheet { 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'; @@ -248,17 +256,33 @@ export struct FbDayBirthdaySheet { .padding({ top: 4, bottom: 18 }) .alignItems(VerticalAlign.Center) - /* ---- 「几号」大字块 + 剩余天数 ---- */ - /* 用户第 2 条:「显示…生日的『日』和日期就可以了」 - ⇒ 把「日」做成一个视觉焦点(大数字),日期在下面一行小字。 - 底色用浅一档主题色(fbMixWhite 0.91),与下拉框/胶囊同一套。 */ - Row({ space: 12 }) { - Column({ space: 0 }) { - Text(this.dayNum()) + /* ---- 方框(还剩几天)+ 右侧(日期 / 年龄)---- + 🔴🔴 #88(用户 2026-11-05): + 「还有5天,也就是10月2号,这个不好。因为"还有5天"这个事情比较重要, + 所以方形框里面应该写几天,比如还有5天就写5天; + 现在还有5天,那个位置应该写上10月2日。 + 如果是农历的话,就要写上农历十月二日。下面还要写上阳历: + 换算完之后,今年阳历是多少?比如11月10日, + 都放在右侧"满42周岁"这个位置。」 + + ⇒ 信息分工重排(上一版正好是反的:方框放"几号"、右侧放"还有几天"): + 方框 = **还剩几天**(用户说这件事最重要,要大) + 右侧第一行 = 日期(农历生日写「十月初二」,公历生日写「11月16日」) + 右侧第二行 = 阳历换算(农历生日才需要;公历生日与第一行重复,不画) + 右侧第三行 = 满 N 周岁 + + ⚠️ 「还剩几天」为什么不做成"5 天"两个单位分开: + 30 以上是两位数,分开排会挤;`fontSize(34)` 放「12」正好。 + ⚠️ 农历生日的两行日期**不是同一天**(十月初二 ↔ 11月10日), + 所以必须都画;公历生日两行会一模一样,只画一行。 */ + Row({ space: 14 }) { + Column({ space: 2 }) { + Text(this.daysNum()) .fontSize(34) .fontWeight(FontWeight.Bold) .fontColor(this.accent) - Text(this.monthWord()) + /* 「还有 5 天」的时候,这一行是「天」;就是今天时写「今天」 */ + Text(this.item !== null && this.item.days === 0 ? '今天' : '天') .fontSize(FbMetric.fontTiny) .fontColor(fbMixWhite(this.accent, 0.35)) } @@ -269,21 +293,22 @@ export struct FbDayBirthdaySheet { .borderRadius(FbMetric.radiusS) Column({ space: 6 }) { - Text(this.daysWord()) - .fontSize(FbMetric.fontSmall) + /* 第一行:日期 */ + Text(this.datePrimary()) + .fontSize(FbMetric.fontBody) .fontWeight(FontWeight.Medium) .fontColor(this.accent) - if (this.item !== null && this.item.age >= 0) { - Text('满 ' + this.item.age.toString() + ' 周岁') - .fontSize(FbMetric.fontTiny) + /* 第二行:阳历换算(只有农历生日才画) */ + if (this.dateSolar() !== '') { + Text(this.dateSolar()) + .fontSize(FbMetric.fontSmall) .fontColor(FbColors.muted) } - if (this.isLunar()) { - /* 农历生日时「日」是农历日,与上面的公历日期不同 —— - 不说明一句用户会以为"日子算错了"。 */ - Text('农历日期,每年按农历换算') - .fontSize(FbMetric.fontTiny) - .fontColor(FbColors.faint) + /* 第三行:满 N 周岁 */ + if (this.item !== null && this.item.age >= 0) { + Text('满 ' + this.item.age.toString() + ' 周岁') + .fontSize(FbMetric.fontSmall) + .fontColor(FbColors.muted) } } .alignItems(HorizontalAlign.Start) diff --git a/entry/src/main/ets/data/FbParse.ets b/entry/src/main/ets/data/FbParse.ets index b215859..52bb425 100644 --- a/entry/src/main/ets/data/FbParse.ets +++ b/entry/src/main/ets/data/FbParse.ets @@ -187,6 +187,8 @@ interface RawRecentDay { /* #87:生日只读卡要用(服务端 Anniversary::occurrences 已输出) */ person_name?: string | null; avatar?: string | null; avatar_color?: string | null; day?: number | null; month?: number | null; + /* #88:卡片右侧的两种日期写法(服务端给成品文字) */ + lunar_label?: string | null; solar_md?: string | null; } interface RawTaskBoard { @@ -921,6 +923,8 @@ export function parseRecentDays(v: Object | null | undefined): FbRecentDay[] { 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, + lunarLabel: s(r.lunar_label), + solarMd: s(r.solar_md), }; out.push(it); } diff --git a/entry/src/main/ets/model/Types.ets b/entry/src/main/ets/model/Types.ets index c29a9a5..5a58699 100644 --- a/entry/src/main/ets/model/Types.ets +++ b/entry/src/main/ets/model/Types.ets @@ -238,6 +238,25 @@ export interface FbRecentDay { day: number; /** 「月」—— 同理(农历生日的月份是农历月) */ month: number; + /** + * 农历写法的成品文字,如「十月初二」「闰四月初五」。 + * 只有农历生日才有;公历生日 / 自建纪念日为**空串**。 + * + * 🔴 #88(用户 2026-11-05):「如果是农历的话,就要写上农历十月二日。」 + * ⚠️ 为什么由服务端给成品:`Lunar` 有完整的月名/日名对照表 + * (正月/冬月/腊月、初一/廿三…),端上再抄一份必然漂移, + * 闰月(闰四月)这种特例也得一起处理。 + */ + lunarLabel: string; + /** + * 今年实际发生那天的公历月日,如「11月10日」。 + * + * 🔴 #88(用户 2026-11-05):「下面还要写上阳历:换算完之后,今年阳历是多少? + * 比如11月10日,都放在右侧『满42周岁』这个位置。」 + * ⚠️ 农历生日时它与 `lunarLabel` **不是同一天**(一个农历一个公历), + * 这正是用户要同时看到两个的原因。 + */ + solarMd: string; } /** 首页「模块卡片」—— 一块一块的入口,带一句关键数字 */