diff --git a/entry/src/main/ets/components/FbDayEditSheet.ets b/entry/src/main/ets/components/FbDayEditSheet.ets index 54438ac..1ba3723 100644 --- a/entry/src/main/ets/components/FbDayEditSheet.ets +++ b/entry/src/main/ets/components/FbDayEditSheet.ets @@ -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 '全家的事'; - } - const names: string[] = []; + private token(): string { + return FB_TOKEN_STORE.get(); + } + + /** + * 已选的关联人(按 `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,43 +302,86 @@ export struct FbDayEditSheet { // ---- 分类 ---- Column({ space: 6 }) { this.fieldLb('分类') - Scroll() { - Row({ space: 8 }) { - ForEach(this.kinds(), (k: string) => { - Text(k) - .fontSize(FbMetric.fontTiny) - .fontColor(this.kind === k ? '#FFFFFF' : FbColors.muted) - .padding({ left: 10, right: 10, top: 6, bottom: 6 }) - .backgroundColor(this.kind === k ? this.accent : FbColors.inputBg) - .borderRadius(FbMetric.radiusPill) - .onClick((): void => { - // 再点一下 = 取消分类(不分类是合法状态) - this.kind = this.kind === k ? '' : k; - }) - }, (k: string): string => 'kd_' + k) - } - .padding({ right: 4 }) + /* 🔴 #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) + .fontColor(this.kind === k ? '#FFFFFF' : FbColors.muted) + .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) } - .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()) - .fontSize(FbMetric.fontSmall) - .fontColor(this.personIds.length > 0 ? FbColors.ink : FbColors.muted) - .maxLines(1) - .textOverflow({ overflow: TextOverflow.Ellipsis }) + if (this.personIds.length === 0) { + Text('全家的事') + .fontSize(FbMetric.fontSmall) + .fontColor(FbColors.muted) + .width('100%') + .height(40) + .padding({ left: 12, right: 12 }) + .backgroundColor(FbColors.inputBg) + .borderRadius(FbMetric.radiusS) + .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%') - .height(40) - .padding({ left: 12, right: 12 }) - .backgroundColor(FbColors.inputBg) - .borderRadius(FbMetric.radiusS) + } + /* 「更换」入口单独一行:与任务面板「负责人」那颗「更换」按钮同一手法 + (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; })