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)。