From 6a5d351e793fc76048b70c01c92d68c87da8e073 Mon Sep 17 00:00:00 2001 From: laoyang Date: Fri, 6 Nov 2026 11:40:26 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A6=96=E9=A1=B5=E8=81=94=E7=B3=BB=E4=BA=BA?= =?UTF-8?q?=EF=BC=9A=E4=BF=AE=E5=A4=B4=E5=83=8F=E6=98=BE=E7=A4=BA=20+=20?= =?UTF-8?q?=E6=8E=92=E9=99=A4=E8=87=AA=E5=B7=B1=20(#88)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 用户:首页联系人,需要带头像,排除自己。 ① 头像(真 bug:从来没显示出来过) 改前 Image(p.avatar) —— 而 p.avatar 存的是**存储键**(avatars/xxx.jpg), 不是能喂给 Image() 的地址。Image("avatars/xxx.jpg") 被当成相对沙箱路径, 静默失败 ⇒ 永远只剩首字色块,看起来像"这个功能没做"。 正确出口项目里早就有:fbImageSrc(key, token)(先查本地解密缓存, 没缓存才拼 media.php?k=&token=)。名册页/观影卡都这么写,唯独首页这处漏了。 ⇒ 改用 FbAvatar({ name, color, dia, imageUrl }): · 底色+首字常驻,图片成功才盖上去 —— 名册绝大多数人没头像,必须回落; · 有 key 但图坏了(OSS 文件缺失/token 过期)时 Image 是纯空白, FbAvatar 会露出下面的首字,不会变成一块空光板。 personInitial() 因此成了死代码,删掉(FbAvatar 内部按 name 取首字)。 ② 排除自己 FbPersonRepo.list() 返回整个名册(含"我"),自己占掉一个最显眼的位置 (一屏只露 6 个,3 列 × 2 行)。 - 用 session.me.id 判,不用名字/昵称比(重名、改名会漏); - 取不到 id(0)时不剔任何人 —— 宁可多显示一个, 也不要因空 id 把列表清空(本项目踩过判断写反 ⇒ 列表恒空的坑); - pfTotal 用剔除后的数量:它渲染成标题「N 人」, 用原始总数会写 800 人却只列 799 个,看着像丢人。 验证(真机 5NC0225B27004718): - 标题 800 人 → 799 人;6 格从「爸爸/妈妈/岳父/杨永全/红围脖/轻舟」 变成「爸爸/妈妈/岳父/岳母/红围脖/轻舟」,即自己消失、后面依次前移; - 底部说明同步为「共 799 人」; - 6 个头像逐格取样(圆心 ±25px):色数 223~2162、主色占比 0.00~0.40, 全部是多色真实图像(纯色首字头会是主色占比>0.75、色数<50)。 hvigorw assembleHap BUILD SUCCESSFUL。 --- entry/src/main/ets/pages/home/FbHomePage.ets | 65 +++++++++++--------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/entry/src/main/ets/pages/home/FbHomePage.ets b/entry/src/main/ets/pages/home/FbHomePage.ets index 7934571..c021bc7 100644 --- a/entry/src/main/ets/pages/home/FbHomePage.ets +++ b/entry/src/main/ets/pages/home/FbHomePage.ets @@ -53,7 +53,7 @@ import { FB_TOKEN_STORE } from '../../data/FbTokenStore'; import { parseTaskMeta } from '../../data/FbParse'; import { FB_CARD_FORMS } from '../../data/FbCardForms'; import { fbApi, FbApiResult } from '../../data/FbHttp'; -import { FbSectionTitle } from '../../components/Widgets'; +import { FbAvatar, FbSectionTitle } from '../../components/Widgets'; import { FbStatCell } from '../../components/FbStatCell'; import { FbDayEventPanel } from '../../components/FbDayEventPanel'; import { FbEventSheet } from '../../components/FbEventSheet'; @@ -1124,10 +1124,25 @@ export struct FbHomePage { } try { const people: FbRosterPerson[] = await FbPersonRepo.inst().list(); - this.pfTotal = people.length; + /* 🔴 用户 2026-11-06:「首页联系人,需要带头像,**排除自己**。」 + ⇒ 从名册里剔掉"我"自己。首页这块是"家里人速览", + 把自己列在里面既没用(头像是自己)又占掉一个宝贵的位置 + (一屏只露 6 个,3 列 × 2 行)。 + ⚠️ 用 `session.me.id` 判,**不用名字/昵称比** —— 重名、改名都会漏; + 名册的 `id` 与服务端 persons.id 同一套,稳。 + ⚠️ 取不到(0,比如还没登录完)时**不剔任何人**:宁可多显示一个, + 也不要因为一个空 id 把整个列表清空(历史上踩过"suspend 条件写反 + ⇒ 列表恒空"的坑)。 + ⚠️ `pfTotal` 用**剔除后**的数量:它渲染成标题右侧「N 人」, + 若还是原始总数,卡片会写"N 人"却只列出 N-1 个,看着像丢人。 */ + const meId: number = this.app.session.me.id; + const others: FbRosterPerson[] = meId > 0 + ? people.filter((x: FbRosterPerson): boolean => x.id !== meId) + : people; + this.pfTotal = others.length; /* 卡片上只露前 6 个:与 `HomeCards` 的 `contacts` 默认 `n => 8` 同口径, 手机上 6 个(3 列 × 2 行)刚好一屏内不压其他卡片。 */ - this.pfRecent = people.slice(0, 6); + this.pfRecent = others.slice(0, 6); } catch (err) { hilog.warn(DOMAIN, TAG, '首页读名册失败:%{public}s', JSON.stringify(err)); this.pfRecent = []; @@ -2759,27 +2774,22 @@ export struct FbHomePage { @Builder personTile(p: FbRosterPerson) { Column({ space: 5 }) { - if (p.avatar !== '') { - Image(p.avatar) - .width(38) - .height(38) - .borderRadius(19) - .objectFit(ImageFit.Cover) - .alt($r('app.media.fb_ic_people')) - } else { - /* 没有头像 ⇒ 首字 + 名册里那个人的底色(与名册页一致,不另算颜色)。 - ⚠️ 字也要用**对色**(`FbPersonRepo` 存了 avatarColor 是给底用的)—— - 这里简单用白字:底色本身就是中深色(名册页的取色规则)。 */ - Text(this.personInitial(p)) - .width(38) - .height(38) - .borderRadius(19) - .backgroundColor(p.avatarColor !== '' ? p.avatarColor : '#B7A99A') - .fontColor(Color.White) - .fontSize(16) - .fontWeight(FontWeight.Medium) - .textAlign(TextAlign.Center) - } + /* 🔴 用户 2026-11-06:「首页联系人,需要带头像」。 + 改前这里是 `if (p.avatar !== '') { Image(p.avatar) }` —— 头像**从来显示不出来**。 + 根因:`FbRosterPerson.avatar` 存的是**存储键**(`avatars/xxx.jpg`), + 不是能直接喂给 `Image()` 的地址。`Image('avatars/xxx.jpg')` 会被当成 + 相对沙箱路径 ⇒ 静默失败 ⇒ 永远走不到图,只剩首字色块。 + ⇒ 统一改用 `FbAvatar`:它接受 `imageUrl`(用 `fbImageSrc(key, token)` + 拼好传进来),并且**底色+首字常驻、图片成功才盖上去** —— + 名册 800 人里只有 19 人传过头像,没图的必须回落到首字, + 而"有 key 但图坏了"时也不会变成一块空光板(`Image` 失败是空白)。 + ⚠️ 尺寸 38 与原实现一致(三列网格、两行不压其它卡)。 */ + FbAvatar({ + name: this.personLabel(p), + color: p.avatarColor !== '' ? p.avatarColor : '#B7A99A', + dia: 38, + imageUrl: p.avatar !== '' ? fbImageSrc(p.avatar, FB_TOKEN_STORE.get()) : '' + }) Text(this.personLabel(p)) .fontSize(FbMetric.fontTiny) @@ -2814,11 +2824,8 @@ export struct FbHomePage { return p.name; } - /** 首字(头像兜底)。空名兜底成 `?`,别画出一个空圆。 */ - private personInitial(p: FbRosterPerson): string { - const nm: string = this.personLabel(p); - return nm.length > 0 ? nm.substring(0, 1) : '?'; - } + /** 首字兜底已移交给 `FbAvatar`(它内部按 `name` 取首字)。 + * 2026-11-06 首页联系人改用它之后,这里的 `personInitial()` 成了死代码,删掉。 */ /** * 「最近纪念日」里的一行(v59,用户 2026-10-18)。