纪念日编辑框:五项文案与形态调整 (#91)

用户 2026-11-05 五点:
  「只记"几月几号,每年自动提醒"这句话,把它去掉。」
  「"叫什么"不应该这么叫,应该换成"纪念日"标题。」
  「"按什么重复"也太复杂了,就写"重复"。」
  「日期右边为什么有个箭头呢?不要。」
  「分类这个地方平铺。关联人这个地方也显示出来:
    这个人已经关联的人是谁?名字、头像。」

① 删掉副标题「只记几月几号,每年自动提醒」
   标题已经说清这是纪念日,副标题在解释"格式",用户不需要看第二遍。

② 「叫什么」→「纪念日」

③ 「按什么重复」→「重复」

④ 日期行去掉右侧 ›
   `FbDateTimeRow` 内部的 `›` 是**写死的**(给"点开会选"的暗示)。
   不用它、改成手画一个与其它字段同形态的框(40 高 / inputBg / radiusS):
   ⚠️ 不动那个组件:它还有自己的标签行、42 高、箭头,三样都与本框不一致;
      硬改成参数化会波及任务/日程/观影几处的用法。
   ⚠️ 点击整框(不只文字)都能开选择器 —— Row 的 onClick。

⑤ 分类改平铺
   横滑 Scroll → `Flex(wrap: FlexWrap.Wrap)`,全部一眼看全。
   ⚠️ 不能用 Row:ArkUI 的 Row 不换行,塞不下会横向溢出
      (任务面板看板 chips 踩过:最后一个被裁掉且点不到)。
   ⚠️ Flex 里 `space` 不生效 ⇒ 间距靠 chip 自己的 margin。

⑥ 关联人改成「头像 + 名字」chips
   改前:一行纯文字(「张三、李四」/「全家的事」)
   改后:换行平铺的 chips,每个 = 24vp 头像 + 名字
   一个都没关联时显示「全家的事」框;下面单独一颗「+ 指定人 / 更换」按钮
   (只点 chips 会让人以为只能取消,看不出能加人 —— 与任务面板
      「负责人」那颗「更换」同一手法)。
   ⚠️ 顺序按 personIds(用户点选顺序)而不是名册顺序,
      否则"刚加的人跑到最后去了",看着像没加上。
   ⚠️ 顺手删掉已无人调用的 peopleText()(520 字符死代码)。

编译通过,已装真机。
This commit is contained in:
2026-11-05 20:50:49 +08:00
parent 93d0e886fb
commit 4963a1b520
+106 -30
View File
@@ -23,6 +23,10 @@ import { FbSheetClose } from './FbSheetClose';
import { FbSheetRing } from './FbSheetRing';
import { FbDateTimeRow, FbDateTimePicker, fbToday } from './FbDateTimeField';
import { FbPersonPickSheet } from './FbPersonPickSheet';
/* #91:关联人 chips 要画头像 / 日期行要格式化中文日期 */
import { FbAvatar } from './Widgets';
import { fbImageSrc } from '../data/FbAttachQueue';
import { fbCnDate } from './FbDateTimeField';
import { FbRosterPerson } from '../data/FbPersonRepo';
import { FB_TOKEN_STORE } from '../data/FbTokenStore';
import { createDay, updateDay, deleteDay, FbDayDraft } from '../data/FbDayRepo';
@@ -94,20 +98,33 @@ export struct FbDayEditSheet {
return idx >= 0 && idx < REPEAT_LABELS.length ? REPEAT_LABELS[idx] : REPEAT_LABELS[0];
}
/** 已选的关联人显示名(「全家的事」= 一个都没选) */
private peopleText(): string {
if (this.personIds.length === 0) {
return '全家的事';
private token(): string {
return FB_TOKEN_STORE.get();
}
const names: string[] = [];
/**
* 已选的关联人(按 `personIds` 的顺序返回,找不到的跳过)。
*
* 🔴 #91(用户 2026-11-05):「关联人这个地方也显示出来:这个人已经关联的人
* 是谁?名字、头像。」
*
* ⚠️ 返回**对象数组**而不是名字字符串:调用方要画头像(`avatar`/`avatarColor`)。
* ⚠️ 原来还有个 `peopleText()` 生成「张三、李四」这种纯文字串 ——
改成 chips 之后**没人用了**,已删。别再写回来:
名字串在人多时要靠省略号截断,看不出「关联了几个」。
* ⚠️ 顺序按 `personIds`(用户在选人弹窗里的点选顺序),
* 不按名册顺序 —— 否则"我刚加的人跑到最后去了",看着像没加上。
*/
private pickedPeople(): FbRosterPerson[] {
const out: FbRosterPerson[] = [];
for (const id of this.personIds) {
const p: FbRosterPerson | undefined =
this.roster.find((x: FbRosterPerson): boolean => x.id === id);
if (p !== undefined) {
names.push(p.shown !== '' ? p.shown : p.name);
out.push(p);
}
}
return names.length > 0 ? names.join('、') : ('已选 ' + this.personIds.length.toString() + ' 人');
return out;
}
/** 分类清单:预置 + 当前值(老数据里的自定义分类不能丢) */
@@ -176,10 +193,10 @@ export struct FbDayEditSheet {
.fontWeight(FontWeight.Bold)
.fontColor(this.accent)
.maxLines(1)
Text('只记几月几号,每年自动提醒')
.fontSize(FbMetric.fontTiny)
.fontColor(FbColors.faint)
.maxLines(1)
/* 🔴 #91(用户 2026-11-05):「只记"几月几号,每年自动提醒"
这句话,把它去掉。」
⇒ 删掉。标题已经说清这是纪念日,这行副标题是解释"格式",
用户不需要看第二遍。 */
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
@@ -210,7 +227,8 @@ export struct FbDayEditSheet {
Column({ space: 14 }) {
// ---- 名称 ----
Column({ space: 6 }) {
this.fieldLb('叫什么')
/* 🔴 #91:「"叫什么"不应该这么叫,应该换成"纪念日"标题。」 */
this.fieldLb('纪念日')
TextInput({ text: this.title, placeholder: '如:结婚纪念日' })
.placeholderColor(FbColors.faint)
.placeholderFont({ size: FbMetric.fontSmall })
@@ -231,7 +249,8 @@ export struct FbDayEditSheet {
// ---- 重复方式 ----
Column({ space: 6 }) {
this.fieldLb('按什么重复')
/* 🔴 #91:「"按什么重复"也太复杂了,就写"重复"。」 */
this.fieldLb('重复')
Row({ space: 8 }) {
ForEach(REPEAT_KEYS, (k: string, idx: number) => {
Text(this.repeatLabel(idx))
@@ -253,14 +272,28 @@ export struct FbDayEditSheet {
// ---- 日期 ----
Column({ space: 6 }) {
this.fieldLb('日期')
FbDateTimeRow({
label: '',
date: this.pickDate,
allDay: true,
accent: this.accent,
onTap: (): void => {
this.pickOpen = true;
/* 🔴 #91(用户 2026-11-05):「日期右边为什么有个箭头呢?不要。」
`FbDateTimeRow` 内部的 `›` 是写死的(给"点开会选"的暗示),
这里不能用它 —— 改成直接画一个与其它控件同形态的框。
⚠️ 不用 `FbDateTimeRow` 而手画:那个组件还有自己的标签行、
42 高、箭头,三样都与本框的字段样式不一致,
硬改组件参数会波及任务/日程/观影那边的用法。
⚠️ 点击整框(不只是文字)都要能开选择器 —— 用 Row 的 onClick,
与「截止」「负责人」那些可点行同一手法。 */
Row({ space: 8 }) {
Text(fbCnDate(this.pickDate))
.fontSize(FbMetric.fontSmall)
.fontColor(FbColors.ink)
.layoutWeight(1)
}
.width('100%')
.height(40)
.padding({ left: 12, right: 12 })
.backgroundColor(FbColors.inputBg)
.borderRadius(FbMetric.radiusS)
.alignItems(VerticalAlign.Center)
.onClick((): void => {
this.pickOpen = true;
})
}
.width('100%')
@@ -269,8 +302,12 @@ export struct FbDayEditSheet {
// ---- 分类 ----
Column({ space: 6 }) {
this.fieldLb('分类')
Scroll() {
Row({ space: 8 }) {
/* 🔴 #91(用户 2026-11-05):「分类这个地方平铺。」
⇒ 从横滑改成 **Flex(wrap) 换行平铺**,全部一眼看全。
⚠️ 不能用 `Row`:ArkUI 的 Row 不换行,塞不下会横向溢出
(任务面板的看板 chips 踩过:最后一个被裁掉且点不到)。
⚠️ Flex 里 `space` 不生效 ⇒ 间距靠每个 chip 的 margin。 */
Flex({ wrap: FlexWrap.Wrap }) {
ForEach(this.kinds(), (k: string) => {
Text(k)
.fontSize(FbMetric.fontTiny)
@@ -278,29 +315,29 @@ export struct FbDayEditSheet {
.padding({ left: 10, right: 10, top: 6, bottom: 6 })
.backgroundColor(this.kind === k ? this.accent : FbColors.inputBg)
.borderRadius(FbMetric.radiusPill)
.margin({ right: 8, bottom: 8 })
.onClick((): void => {
// 再点一下 = 取消分类(不分类是合法状态)
this.kind = this.kind === k ? '' : k;
})
}, (k: string): string => 'kd_' + k)
}
.padding({ right: 4 })
}
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
.width('100%')
}
.width('100%')
.alignItems(HorizontalAlign.Start)
// ---- 关联人 ----
/* 🔴 #91(用户 2026-11-05):「关联人这个地方也显示出来:
这个人已经关联的人是谁?名字、头像。」
⇒ 从"一行纯文字"改成**头像 + 名字的 chip 列表**,
一眼看出关联了谁。一个都没关联时显示「全家的事」(语义同前)。 */
Column({ space: 6 }) {
this.fieldLb('关联人')
Text(this.peopleText())
if (this.personIds.length === 0) {
Text('全家的事')
.fontSize(FbMetric.fontSmall)
.fontColor(this.personIds.length > 0 ? FbColors.ink : FbColors.muted)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.fontColor(FbColors.muted)
.width('100%')
.height(40)
.padding({ left: 12, right: 12 })
@@ -309,6 +346,45 @@ export struct FbDayEditSheet {
.onClick((): void => {
this.personPickOpen = true;
})
} else {
/* 多个关联人:换行平铺的 chips(同分类的排法) */
Flex({ wrap: FlexWrap.Wrap }) {
ForEach(this.pickedPeople(), (p: FbRosterPerson) => {
Row({ space: 6 }) {
FbAvatar({
name: p.shown !== '' ? p.shown : p.name,
color: p.avatarColor !== '' ? p.avatarColor : this.accent,
imageUrl: p.avatar !== '' ? fbImageSrc(p.avatar, this.token()) : '',
dia: 24,
fontSizeVp: 11
})
Text(p.shown !== '' ? p.shown : p.name)
.fontSize(FbMetric.fontSmall)
.fontColor(FbColors.ink)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.constraintSize({ maxWidth: 110 })
}
.padding({ left: 4, right: 10, top: 4, bottom: 4 })
.backgroundColor(FbColors.inputBg)
.borderRadius(FbMetric.radiusPill)
.margin({ right: 8, bottom: 8 })
}, (p: FbRosterPerson): string => 'pp_' + p.id.toString())
}
.width('100%')
}
/* 「更换」入口单独一行:与任务面板「负责人」那颗「更换」按钮同一手法
(chips 本身可点,但只点 chips 会让人以为只能取消,看不出能加人)。 */
Text(this.personIds.length === 0 ? '+ 指定人' : '更换')
.fontSize(FbMetric.fontTiny)
.fontWeight(FontWeight.Medium)
.fontColor(this.accent)
.padding({ left: 10, right: 10, top: 6, bottom: 6 })
.backgroundColor(fbAlpha(this.accent, 0.10))
.borderRadius(FbMetric.radiusPill)
.onClick((): void => {
this.personPickOpen = true;
})
}
.width('100%')
.alignItems(HorizontalAlign.Start)