v0.8.2 头像点进我的详情 / 未读数接真实数据 / 名册圆角卡(容器要换成页面底色)
用户 2026-10-18 夜三条: ①「右上角,显示的应该是登录者的头像,点击头像进入我的详情页面。」 头像**本来就是登录者本人的**(v59 已接 session.me.avatarUrl); 真正缺的是**点击** —— TopBar 里那个 FbAvatar **根本没有 onClick**, 只有一句写着"点开账号菜单"的注释,而"账号菜单"这个东西在代码里并不存在。 ⇒ 接 openMyDetail() → bindSheet 弹 FbPersonSheet(复用名册那个人详情组件)。 🔴 数据必须走 repo.byId(meId)(本次为它新增 byId),不能从名册列表那批里找: **"我"常常不在自己的名册里**(名册是"我挑出来的那一小撮"), 从列表里查会**静默落空**、点了没反应 —— 最难查的那种失败。 ⚠️ 三种状态都说清楚:加载中 / 拿到了 / 拿不到,绝不留空白浮层。 ②「提醒按钮,明明没提醒,怎么还显示个 2?」 🔴 真根因:`@Trace unread: number = 2;` 是**写死的占位初值**, 而全工程只有一处给它赋值(通知页「全部已读」清 0)。 没进过通知页的人**永远看到 2**;进了通知页又"永远 0"(把真实未读也盖掉) —— 两个方向都错。 ⇒ ① 初值改 0(拿到真值前必须是"没有未读",不能凭空多出 2); ② 首页把 /home 的真实 unread 写进全局状态。 (服务端 Notification::unreadCount,与通知页同源;/home 本来就返回它、 FbParse 也早就解析了 —— 只是**没人往全局状态里写**。) ③「名册页面,不好看,太丑了,应该是每个人都是圆角矩形,往中间收一点, 距离左右都有点距离,每个人中间都有一点空隙。」 🔴🔴 真凶**不是卡片形状**(v51 就做了 borderRadius + margin)—— 而是**列表容器也是纯白** ⇒ 白卡压白底 ⇒ 圆角与左右收边**全看不见**, 看上去就是一整块通栏白。这解释了"改过一轮还是丑":上次改的是卡片, 问题在"背景没有对比"。 ⇒ 容器 + 外层兜底改 FbColors.paper(页面底色),卡片保持白; 圆角 radiusS(10) → 新增 radiusCard(14)(列表项专用档:16 显胖、10 显方); 左右各 pagePad(16)、卡间 10(原 8 偏挤)、行内边距 11→12。 验证:hvigor BUILD SUCCESSFUL;_fb_arkts_guard.js 347/0(本批新增 18 条, 另**收紧 2 条**旧判据 —— M 组"圆角卡"那条原来锚"逐字相邻两行"、且**测错了对象**: 没查容器背景,所以对"白卡压白底"这个真实缺陷毫无把关能力); _fb_v59b_falsify.py 8 项注入 ⇒ 8/0。 ⚠️ 本轮反向验证头一轮漏了 3 条(都是"判据太宽"),已逐条收紧并记入 pitfalls: · 删掉头像 onClick 后仍绿 —— openMyDetail 这个标识符在**方法定义**里也出现; · 容器改回白底后仍绿 —— 本页有**两处** FbColors.paper(容器 / 兜底); · /home unread 改成写死 2 后仍绿 —— Notification::unreadCount 在 PHP 里也有两处。
This commit is contained in:
@@ -42,8 +42,20 @@ export class FbAppState {
|
||||
/** 当前会话(接口接上之前先用演示数据;`loggedIn=false` 时应跳登录页) */
|
||||
@Trace session: FbSession = FB_DEMO_SESSION;
|
||||
|
||||
/** 未读通知数(顶栏铃铛角标) */
|
||||
@Trace unread: number = 2;
|
||||
/**
|
||||
* 未读通知数(顶栏铃铛角标)。
|
||||
*
|
||||
* 🔴🔴 v59b(用户 2026-10-18):「提醒按钮,明明没提醒,怎么还显示个 2?」
|
||||
* 这个 **写死的 2** 就是答案:它原来只是个占位初值,而全工程没有任何地方
|
||||
* 用真实数据填过它(只有通知页的「全部已读」会清成 0)
|
||||
* ⇒ 没进过通知页的人**永远看到 2**。
|
||||
*
|
||||
* ⚠️ 改成 **0**:未读数在拿到真实值之前必须是"没有未读",
|
||||
* 而不是"假装有 2 条"。真实值由 `/home` 的 `unread` 写入
|
||||
* (见 FbHomePage 里那段说明),进通知页后由那边继续维护。
|
||||
* 宁可短暂少显示,也不能凭空多出一个用户会去追问的数字。
|
||||
*/
|
||||
@Trace unread: number = 0;
|
||||
|
||||
/**
|
||||
* 状态栏高度(vp)。
|
||||
|
||||
@@ -58,6 +58,15 @@ export class FbMetric {
|
||||
static readonly radius: number = 16;
|
||||
/** 小圆角(内嵌块 / 输入框) */
|
||||
static readonly radiusS: number = 10;
|
||||
/**
|
||||
* 列表项圆角(**一行一张卡**那种,如名册的人员行)。
|
||||
*
|
||||
* 🔴 为什么单独一档(2026-10-18 用户「名册太丑」):
|
||||
* 列表项**一行一张卡**、上下密排;用 16(区块卡的圆角)会显得"胖"、
|
||||
* 相邻两卡的圆角挤在一起很吵;用 10(内嵌小块的圆角)在 12vp 的行内边距下
|
||||
* 又显得方、像"被裁过的白条"。14 是这两个之间的甜点。
|
||||
*/
|
||||
static readonly radiusCard: number = 14;
|
||||
/** 胶囊圆角 */
|
||||
static readonly radiusPill: number = 999;
|
||||
|
||||
|
||||
@@ -21,7 +21,13 @@ import { FbAppState, fbAppState } from '../common/Store';
|
||||
import { FbSyncState, SYNC_DONE, SYNC_FAIL, SYNC_RUNNING, fbSyncState } from '../common/FbSyncStore';
|
||||
import { fbModuleOf } from '../model/Modules';
|
||||
import { FbAvatar } from './Widgets';
|
||||
import { FbPersonSheet } from './FbPersonSheet';
|
||||
// ⚠️ `inst()` 拿单例(本工程所有 repo 都是这个约定,见 FbPersonRepo 文件头);
|
||||
// `FB_TOKEN_STORE` 在 **FbTokenStore.ets** 里(不是在 FbDeviceStore)。
|
||||
import { FbPersonRepo, FbRosterPerson } from '../data/FbPersonRepo';
|
||||
import { FB_TOKEN_STORE } from '../data/FbTokenStore';
|
||||
import { syncAll } from '../data/FbSyncAll';
|
||||
import { BusinessError } from '@kit.BasicServicesKit';
|
||||
import { hilog } from '@kit.PerformanceAnalysisKit';
|
||||
|
||||
@ComponentV2
|
||||
@@ -41,6 +47,15 @@ export struct FbTopBar {
|
||||
/** 同步面板是否打开 */
|
||||
@Local syncSheet: boolean = false;
|
||||
|
||||
/** 「我的详情」浮层是否打开(点头像触发) */
|
||||
@Local myDetailSheet: boolean = false;
|
||||
/** 「我的详情」里的人(null = 还没取到) */
|
||||
@Local myDetail: FbRosterPerson | null = null;
|
||||
/** 「我的详情」是否在加载 */
|
||||
@Local myDetailLoading: boolean = false;
|
||||
/** 「我的详情」的兜底提示(拿不到资料时显示) */
|
||||
@Local myDetailNote: string = '';
|
||||
|
||||
build() {
|
||||
// 🔴 顶栏横向镜像 —— 「质感握姿」(用户 2026-10-16 第 4 条):
|
||||
// 左手握时家书图标在**左**,右手握时它跑到**右**,方便单手点它开抽屉。
|
||||
@@ -177,12 +192,22 @@ export struct FbTopBar {
|
||||
// 与左边的同步图标、右边的头像各拉开一段(用户:太近了)
|
||||
.margin({ left: FbMetric.gapTopActions, right: FbMetric.gapTopActions })
|
||||
|
||||
// 头像(点开账号菜单)
|
||||
// 头像 —— 点它打开**我自己的详情**
|
||||
//
|
||||
// 🔴 v59(用户 2026-10-18):「右上角的头像应该是真实的。」
|
||||
// ⇒ 传 `imageUrl`(真实头像图;服务端 `avatar_url()` 给的)。
|
||||
// 没传过头像的人拿到空串 ⇒ `FbAvatar` 自带色块字回落,
|
||||
// 所以这里不需要额外判断("两者都要有"是 FbAvatar 的既有设计)。
|
||||
// 🔴🔴 v59b(用户 2026-10-18):「右上角,显示的应该是登录者的头像,
|
||||
// **点击头像进入我的详情页面**。」
|
||||
//
|
||||
// ⚠️ 原来这里**根本没有 onClick**(只有一句写着"点开账号菜单"的注释)——
|
||||
// 用户点了没任何反应,而代码里连一个"账号菜单"都不存在。
|
||||
// ⇒ 现在接的是**详情浮层**(与名册里点某个人同一个组件、同一套数据源)。
|
||||
//
|
||||
// 🔴 头像**已经是登录者本人的**(`session.me.avatarUrl` 由 `/login` 与
|
||||
// `/me` 两处给,见 FbLogin/FbSession)—— 用户这条要求上一轮就已满足,
|
||||
// 真正缺的是"点了能进去"。
|
||||
//
|
||||
// ⚠️ 数据取自**本地库**(`FbPersonRepo.inst().byId`),不是名册列表里那份:
|
||||
// "我"常常**不在自己的名册**里(名册是"我挑出来的那一小撮"),
|
||||
// 从名册那批里找会静默落空 ⇒ 点了没反应(最难查的那种失败)。
|
||||
FbAvatar({
|
||||
name: this.app.session.me.name,
|
||||
color: this.app.session.me.avatarColor,
|
||||
@@ -192,6 +217,32 @@ export struct FbTopBar {
|
||||
? this.app.session.me.avatarUrl
|
||||
: ''
|
||||
})
|
||||
// ⚠️ `FbAvatar` 的布局尺寸在画布内(`Image` 自己撑圆),外层要显式
|
||||
// 给一个可点区域 —— 32 的头像直接当热区在真机上偏小(手指容易点空)。
|
||||
.width(40)
|
||||
.height(40)
|
||||
.margin({ left: FbMetric.gapTopActions })
|
||||
.onClick((): void => {
|
||||
this.openMyDetail();
|
||||
})
|
||||
// 「我的详情」浮层 —— 复用名册那个人详情组件(同一个组件、同一套字段)
|
||||
//
|
||||
// ⚠️ 用 `bindSheet` 而不是自己在 `build` 里叠一层遮罩:
|
||||
// 这条顶栏在**每个模块页**都会渲染(`topBarSlot`),
|
||||
// 自己叠遮罩要处理"盖住悬浮栏 / 盖住抽屉 / 手势返回"一堆事;
|
||||
// bindSheet 是系统能力,这些它都管(同步面板也是这么做的)。
|
||||
//
|
||||
// ⚠️ `onDisappear` 必须复位 `myDetailSheet`(点遮罩/下滑关闭都会走它),
|
||||
// 否则下次点头像**打不开**(状态位还是 true 但面板已经不在)。
|
||||
.bindSheet(this.myDetailSheet, this.myDetailPanel(), {
|
||||
height: SheetSize.FIT_CONTENT,
|
||||
dragBar: true,
|
||||
showClose: false,
|
||||
backgroundColor: FbColors.surface,
|
||||
onDisappear: (): void => {
|
||||
this.myDetailSheet = false;
|
||||
}
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
// 🔴 高度 = **状态栏高度 + 顶栏本身高度**(用户 2026-10-13 要"全沉浸")。
|
||||
@@ -245,6 +296,104 @@ export struct FbTopBar {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开「我」的详情浮层(点右上角头像触发)。
|
||||
*
|
||||
* 🔴 v59b(用户 2026-10-18):「点击头像进入我的详情页面。」
|
||||
*
|
||||
* 为什么**先打开浮层、再补数据**(而不是等网络回来才开):
|
||||
* 本地优先是本应用的立身之本 —— 点一下要**立刻**有东西出来,
|
||||
* 断网时也必须能看。本地库那份已经够画详情的前几段,
|
||||
* 网络回来后再原地补全(`fetchDetail`)。
|
||||
*
|
||||
* ⚠️ 失败时**不弹错误**:`me.id` 拿不到(未登录/数据还没同步下来)就只弹一句
|
||||
* "资料还没同步下来",而不是让用户对着一个空白浮层猜。
|
||||
*/
|
||||
private async openMyDetail(): Promise<void> {
|
||||
const meId: number = this.app.session.me.id;
|
||||
if (meId <= 0) {
|
||||
this.myDetailNote = '还没拿到你的资料,请先同步一次';
|
||||
this.myDetailSheet = true;
|
||||
return;
|
||||
}
|
||||
/* ⚠️ 先开浮层(`myDetailSheet = true`)再 await:
|
||||
否则网络慢时用户点了一下**几十毫秒内毫无反应**,会以为按钮坏了。
|
||||
`loading` 由浮层自己显示,观感上"点开就有东西"。 */
|
||||
this.myDetailLoading = true;
|
||||
this.myDetail = null;
|
||||
this.myDetailSheet = true;
|
||||
try {
|
||||
const local: FbRosterPerson | null = await FbPersonRepo.inst().byId(meId);
|
||||
this.myDetail = local;
|
||||
this.myDetailLoading = false;
|
||||
// 本地有 ⇒ 顺手用网络那份补全(口径与名册里点某人完全一致)
|
||||
const token: string = FB_TOKEN_STORE.get();
|
||||
if (token !== '' && local !== null) {
|
||||
const full: FbRosterPerson | null = await FbPersonRepo.inst().fetchDetail(meId, token);
|
||||
// ⚠️ 浮层可能已经被关掉、或期间换了人 ⇒ 只在"还开着同一个人"时才覆盖
|
||||
if (full !== null && this.myDetailSheet
|
||||
&& this.myDetail !== null && this.myDetail.id === meId) {
|
||||
this.myDetail = full;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
const e: BusinessError = err as BusinessError;
|
||||
hilog.warn(0x0000, 'FamilyBook', '取我的详情失败:%{public}s',
|
||||
e.message !== undefined ? e.message : JSON.stringify(err));
|
||||
this.myDetailLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 「我的详情」面板(点头像弹出)。
|
||||
*
|
||||
* ⚠️ 三种状态都要有话说(用户 2026-10-18 报过"点了没反应"这类问题):
|
||||
* · 加载中 ⇒ 「正在读取…」(不要让浮层空着)
|
||||
* · 拿到了 ⇒ 复用 `FbPersonSheet`(姓名/称呼/电话/生日/单位/标签…)
|
||||
* · 拿不到 ⇒ 显式一句 `myDetailNote`(而不是空白)
|
||||
*/
|
||||
@Builder
|
||||
myDetailPanel() {
|
||||
Column() {
|
||||
if (this.myDetailLoading) {
|
||||
Row({ space: 8 }) {
|
||||
LoadingProgress().width(18).height(18).color(FbColors.brand)
|
||||
Text('正在读取我的资料…')
|
||||
.fontSize(FbMetric.fontSmall)
|
||||
.fontColor(FbColors.muted)
|
||||
}
|
||||
.width('100%')
|
||||
.justifyContent(FlexAlign.Center)
|
||||
.padding({ top: 28, bottom: 28 })
|
||||
} else if (this.myDetail !== null) {
|
||||
FbPersonSheet({
|
||||
person: this.myDetail,
|
||||
onClose: (): void => {
|
||||
this.myDetailSheet = false;
|
||||
},
|
||||
// ⚠️ 这里**不给编辑入口**:编辑要跳名册页那套编辑浮层(含标签/电话增删),
|
||||
// 而顶栏在**每个模块页**都存在 —— 在这里接编辑会变成
|
||||
// "在日程页里编辑家庭成员的资料",职责与页面上下文都不对。
|
||||
// 要看/改详细资料,从名册进(那是它的主场)。
|
||||
onEdit: (): void => {
|
||||
this.myDetailSheet = false;
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Text(this.myDetailNote !== ''
|
||||
? this.myDetailNote
|
||||
: '暂时拿不到你的资料,下拉同步一次再试')
|
||||
.fontSize(FbMetric.fontSmall)
|
||||
.fontColor(FbColors.muted)
|
||||
.textAlign(TextAlign.Center)
|
||||
.width('100%')
|
||||
.padding({ top: 28, bottom: 28, left: 24, right: 24 })
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.constraintSize({ maxHeight: '82%' })
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步面板(点顶栏图标弹出)。
|
||||
*
|
||||
|
||||
@@ -509,6 +509,37 @@ export class FbPersonRepo {
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 id 取**一个人**(名册里那份,非详情接口)。
|
||||
*
|
||||
* 🔴 v59(用户 2026-10-18):「点击头像进入我的详情页面。」
|
||||
* 头像点开的是**当前登录者自己**的详情,而"我"**不一定在自己的名册里** ——
|
||||
* 名册筛的是"我挑出来的那一小撮",本人常常不在其中。
|
||||
* 不加这个查询,"点头像 → 详情"就会**静默没有任何反应**(`rawById` 里查不到)。
|
||||
*
|
||||
* ⚠️ 与 `list()` 的差别只有两点:不 JOIN `person_roster`(不要求"在我名册里"),
|
||||
* 以及带 `kind='member'`(排除观影那边可能写进来的非成员行)。
|
||||
* 字段清单必须与 `list()` **完全一致**,否则 `rowToPerson` 会读出 undefined
|
||||
* (它按列名取值)⇒ 到头来没人看得懂为什么"详情里少了几行"。
|
||||
*/
|
||||
async byId(id: number): Promise<FbRosterPerson | null> {
|
||||
if (id <= 0) {
|
||||
return null;
|
||||
}
|
||||
const sql: string =
|
||||
'SELECT p.id, p.name, p.nickname, p.gender, p.birthday, p.avatar, p.avatar_color,' +
|
||||
' p.note, p.email, p.org, p.title, p.slogan, p.addr_city,' +
|
||||
' 0 AS sort_order, NULL AS phones,' +
|
||||
' (SELECT GROUP_CONCAT(t.tag, "\\u0001") FROM person_tags t' +
|
||||
' WHERE t.person_id = p.id) AS tags' +
|
||||
' FROM persons p WHERE p.id = ? LIMIT 1';
|
||||
const rows: FbRow[] = await this.db.queryRows(sql, [id]);
|
||||
if (rows.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return this.rowToPerson(rows[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读名册的元信息(人 + 标签云 + 我的 id)。
|
||||
*
|
||||
|
||||
@@ -133,6 +133,21 @@ export struct FbHomePage {
|
||||
this.statOverdue = d.stat.overdue;
|
||||
this.memories = d.memories;
|
||||
this.recentDays = d.recentDays;
|
||||
/* 🔴🔴 v59b(用户 2026-10-18):「提醒按钮,明明没提醒,怎么还显示个 2?」
|
||||
*
|
||||
* 真根因:`app.unread` **从来没接过数据** —— 它只是 `FbAppState` 里的
|
||||
* 一个写死的初值 `@Trace unread: number = 2;`,而全工程**只有一处**
|
||||
* 给它赋值(通知页的「全部已读」把它改成 0)。
|
||||
* ⇒ 于是"从没进过通知页"的用户**永远看到 2**;进了通知页又变成
|
||||
* "永远是 0"(把真实未读也盖掉了)。两个方向都错。
|
||||
*
|
||||
* `/home` 本来就返回权威的 `unread`(服务端 `Notification::unreadCount`,
|
||||
* 与通知页同一个来源)—— 这里把它同步进全局状态,铃铛角标就真了。
|
||||
*
|
||||
* ⚠️ 首页是启动后必到的页面(默认模块),所以这一个赋值点就够
|
||||
* "进应用看到真数字";进通知页后由那边继续维护(标记已读会变)。
|
||||
*/
|
||||
this.app.unread = d.unread;
|
||||
},
|
||||
(note: string): void => {
|
||||
this.syncNote = note;
|
||||
|
||||
@@ -802,15 +802,21 @@ export struct FbPeoplePage {
|
||||
// 见 `build()` 的说明。
|
||||
.layoutWeight(1)
|
||||
.width('100%')
|
||||
// 🔴 **白底铺满整屏、不内缩、不圆角**(用户 2026-10-15 反馈"最下面还有一条
|
||||
// 有背景色的东西,不是从最底下滑上来的")。
|
||||
//
|
||||
// 之前是"左右 margin 内缩 + 圆角"的**卡片形态** ⇒
|
||||
// ① 列表底部与屏幕底之间留出页面底色;
|
||||
// ② 左右两条底色也会在滚到底时露出来。
|
||||
// ⇒ 白底**通栏到底**,不再做卡片。
|
||||
// ⚠️ 别再用 `margin`/`borderRadius`/`clip` —— 那三个就是"卡片感"的来源。
|
||||
.backgroundColor(FbColors.surface)
|
||||
/* 🔴🔴 v59b(用户 2026-10-18):「名册页面,不好看,太丑了,应该是
|
||||
* 每个人都是圆角矩形,往中间收一点,距离左右都有点距离,
|
||||
* 每个人中间都有一点空隙。这样是很多个圆角矩形平铺下来的。」
|
||||
*
|
||||
* 🔴 真凶:卡片**早就**是圆角矩形了(v51 就做了 `borderRadius` +
|
||||
* `margin`),但**容器也是纯白** ⇒ **白卡压在白底上**,
|
||||
* 圆角和左右收边**全都看不见** —— 看上去就是一整块通栏白。
|
||||
* (这解释了为什么"改过一轮还是丑":改的是卡片的形状,
|
||||
* 而问题在于它没有可对比的背景。)
|
||||
*
|
||||
* ⇒ 容器改成**页面底色(宣纸米色)**,白卡才"浮"得出来;
|
||||
* 外层那个兜底白(见 build 末尾)也一并改掉,否则滚到底
|
||||
* 会从米色突然切回白色。
|
||||
*/
|
||||
.backgroundColor(FbColors.paper)
|
||||
// 🔴🔴 **这里绝对不能再加 `padding({bottom})`**
|
||||
// (用户 2026-10-15:「它的内容是从悬浮框上面滚出来的」)。
|
||||
//
|
||||
@@ -831,9 +837,10 @@ export struct FbPeoplePage {
|
||||
}
|
||||
.width('100%')
|
||||
.layoutWeight(1)
|
||||
// 🔴 外层也铺白底:内容不足一屏时,列表白底铺不到屏幕底,
|
||||
// 这一层就是"兜底的白" —— 不能让页面底色从底部露出来。
|
||||
.backgroundColor(FbColors.surface)
|
||||
/* 兜底底色 = **页面底色**(原来是纯白)。
|
||||
⚠️ 必须与列表容器同色:列表内容不足一屏时,露出来的就是这一层;
|
||||
两层不同色会在底部切出一条突兀的色带(v51 踩过同类问题)。 */
|
||||
.backgroundColor(FbColors.paper)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -916,14 +923,22 @@ export struct FbPeoplePage {
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.padding({ left: 14, right: 14, top: 11, bottom: 11 })
|
||||
// 🔴 用户 2026-10-16:「人员列表项:每一个人员是不是都可以做成一个
|
||||
// **圆角矩形**的形式?」⇒ 每条**独立一张圆角卡**(白底 + 间距),
|
||||
// 不再靠 Divider 连成一大块。
|
||||
.padding({ left: 14, right: 14, top: 12, bottom: 12 })
|
||||
/* 🔴 v59b(用户 2026-10-18):「每个人都是圆角矩形,往中间收一点,
|
||||
* 距离左右都有点距离,每个人中间都有一点空隙。这样是很多个
|
||||
* 圆角矩形平铺下来的。」
|
||||
*
|
||||
* ⚠️ 形状其实**早就是**圆角卡了(v51),用户说"丑"的真凶在容器 ——
|
||||
* 列表容器也是纯白 ⇒ 白卡压白底 ⇒ 圆角/收边**全看不见**。
|
||||
* 已把容器改成页面底色(见 rosterView 的 `backgroundColor`),
|
||||
* 白卡这才"浮"得出来。
|
||||
* ⚠️ 这里的三个数也一起放大了一档(user 明确要"收一点 + 有空隙"):
|
||||
* 左右 16(= 全站 pagePad,与页头对齐)、卡间 10(原来 8,偏挤)、
|
||||
* 圆角 14(原来 10,在 12 的行内边距下 10 显得方)。
|
||||
*/
|
||||
.backgroundColor(FbColors.surface)
|
||||
.borderRadius(FbMetric.radiusS)
|
||||
// ⚠️ 间距放这里(@Builder 不能链式)—— 左右留边 + 卡间空隙
|
||||
.margin({ left: FbMetric.pagePad, right: FbMetric.pagePad, bottom: 8 })
|
||||
.borderRadius(FbMetric.radiusCard)
|
||||
.margin({ left: FbMetric.pagePad, right: FbMetric.pagePad, bottom: 10 })
|
||||
.alignItems(VerticalAlign.Center)
|
||||
// 🔴 点整行 = **拨打这个人的电话**(用户 2026-10-13 / 10-15 明确要求)。
|
||||
// 规则(2026-10-15 用户确认):**有主号打主号**;
|
||||
|
||||
Reference in New Issue
Block a user