v76 旅程:信息铺得开 + 每段行程各自成卡 + 照片可点开 / 视频可播
用户 2026-10-22(四条毛病,同一个根因:信息往一行里挤):
「那个城市……如果一行显不下的话,应该显示在下边一行,把所有的城市全列出来。
就跟那个人员一样,你人员特别多的时候,一行显示不下,就直接往下放就行了。」
「点进详情之后……现在人员显示不下的话,你直接都放在右边,都溢出到这个块外面去了……
应该直接顺着往下铺就行了,所以它长一点无所谓。」
「实际行程它应该也是一段一段的,不要把它整个实际行程放在一块,
就是每一个行程都是一个一个块。然后里面的照片要可以点击查看,视频要能够播放。」
根因不是"忘了加滚动",而是 **`Row` 在 ArkUI 里不换行**:
塞不下的子节点会被压缩、或直接横向溢出父容器。四处都改成
`Flex({ wrap: FlexWrap.Wrap })`。
- `Types.ets`:`FbTripItem` 新增 `cities: string[]`(整串只能截断);
`FbTripNodePhoto` 新增 `mime` / `size`
- `FbParse.parseTrips` 新增 `cityListOf()`:优先用服务端 `cities` 数组,
只给整串时按 `·` 拆回来("显示不全"不再从别的入口漏进来)
- 列表卡:城市从「📍 一行长串 + 省略号」改成一颗颗 chip,日期单独占一行
- 详情页:城市 / 参与的人 / 每段的参与人 全部改 `Flex wrap`
(实测「黑龙江」那趟 5 个人自动排成 2 行,不再溢出卡片)
- **每段行程各自一张卡**:组头退成章节标题(不带卡片底),
`nodeCard` 自己带白底 + 圆角 + 左侧阶段色条(取 `n.stage`)
- 照片:点缩略图开全屏查看器(`PanGesture` 左右滑、上一张/下一张、关闭)
- 视频:按 `mime` 前缀认出视频(`is_image` 只有两态),缩略块 + ▶ 角标,
点开用系统 `Video` 播放(`media.php` 支持 Range,可拖进度条)
🔴 真机抓到的布局 bug:`Stack` 子节点上的 `.align(Alignment.Bottom/TopEnd)`
**完全无效** —— 关闭按钮和翻页条双双掉到屏幕正中。改成铺满的 Column +
`layoutWeight(1)` 撑开,并给控制层 `hitTestBehavior(Transparent)`
保证"点背景关闭"仍穿透。
验证:真机 33/0(含"城市 chip 数 == 统计里个城市"、"相邻行程卡有实际间隙"、
"点视频块起播放器且无放不出来");守卫 953/0;反向验证 181/0
(其中一条注入暴露了我新写断言的假绿,已改成结构化顺序判据)。
This commit is contained in:
@@ -114,22 +114,22 @@ export const FB_DEMO_CINEMAS: string[] = ['家里', '万达影城·李沧店', '
|
||||
export const FB_DEMO_TRIPS: FbTripItem[] = [
|
||||
{
|
||||
id: 1, title: '青岛·崂山 两日', sub: '青岛 · 2 天', dateRange: '2026-10-02 ~ 10-03',
|
||||
nodeCount: 8, doneCount: 8, coverKey: '', city: '青岛', summary: '海边住了两晚,早上赶海、下午爬山。',
|
||||
nodeCount: 8, doneCount: 8, coverKey: '', city: '青岛', cities: ['青岛'], summary: '海边住了两晚,早上赶海、下午爬山。',
|
||||
attendeeCount: 3
|
||||
},
|
||||
{
|
||||
id: 2, title: '烟台海边周末', sub: '烟台 · 2 天', dateRange: '2026-08-15 ~ 08-16',
|
||||
nodeCount: 6, doneCount: 6, coverKey: '', city: '烟台', summary: '带孩子去看海,吃了顿海鲜。',
|
||||
nodeCount: 6, doneCount: 6, coverKey: '', city: '烟台', cities: ['烟台'], summary: '带孩子去看海,吃了顿海鲜。',
|
||||
attendeeCount: 4
|
||||
},
|
||||
{
|
||||
id: 3, title: '国庆西安行', sub: '西安 · 4 天', dateRange: '2025-10-01 ~ 10-04',
|
||||
nodeCount: 12, doneCount: 12, coverKey: '', city: '西安', summary: '兵马俑、城墙、回民街。',
|
||||
nodeCount: 12, doneCount: 12, coverKey: '', city: '西安', cities: ['西安'], summary: '兵马俑、城墙、回民街。',
|
||||
attendeeCount: 3
|
||||
},
|
||||
{
|
||||
id: 4, title: '寒假哈尔滨', sub: '哈尔滨 · 5 天', dateRange: '2026-01-20 ~ 01-24',
|
||||
nodeCount: 0, doneCount: 0, coverKey: '', city: '哈尔滨', summary: '',
|
||||
nodeCount: 0, doneCount: 0, coverKey: '', city: '哈尔滨', cities: ['哈尔滨'], summary: '',
|
||||
attendeeCount: 0
|
||||
}
|
||||
];
|
||||
|
||||
@@ -403,6 +403,15 @@ export interface FbTripItem {
|
||||
* 这个字段**只放城市**,供卡片单独显示「📍 青岛」那一行。
|
||||
*/
|
||||
city: string;
|
||||
/**
|
||||
* 城市列表(已去重,服务端 `cities` 原样)。
|
||||
*
|
||||
* 🔴 v76(用户 2026-10-22):「那个城市……如果一行显不下的话,应该显示在下边一行,
|
||||
* 把所有的城市全列出来。就跟那个人员一样。」
|
||||
* ⇒ 卡片上不再拼成一个长串(那样只能截断),改成**一颗颗 chip 自动换行**。
|
||||
* ⚠️ `city` 保留:有的地方(如按城市搜索)还是想要一个整串。
|
||||
*/
|
||||
cities: string[];
|
||||
/** 简介(网页版列表卡截 80 字显示) */
|
||||
summary: string;
|
||||
/** 同行人数(所有行程参与人的合集,与网页版一致) */
|
||||
@@ -482,8 +491,19 @@ export interface FbTripNodePhoto {
|
||||
key: string;
|
||||
/** 原始文件名(非图片才有意义) */
|
||||
name: string;
|
||||
/** 1 = 图片,可直接铺缩略图 */
|
||||
/** 1 = 图片,可直接铺缩略图(服务端 `is_image`,按内容嗅探得到) */
|
||||
isImage: boolean;
|
||||
/**
|
||||
* 内容嗅探出来的 MIME(服务端 `attachments.mime`)。
|
||||
*
|
||||
* 🔴 v76(用户 2026-10-22):「里面的照片要可以点击查看,视频要能够播放。」
|
||||
* ⇒ 端上第一次需要区分「图片 / 视频 / 其它」,而 `is_image` 只有两态。
|
||||
* ⚠️ 判视频一律用 `mime` 前缀 + 扩展名兜底,**不看 `is_image === false`**
|
||||
* —— 那份 pdf/word 也不是图片,但不是视频。
|
||||
*/
|
||||
mime: string;
|
||||
/** 字节数(0 = 服务端没给) */
|
||||
size: number;
|
||||
}
|
||||
|
||||
/** 旅程详情页右上角的五项统计(服务端 `Trip::summary()`) */
|
||||
|
||||
Reference in New Issue
Block a user