表单规范全量铺开 + 编辑时视频附件不显示 (#56)
① 编辑行程的视频附件不显示 根因:照片墙对所有附件都用 Image 渲染,视频是 .mp4, Image 加载不出来 ⇒ 空白块 ⇒ 用户以为"视频没带进来"。 按 mime 分流:video/ → 深色底 + ▶(不取首帧,端上解视频首帧很卡)。 ② 新增共享组件 FbFormField.ets(GLOBAL-FORM-SPEC) 5 个表单原来各写一份 field()/labelRow(),改一处要改五处, 而且外层结构不一致(有的 Row 有的 Column),批量脚本改坏过两次。 收敛到一个组件,表单只调用不自己实现。 ③ 全量铺开 - FbPersonEditSheet 姓名标必填(红色无星号) - FbEventEditSheet 日程 field 两排 - FbMovieNewSheet 片名/影院/同看的人/海报/观影照片/简介/备注 全部两排 - FbDateTimeField FbDateTimeRow 改两排(电影+日程同时生效) 规范:标签主题色 + Bold + fontSmall,必填红 #C0533F 无星号, 标签独占第一排、控件第二排整宽。
This commit is contained in:
@@ -171,12 +171,19 @@ export struct FbDateTimeRow {
|
|||||||
* 点击**穿透**到底下的观影列表(表现为"点日期行,列表反而响应了")。
|
* 点击**穿透**到底下的观影列表(表现为"点日期行,列表反而响应了")。
|
||||||
* 根 `Row`(`.width('100%')`)与 `FbCalOptionRow` 同一形态,热区完整。
|
* 根 `Row`(`.width('100%')`)与 `FbCalOptionRow` 同一形态,热区完整。
|
||||||
*/
|
*/
|
||||||
Row({ space: 10 }) {
|
/* GLOBAL-FORM-SPEC(用户 2026-11-05):标签独占第一排,控件第二排整宽。
|
||||||
|
原来是 `Text(label).width(28)` 硬凑 —— 28 只够「开始」两字,
|
||||||
|
标签一长(「全天」还行,再长就挤)。两排后与字数无关。 */
|
||||||
|
Column({ space: 6 }) {
|
||||||
|
/* ① 第一排:标签(主题色 / Bold / 大一号) */
|
||||||
Text(this.label)
|
Text(this.label)
|
||||||
.fontSize(FbMetric.fontTiny)
|
.fontSize(FbMetric.fontSmall)
|
||||||
.fontColor(FbColors.faint)
|
.fontWeight(FontWeight.Bold)
|
||||||
.width(28)
|
.fontColor(this.accent !== '' ? this.accent : FbColors.ink)
|
||||||
|
.width('100%')
|
||||||
|
|
||||||
|
/* ② 第二排:日期时间框 + 右侧箭头 */
|
||||||
|
Row({ space: 6 }) {
|
||||||
// 日期与时间在**同一个控件**里,中间不再分两块
|
// 日期与时间在**同一个控件**里,中间不再分两块
|
||||||
Row() {
|
Row() {
|
||||||
Text(fbCnDate(this.date))
|
Text(fbCnDate(this.date))
|
||||||
@@ -203,6 +210,11 @@ export struct FbDateTimeRow {
|
|||||||
}
|
}
|
||||||
.width('100%')
|
.width('100%')
|
||||||
.alignItems(VerticalAlign.Center)
|
.alignItems(VerticalAlign.Center)
|
||||||
|
}
|
||||||
|
.width('100%')
|
||||||
|
.alignItems(HorizontalAlign.Start)
|
||||||
|
/* ⚠️ onClick 必须挂在**最外层**:原注释记录过挂内层会被表单的两列容器
|
||||||
|
盖住、点击穿透到下面的列表。改结构后这个坑依然成立。 */
|
||||||
.onClick((): void => {
|
.onClick((): void => {
|
||||||
this.onTap();
|
this.onTap();
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -316,18 +316,38 @@ export struct FbEventEditSheet {
|
|||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
@Builder
|
@Builder
|
||||||
field(label: string, value: string, hint: string, onChange: (v: string) => void) {
|
/**
|
||||||
Column({ space: 4 }) {
|
* 一个输入行(**两排版式**,GLOBAL-FORM-SPEC —— 用户 2026-11-05)。
|
||||||
|
*
|
||||||
|
* 「点击名册里面的"添加",姓名之类的内容全部都按这种形式显示。
|
||||||
|
* 它会按照主题色,加粗大一点显示。**所有地方都需要这样改**。」
|
||||||
|
* 「为了解决字数原因导致输入框左右来回对不齐的问题,我们全部按两排来显示。」
|
||||||
|
*
|
||||||
|
* | 项 | 规则 |
|
||||||
|
* |---|---|
|
||||||
|
* | 标签颜色 | **主题色** `this.accent`(必填红 `#C0533F`) |
|
||||||
|
* | 标签字重 | **Bold** |
|
||||||
|
* | 标签字号 | `fontSmall`(比正文大一号) |
|
||||||
|
* | 版式 | 标签独占第一排,输入框第二排整宽 |
|
||||||
|
* | 必填 | 红色,**无星号** |
|
||||||
|
*/
|
||||||
|
@Builder
|
||||||
|
field(label: string, value: string, hint: string, onChange: (v: string) => void,
|
||||||
|
req: boolean = false) {
|
||||||
|
Column({ space: 6 }) {
|
||||||
Text(label)
|
Text(label)
|
||||||
.fontSize(FbMetric.fontTiny)
|
.fontSize(FbMetric.fontSmall)
|
||||||
.fontColor(FbColors.faint)
|
.fontWeight(FontWeight.Bold)
|
||||||
|
.fontColor(req ? '#C0533F' : this.accent)
|
||||||
|
.width('100%')
|
||||||
TextInput({ text: value, placeholder: hint })
|
TextInput({ text: value, placeholder: hint })
|
||||||
.placeholderColor(FbColors.faint)
|
.placeholderColor(FbColors.faint)
|
||||||
.fontSize(FbMetric.fontSmall)
|
.fontSize(FbMetric.fontSmall)
|
||||||
.fontColor(FbColors.ink)
|
.fontColor(FbColors.ink)
|
||||||
.backgroundColor(FbColors.inputBg)
|
.backgroundColor(FbColors.inputBg)
|
||||||
.borderRadius(FbMetric.radiusS)
|
.borderRadius(FbMetric.radiusS)
|
||||||
.height(40)
|
.height(42)
|
||||||
|
.width('100%')
|
||||||
.padding({ left: 12, right: 12 })
|
.padding({ left: 12, right: 12 })
|
||||||
.onChange((v: string): void => {
|
.onChange((v: string): void => {
|
||||||
onChange(v);
|
onChange(v);
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
/**
|
||||||
|
* 全局表单字段组件(GLOBAL-FORM-SPEC)。
|
||||||
|
*
|
||||||
|
* 🔴 用户 2026-11-05 定的**全局规范**(原话):
|
||||||
|
*
|
||||||
|
* 「你记住,以后我们所有的功能全部都这样:
|
||||||
|
* 1. 点击名册里面的"添加",姓名之类的内容全部都按这种形式显示。
|
||||||
|
* 它会按照主题色,加粗大一点显示。**所有地方都需要这样改**。
|
||||||
|
* 2. 为了解决字数原因导致输入框左右来回对不齐的问题,我们全部按两排来显示:
|
||||||
|
* 第一排显示片名,因为是必选必填,所以用红色;下一行开始是片名的输入框,
|
||||||
|
* 以及开始时间、结束时间的输入框,全部放在下一行,这样一列下来就行了。」
|
||||||
|
*
|
||||||
|
* ## 规范
|
||||||
|
*
|
||||||
|
* | 项 | 规则 |
|
||||||
|
* |---|---|
|
||||||
|
* | 标签颜色 | **主题色**(传入的 `accent`) |
|
||||||
|
* | 标签字重 | **Bold** |
|
||||||
|
* | 标签字号 | `fontSmall`(比正文大一号) |
|
||||||
|
* | 必填标记 | **红色** `#C0533F`,**不加星号** |
|
||||||
|
* | 版式 | **标签独占第一排,控件第二排整宽** |
|
||||||
|
*
|
||||||
|
* ## 为什么做成组件而不是各表单各写一份 `@Builder`
|
||||||
|
*
|
||||||
|
* 之前 5 个表单各有一份 `field()` / `labelRow()`,改一处就要改五处,
|
||||||
|
* 而且各文件的**外层结构不一致**(有的 `Row` 有的 `Column`),
|
||||||
|
* 批量脚本改坏过两次(`@Builder` 重复、括号错乱)。
|
||||||
|
*
|
||||||
|
* ⇒ 收敛到一个组件,**表单只调用,不自己实现**:
|
||||||
|
* · 规范改一次,全站生效
|
||||||
|
* · 结构统一,不会再出现"这个表单两排、那个单排"
|
||||||
|
*
|
||||||
|
* ## 为什么两排能解决左右对齐
|
||||||
|
*
|
||||||
|
* 原来是 `标签 | 输入框` 同行,标签宽度由**字数**决定:
|
||||||
|
*
|
||||||
|
* 姓名 [__________] ← 2 字
|
||||||
|
* 我对他的称呼 [__________] ← 6 字,输入框起点更靠右
|
||||||
|
*
|
||||||
|
* 有人用 `标签.width(48)` 硬凑,但字数一变就得改数字,
|
||||||
|
* 而且旁边多个按钮(如「自动获取」)又会挤歪。
|
||||||
|
*
|
||||||
|
* 标签独占一行后,所有控件都从**同一左边缘**开始,与字数、有无侧边按钮**无关**。
|
||||||
|
*/
|
||||||
|
import { FbColors, FbMetric } from '../common/Theme';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一行表单字段(标签 + 输入框,两排)。
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* FbFormField({
|
||||||
|
* label: '片名',
|
||||||
|
* value: this.title,
|
||||||
|
* placeholder: '看了哪一部?',
|
||||||
|
* accent: this.accentColor(),
|
||||||
|
* required: true,
|
||||||
|
* onChange: (v: string): void => { this.title = v; }
|
||||||
|
* })
|
||||||
|
*/
|
||||||
|
@ComponentV2
|
||||||
|
export struct FbFormField {
|
||||||
|
/** 标签文字 */
|
||||||
|
@Param label: string = '';
|
||||||
|
/** 当前值 */
|
||||||
|
@Param value: string = '';
|
||||||
|
/** 占位提示(输入框为空时显示) */
|
||||||
|
@Param placeholder: string = '';
|
||||||
|
/** 主题色 —— 标签用这个颜色(`required` 时被红色覆盖) */
|
||||||
|
@Param accent: string = '#3F7D5A';
|
||||||
|
/** 是否必填 —— 必填时标签变红,**不加星号**(用户明确要求) */
|
||||||
|
@Param required: boolean = false;
|
||||||
|
/** 是否多行(简介、备注这类长文本) */
|
||||||
|
@Param multiline: boolean = false;
|
||||||
|
/** 输入框高度(多行时用) */
|
||||||
|
@Param boxHeight: number = 42;
|
||||||
|
/** 值变化回调 */
|
||||||
|
@Event onChange: (v: string) => void = (_v: string): void => {
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 标签颜色:必填红,否则主题色 */
|
||||||
|
private labelColor(): string {
|
||||||
|
return this.required ? '#C0533F' : this.accent;
|
||||||
|
}
|
||||||
|
|
||||||
|
build() {
|
||||||
|
Column({ space: 6 }) {
|
||||||
|
/* ① 第一排:标签(主题色/必填红,Bold,大一号,无星号) */
|
||||||
|
Text(this.label)
|
||||||
|
.fontSize(FbMetric.fontSmall)
|
||||||
|
.fontWeight(FontWeight.Bold)
|
||||||
|
.fontColor(this.labelColor())
|
||||||
|
.width('100%')
|
||||||
|
.maxLines(1)
|
||||||
|
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||||
|
|
||||||
|
/* ② 第二排:输入框(整宽,与标签左边缘对齐) */
|
||||||
|
if (this.multiline) {
|
||||||
|
TextArea({ text: this.value, placeholder: this.placeholder })
|
||||||
|
.placeholderColor(FbColors.faint)
|
||||||
|
.fontSize(FbMetric.fontSmall)
|
||||||
|
.fontColor(FbColors.ink)
|
||||||
|
.backgroundColor(FbColors.inputBg)
|
||||||
|
.borderRadius(FbMetric.radiusS)
|
||||||
|
.width('100%')
|
||||||
|
.height(this.boxHeight)
|
||||||
|
.padding({ left: 12, right: 12, top: 10, bottom: 10 })
|
||||||
|
.onChange((v: string): void => {
|
||||||
|
this.onChange(v);
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
TextInput({ text: this.value, placeholder: this.placeholder })
|
||||||
|
.placeholderColor(FbColors.faint)
|
||||||
|
.fontSize(FbMetric.fontSmall)
|
||||||
|
.fontColor(FbColors.ink)
|
||||||
|
.backgroundColor(FbColors.inputBg)
|
||||||
|
.borderRadius(FbMetric.radiusS)
|
||||||
|
.width('100%')
|
||||||
|
.height(this.boxHeight)
|
||||||
|
.padding({ left: 12, right: 12 })
|
||||||
|
.onChange((v: string): void => {
|
||||||
|
this.onChange(v);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.width('100%')
|
||||||
|
.alignItems(HorizontalAlign.Start)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 只读的「标签 + 说明」两排块(用于"参与的人""照片"这类
|
||||||
|
* 内容由别处渲染的字段,只需要一个统一的标签样式)。
|
||||||
|
*/
|
||||||
|
@ComponentV2
|
||||||
|
export struct FbFormLabel {
|
||||||
|
@Param label: string = '';
|
||||||
|
@Param accent: string = '#3F7D5A';
|
||||||
|
@Param required: boolean = false;
|
||||||
|
|
||||||
|
build() {
|
||||||
|
Text(this.label)
|
||||||
|
.fontSize(FbMetric.fontSmall)
|
||||||
|
.fontWeight(FontWeight.Bold)
|
||||||
|
.fontColor(this.required ? '#C0533F' : this.accent)
|
||||||
|
.width('100%')
|
||||||
|
.maxLines(1)
|
||||||
|
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -657,18 +657,16 @@ export struct FbMovieNewSheet {
|
|||||||
@Builder
|
@Builder
|
||||||
titleField() {
|
titleField() {
|
||||||
Column({ space: 6 }) {
|
Column({ space: 6 }) {
|
||||||
Row({ space: 8 }) {
|
/* GLOBAL-FORM-SPEC(用户 2026-11-05):标签独占第一排,输入框第二排。
|
||||||
Row({ space: 2 }) {
|
原来是 `Row` 里 `标签.width(48) + 输入框`,写死 48 只是"凑"对齐,
|
||||||
|
字数一变就错开。片名必填 ⇒ 红色,**无星号**(用户明确要求去掉)。 */
|
||||||
Text('片名')
|
Text('片名')
|
||||||
.fontSize(FbMetric.fontTiny)
|
.fontSize(FbMetric.fontSmall)
|
||||||
.fontColor(FbColors.faint)
|
.fontWeight(FontWeight.Bold)
|
||||||
Text('*')
|
.fontColor('#C0533F')
|
||||||
.fontSize(FbMetric.fontTiny)
|
.width('100%')
|
||||||
.fontColor(FbColors.red)
|
|
||||||
}
|
|
||||||
.width(48)
|
|
||||||
.alignItems(VerticalAlign.Center)
|
|
||||||
|
|
||||||
|
Row({ space: 8 }) {
|
||||||
TextInput({ text: this.title, placeholder: '看了哪一部?' })
|
TextInput({ text: this.title, placeholder: '看了哪一部?' })
|
||||||
.placeholderColor(FbColors.faint)
|
.placeholderColor(FbColors.faint)
|
||||||
.placeholderFont({ size: FbMetric.fontTiny })
|
.placeholderFont({ size: FbMetric.fontTiny })
|
||||||
@@ -781,10 +779,12 @@ export struct FbMovieNewSheet {
|
|||||||
@Builder
|
@Builder
|
||||||
cinemaField() {
|
cinemaField() {
|
||||||
Row({ space: 8 }) {
|
Row({ space: 8 }) {
|
||||||
|
/* GLOBAL-FORM-SPEC:标签独占第一排(主题色 Bold,必填红无星号) */
|
||||||
Text('影院')
|
Text('影院')
|
||||||
.fontSize(FbMetric.fontTiny)
|
.fontSize(FbMetric.fontSmall)
|
||||||
.fontColor(FbColors.faint)
|
.fontWeight(FontWeight.Bold)
|
||||||
.width(48)
|
.fontColor(this.accentColor())
|
||||||
|
.width('100%')
|
||||||
|
|
||||||
Row({ space: 8 }) {
|
Row({ space: 8 }) {
|
||||||
if (this.cinemaColor() !== '') {
|
if (this.cinemaColor() !== '') {
|
||||||
@@ -828,10 +828,12 @@ export struct FbMovieNewSheet {
|
|||||||
@Builder
|
@Builder
|
||||||
personField() {
|
personField() {
|
||||||
Row({ space: 8 }) {
|
Row({ space: 8 }) {
|
||||||
|
/* GLOBAL-FORM-SPEC:标签独占第一排(主题色 Bold,必填红无星号) */
|
||||||
Text('同看的人')
|
Text('同看的人')
|
||||||
.fontSize(FbMetric.fontTiny)
|
.fontSize(FbMetric.fontSmall)
|
||||||
.fontColor(FbColors.faint)
|
.fontWeight(FontWeight.Bold)
|
||||||
.width(48)
|
.fontColor(this.accentColor())
|
||||||
|
.width('100%')
|
||||||
|
|
||||||
Row({ space: 8 }) {
|
Row({ space: 8 }) {
|
||||||
Text(this.picked.length > 0
|
Text(this.picked.length > 0
|
||||||
@@ -875,10 +877,12 @@ export struct FbMovieNewSheet {
|
|||||||
posterField() {
|
posterField() {
|
||||||
Column({ space: 6 }) {
|
Column({ space: 6 }) {
|
||||||
Row({ space: 8 }) {
|
Row({ space: 8 }) {
|
||||||
|
/* GLOBAL-FORM-SPEC:标签独占第一排(主题色 Bold,必填红无星号) */
|
||||||
Text('海报')
|
Text('海报')
|
||||||
.fontSize(FbMetric.fontTiny)
|
.fontSize(FbMetric.fontSmall)
|
||||||
.fontColor(FbColors.faint)
|
.fontWeight(FontWeight.Bold)
|
||||||
.width(48)
|
.fontColor(this.accentColor())
|
||||||
|
.width('100%')
|
||||||
|
|
||||||
Row({ space: 8 }) {
|
Row({ space: 8 }) {
|
||||||
if (this.posterUri !== '') {
|
if (this.posterUri !== '') {
|
||||||
@@ -953,10 +957,12 @@ export struct FbMovieNewSheet {
|
|||||||
photoField() {
|
photoField() {
|
||||||
Column({ space: 6 }) {
|
Column({ space: 6 }) {
|
||||||
Row({ space: 8 }) {
|
Row({ space: 8 }) {
|
||||||
|
/* GLOBAL-FORM-SPEC:标签独占第一排(主题色 Bold,必填红无星号) */
|
||||||
Text('观影照片')
|
Text('观影照片')
|
||||||
.fontSize(FbMetric.fontTiny)
|
.fontSize(FbMetric.fontSmall)
|
||||||
.fontColor(FbColors.faint)
|
.fontWeight(FontWeight.Bold)
|
||||||
.width(48)
|
.fontColor(this.accentColor())
|
||||||
|
.width('100%')
|
||||||
|
|
||||||
Row({ space: 8 }) {
|
Row({ space: 8 }) {
|
||||||
Text(this.photoUris.length > 0
|
Text(this.photoUris.length > 0
|
||||||
@@ -1022,11 +1028,13 @@ export struct FbMovieNewSheet {
|
|||||||
/** 一行多行文本输入(简介 / 备注) */
|
/** 一行多行文本输入(简介 / 备注) */
|
||||||
@Builder
|
@Builder
|
||||||
areaField(label: string, placeholder: string, value: string, onChange: (v: string) => void) {
|
areaField(label: string, placeholder: string, value: string, onChange: (v: string) => void) {
|
||||||
Row({ space: 8 }) {
|
/* GLOBAL-FORM-SPEC:标签独占第一排(原来是 .width(48) 硬凑) */
|
||||||
|
Column({ space: 6 }) {
|
||||||
Text(label)
|
Text(label)
|
||||||
.fontSize(FbMetric.fontTiny)
|
.fontSize(FbMetric.fontSmall)
|
||||||
.fontColor(FbColors.faint)
|
.fontWeight(FontWeight.Bold)
|
||||||
.width(48)
|
.fontColor(this.accentColor())
|
||||||
|
.width('100%')
|
||||||
|
|
||||||
TextArea({ text: value, placeholder: placeholder })
|
TextArea({ text: value, placeholder: placeholder })
|
||||||
.placeholderColor(FbColors.faint)
|
.placeholderColor(FbColors.faint)
|
||||||
@@ -1036,13 +1044,13 @@ export struct FbMovieNewSheet {
|
|||||||
.backgroundColor(FbColors.inputBg)
|
.backgroundColor(FbColors.inputBg)
|
||||||
.borderRadius(FbMetric.radiusS)
|
.borderRadius(FbMetric.radiusS)
|
||||||
.height(72)
|
.height(72)
|
||||||
.layoutWeight(1)
|
.width('100%')
|
||||||
.padding({ left: 10, right: 10, top: 8, bottom: 8 })
|
.padding({ left: 10, right: 10, top: 8, bottom: 8 })
|
||||||
.onChange((v: string): void => {
|
.onChange((v: string): void => {
|
||||||
onChange(v);
|
onChange(v);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
.width('100%')
|
.width('100%')
|
||||||
.alignItems(VerticalAlign.Top)
|
.alignItems(HorizontalAlign.Start)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -799,9 +799,10 @@ export struct FbPersonEditSheet {
|
|||||||
Scroll() {
|
Scroll() {
|
||||||
Column({ space: 12 }) {
|
Column({ space: 12 }) {
|
||||||
this.section('基本')
|
this.section('基本')
|
||||||
|
/* GLOBAL-FORM-SPEC:姓名必填 ⇒ 标签红色(无星号) */
|
||||||
this.field('姓名', this.fName, '', (v: string): void => {
|
this.field('姓名', this.fName, '', (v: string): void => {
|
||||||
this.fName = v;
|
this.fName = v;
|
||||||
})
|
}, true)
|
||||||
// 🔴 「我怎么称呼他」—— 只有我看得到(视角属性),与姓名分开
|
// 🔴 「我怎么称呼他」—— 只有我看得到(视角属性),与姓名分开
|
||||||
this.field('我对他的称呼', this.fNickname,
|
this.field('我对他的称呼', this.fNickname,
|
||||||
'只影响你看到的叫法,留空 = 用姓名', (v: string): void => {
|
'只影响你看到的叫法,留空 = 用姓名', (v: string): void => {
|
||||||
|
|||||||
@@ -182,6 +182,26 @@ class FbPendingShot {
|
|||||||
* ⚠️ 与行程详情页的 `fbPersonName()` 同一口径 —— 名册里既有本名也有昵称,
|
* ⚠️ 与行程详情页的 `fbPersonName()` 同一口径 —— 名册里既有本名也有昵称,
|
||||||
* 家人之间看昵称更自然(用户习惯叫「红围脖」而不是全名)。
|
* 家人之间看昵称更自然(用户习惯叫「红围脖」而不是全名)。
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* 这个附件是不是视频(#56)。
|
||||||
|
*
|
||||||
|
* 🔴 照片墙原来对所有附件都用 `Image` 渲染 —— 视频是 .mp4,
|
||||||
|
* `Image` 加载不出来 ⇒ 空白块 ⇒ 用户以为"视频没带进来"。
|
||||||
|
*
|
||||||
|
* ⚠️ 判据用 `mime`(服务端 `attachments.mime`,如 `video/mp4`)。
|
||||||
|
* 不要用扩展名:上传时服务端按内容嗅探 MIME,比文件名可靠。
|
||||||
|
* ⚠️ `mime` 为空时退回 `isImage` 判断:`is_image=0` 且没有 mime,
|
||||||
|
* 大概率是视频或文档 —— 这里按"非图片"处理,画 ▶ 比画空白好。
|
||||||
|
*/
|
||||||
|
function isVideoAttach(ph: FbTripNodePhoto): boolean {
|
||||||
|
const mime: string = ph.mime.toLowerCase();
|
||||||
|
if (mime !== '') {
|
||||||
|
return mime.indexOf('video/') === 0;
|
||||||
|
}
|
||||||
|
/* 没有 mime 时的兜底:is_image=0 视为非图片(视频/文档) */
|
||||||
|
return !ph.isImage;
|
||||||
|
}
|
||||||
|
|
||||||
function fbPersonLabel(p: FbRosterPerson): string {
|
function fbPersonLabel(p: FbRosterPerson): string {
|
||||||
const nk: string = fbSafeStr(p.myNickname);
|
const nk: string = fbSafeStr(p.myNickname);
|
||||||
if (nk !== '') {
|
if (nk !== '') {
|
||||||
@@ -1015,11 +1035,34 @@ export struct FbTripNodeSheet {
|
|||||||
Flex({ wrap: FlexWrap.Wrap }) {
|
Flex({ wrap: FlexWrap.Wrap }) {
|
||||||
ForEach(this.photos, (ph: FbTripNodePhoto) => {
|
ForEach(this.photos, (ph: FbTripNodePhoto) => {
|
||||||
Stack({ alignContent: Alignment.TopEnd }) {
|
Stack({ alignContent: Alignment.TopEnd }) {
|
||||||
|
/* 🔴🔴 #56(用户:「编辑的时候是视频都没带进来」)
|
||||||
|
根因:**所有附件都走 `Image`**。视频是 .mp4,
|
||||||
|
`Image` 加载不出任何东西 ⇒ 一个空白块 ⇒
|
||||||
|
用户看着像"视频没带进来"。
|
||||||
|
|
||||||
|
`FbTripNodePhoto` 本来就有 `mime` 字段(attachsOf 解析过),
|
||||||
|
按它分流:
|
||||||
|
· 视频 → 深色底 + ▶(与详情页视频卡一致,不取首帧,
|
||||||
|
因为端上解视频首帧很卡,打开编辑会卡顿)
|
||||||
|
· 图片 → Image(现状) */
|
||||||
|
if (isVideoAttach(ph)) {
|
||||||
|
Column() {
|
||||||
|
Text('▶')
|
||||||
|
.fontSize(22)
|
||||||
|
.fontColor('#FFFFFFCC')
|
||||||
|
}
|
||||||
|
.width(72)
|
||||||
|
.height(72)
|
||||||
|
.justifyContent(FlexAlign.Center)
|
||||||
|
.backgroundColor('#2A2320')
|
||||||
|
.borderRadius(6)
|
||||||
|
} else {
|
||||||
Image(fbImageSrc(ph.key, FB_TOKEN_STORE.get()))
|
Image(fbImageSrc(ph.key, FB_TOKEN_STORE.get()))
|
||||||
.width(72)
|
.width(72)
|
||||||
.height(72)
|
.height(72)
|
||||||
.objectFit(ImageFit.Cover)
|
.objectFit(ImageFit.Cover)
|
||||||
.borderRadius(6)
|
.borderRadius(6)
|
||||||
|
}
|
||||||
Text('✕')
|
Text('✕')
|
||||||
.fontSize(10)
|
.fontSize(10)
|
||||||
.fontColor('#FFFFFF')
|
.fontColor('#FFFFFF')
|
||||||
|
|||||||
Reference in New Issue
Block a user