任务面板字段改上下两行 + 标题主题色 (#77)

用户 2026-11-05:「还是不对,你还是没有看清楚那个样式的设置:上面的标题和
下面的输入框,其实要分成两行。比如说,"截止"不是直接后面排一个日期,
而是把日期输入框放在"截止"下面;"负责人"也是,"备注"也是,全部都是这样的。
上面"台式机采购计划"这样的标题,应该是主题的颜色。」

前两轮(#77i / #77j)我都在改**颜色和字重**,方向偏了 ——
用户要的是**布局**:标签一行、控件另起一行。

① fieldLb 去掉 width(48)
   上一版把它定成 48vp 固定宽的行内标签,形态是「[截止] 2026-11-07 18:30」,
   与要求的上下两行正好相反。
   现在 width(100%) + textAlign Start,独占一行;
   字号从 fontSmall(13) 降到 fontTiny(11):上下两行之后标签再和控件同号
   会抢视觉重心。

② infoRows 重写为 Column({space:14}),每项 = Column({space:6}){
     标题行 fieldLb(...)
     控件行(height 40 / inputBg / radiusS / 左右 padding 12)
   }
   控件行统一给 height(40):不给的话「设置…」「未指定」这类短文字
   会把框压扁,几行之间的间距就参差不齐。
   负责人那行的头像从 22 调到 24(框内 40 高,22 略嫌小)。
   备注:只读态改 constraintSize({minHeight:40}) + maxLines(3),
   避免长备注把框撑成一大片;编辑态从单行 TextInput 换成
   TextArea(height 76)—— 备注本来就是多行的,单行输入框里
   看不见换行,用户会以为只能写一句。

③ kvRow 同步改成上下两行
   「分类」「循环」若还左右排,夹在截止/负责人/备注中间会显得错位。

④ 面板标题改主题色
   Text(this.titleOf()) 从 FbColors.ink + Medium 改成 this.accent + Bold。
   ⚠️ 完成态仍保留 faint + 删除线:那是"这件事已经过去了"的信号,
      再上主题色会和待办标题一样抢眼,反而分不出轻重。

编译通过,已装真机。
This commit is contained in:
2026-11-05 19:37:08 +08:00
parent b42e657bb2
commit 2fefacccd3
+156 -109
View File
@@ -977,10 +977,14 @@ export struct FbTaskPanel {
}) })
Column({ space: 2 }) { Column({ space: 2 }) {
/* 🔴 #77k(用户 2026-11-05):「上面"台式机采购计划"这样的标题,
应该是主题的颜色。」
⚠️ 完成态仍用 faint + 删除线:那条是"这件事已经过去了"的信号,
再上主题色会和"待办"的标题一样抢眼,反而分不出轻重。 */
Text(this.titleOf()) Text(this.titleOf())
.fontSize(FbMetric.fontTitle) .fontSize(FbMetric.fontTitle)
.fontWeight(FontWeight.Medium) .fontWeight(FontWeight.Bold)
.fontColor(this.isDone() ? FbColors.faint : FbColors.ink) .fontColor(this.isDone() ? FbColors.faint : this.accent)
.decoration({ .decoration({
type: this.isDone() ? TextDecorationType.LineThrough : TextDecorationType.None, type: this.isDone() ? TextDecorationType.LineThrough : TextDecorationType.None,
color: FbColors.faint color: FbColors.faint
@@ -1160,76 +1164,106 @@ export struct FbTaskPanel {
*/ */
@Builder @Builder
infoRows() { infoRows() {
Column({ space: 0 }) { /* 🔴🔴 #77k(用户 2026-11-05):「上面的标题和下面的输入框,其实要分成两行。
/* ---- 截止:可点,弹 FbDateTimePicker ---- */ 比如说,"截止"不是直接后面排一个日期,而是把日期输入框放在"截止"下面;
Row({ space: 8 }) { "负责人"也是,"备注"也是,全部都是这样的。」
⚠️ 上一版(#77j)我把 `fieldLb` 定成了 `width(48)` 的**行内标签**,
于是形态是「[截止] 2026-11-07 18:30」,和用户要的相反。
这次改成每个字段 = 一个 Column:
① 标题行(主题色 + Bold,独占一行)
② 控件行(浅底圆角框,整行宽)
这样「结束时间」「负责人」「备注」的输入区左缘全部对齐,
也和网页端 `.tk-attr-row` 的上下两行形态一致。
⚠️ 控件行统一给 height(40) + inputBg + radiusS:
不给高度的话,「设置…」「未指定」这类短文字会把框压扁,
几行之间的间距就会参差不齐。 */
Column({ space: 14 }) {
/* ---- 截止 ---- */
Column({ space: 6 }) {
this.fieldLb('截止') this.fieldLb('截止')
Text(this.dueOf() !== '' ? this.dueOf() : '设置…') Row({ space: 8 }) {
.fontSize(FbMetric.fontSmall) Text(this.dueOf() !== '' ? this.dueOf() : '设置截止时间…')
.fontColor(this.dueOf() === '' ? FbColors.faint .fontSize(FbMetric.fontSmall)
: (this.overdueOf() ? '#C0533F' : FbColors.ink)) .fontColor(this.dueOf() === '' ? FbColors.faint
.layoutWeight(1) : (this.overdueOf() ? '#C0533F' : FbColors.ink))
if (this.overdueOf()) { .layoutWeight(1)
Text('已逾期') if (this.overdueOf()) {
.fontSize(10) Text('已逾期')
.fontColor('#C0533F')
.padding({ left: 6, right: 6, top: 2, bottom: 2 })
.backgroundColor('#FDECEC')
.borderRadius(FbMetric.radiusPill)
}
/* 可编辑的视觉提示:一支小笔。没有它用户不知道这里能点
(本项目反复踩过"纯文字看着不可点"的坑)。 */
Text('✎')
.fontSize(FbMetric.fontTiny)
.fontColor(this.inlineBusy ? FbColors.faint : this.accent)
}
.width('100%')
.padding({ top: 7, bottom: 7 })
.alignItems(VerticalAlign.Center)
.onClick((): void => {
this.openDuePicker();
})
/* ---- 负责人:头像 + 可点选人 ---- */
Row({ space: 8 }) {
this.fieldLb('负责人')
/* 头像(#77「负责人那个地方也需要有图标,就是人的头像」)
⚠️ 端上不一定拿得到头像图(`assigneeAvatar` 可能是空 key)⇒
有图用图,没图用首字色块兜底(与留言区同一个手法)。 */
if (this.assigneeAvatarSrc() !== '') {
Image(this.assigneeAvatarSrc())
.width(22)
.height(22)
.borderRadius(11)
.objectFit(ImageFit.Cover)
.backgroundColor(FbColors.inputBg)
} else {
Row() {
Text(this.assigneeOf() !== '' ? this.assigneeOf().substring(0, 1) : '?')
.fontSize(10) .fontSize(10)
.fontColor(this.accent) .fontColor('#C0533F')
.padding({ left: 6, right: 6, top: 2, bottom: 2 })
.backgroundColor('#FDECEC')
.borderRadius(FbMetric.radiusPill)
} }
.width(22) /* 可编辑的视觉提示:一支小笔。没有它用户不知道这里能点
.height(22) (本项目反复踩过"纯文字看着不可点"的坑)。 */
.borderRadius(11) Text('✎')
.backgroundColor(FbColors.inputBg) .fontSize(FbMetric.fontTiny)
.justifyContent(FlexAlign.Center) .fontColor(this.inlineBusy ? FbColors.faint : this.accent)
} }
Text(this.assigneeOf() !== '' ? this.assigneeOf() : '未指定') .width('100%')
.fontSize(FbMetric.fontSmall) .height(40)
.fontColor(this.assigneeOf() === '' ? FbColors.faint : FbColors.ink) .padding({ left: 12, right: 12 })
.layoutWeight(1) .backgroundColor(FbColors.inputBg)
Text('✎') .borderRadius(FbMetric.radiusS)
.fontSize(FbMetric.fontTiny) .alignItems(VerticalAlign.Center)
.fontColor(this.inlineBusy ? FbColors.faint : this.accent) .onClick((): void => {
this.openDuePicker();
})
} }
.width('100%') .width('100%')
.padding({ top: 7, bottom: 7 }) .alignItems(HorizontalAlign.Start)
.alignItems(VerticalAlign.Center)
.onClick((): void => {
this.openAssigneePicker();
})
/* ---- 负责人 ---- */
Column({ space: 6 }) {
this.fieldLb('负责人')
Row({ space: 8 }) {
/* 头像(#77「负责人那个地方也需要有图标,就是人的头像」)
⚠️ 端上不一定拿得到头像图(`assigneeAvatar` 可能是空 key)⇒
有图用图,没图用首字色块兜底(与留言区同一个手法)。 */
if (this.assigneeAvatarSrc() !== '') {
Image(this.assigneeAvatarSrc())
.width(24)
.height(24)
.borderRadius(12)
.objectFit(ImageFit.Cover)
.backgroundColor(FbColors.line2)
} else {
Row() {
Text(this.assigneeOf() !== '' ? this.assigneeOf().substring(0, 1) : '?')
.fontSize(11)
.fontColor(this.accent)
}
.width(24)
.height(24)
.borderRadius(12)
.backgroundColor(FbColors.line2)
.justifyContent(FlexAlign.Center)
}
Text(this.assigneeOf() !== '' ? this.assigneeOf() : '未指定')
.fontSize(FbMetric.fontSmall)
.fontColor(this.assigneeOf() === '' ? FbColors.faint : FbColors.ink)
.layoutWeight(1)
Text('✎')
.fontSize(FbMetric.fontTiny)
.fontColor(this.inlineBusy ? FbColors.faint : this.accent)
}
.width('100%')
.height(40)
.padding({ left: 12, right: 12 })
.backgroundColor(FbColors.inputBg)
.borderRadius(FbMetric.radiusS)
.alignItems(VerticalAlign.Center)
.onClick((): void => {
this.openAssigneePicker();
})
}
.width('100%')
.alignItems(HorizontalAlign.Start)
/* ---- 分类 / 循环(同样上下两行)---- */
if (this.categoryOf() !== '') { if (this.categoryOf() !== '') {
this.kvRow('分类', this.categoryOf()) this.kvRow('分类', this.categoryOf())
} }
@@ -1237,56 +1271,60 @@ export struct FbTaskPanel {
this.kvRow('循环', this.repeatOf()) this.kvRow('循环', this.repeatOf())
} }
/* ---- 备注:可编辑 ---- */ /* ---- 备注 ---- */
Column({ space: 4 }) { Column({ space: 6 }) {
Row({ space: 8 }) { this.fieldLb('备注')
this.fieldLb('备注') if (this.noteEdit) {
if (this.noteEdit) { TextArea({ text: this.noteDraft, placeholder: '补充说明…' })
TextInput({ text: this.noteDraft, placeholder: '补充说明…' }) .placeholderColor(FbColors.faint)
.placeholderColor(FbColors.faint) .placeholderFont({ size: FbMetric.fontTiny })
.placeholderFont({ size: FbMetric.fontTiny }) .fontSize(FbMetric.fontSmall)
.fontSize(FbMetric.fontSmall) .fontColor(FbColors.ink)
.fontColor(FbColors.ink) .backgroundColor(FbColors.inputBg)
.backgroundColor(FbColors.inputBg) .borderRadius(FbMetric.radiusS)
.borderRadius(FbMetric.radiusS) .width('100%')
.height(38) .height(76)
.layoutWeight(1) .padding({ left: 12, right: 12, top: 10, bottom: 10 })
.padding({ left: 10, right: 10 }) .onChange((v: string): void => {
.onChange((v: string): void => { this.noteDraft = v;
this.noteDraft = v; })
}) /* 失焦保存 —— 用户改完直接点别处是很自然的动作,
.onSubmit((): void => { 等他再去找"保存"就会以为没存上。 */
this.saveNote(); .onBlur((): void => {
}) this.saveNote();
/* 失焦也保存 —— 用户改完直接点别处是很自然的动作, })
等他再去找"保存"就会以为没存上。 */ } else {
.onBlur((): void => { Row({ space: 8 }) {
this.saveNote();
})
} else {
Text(this.noteOf() !== '' ? this.noteOf() : '点这里添加备注…') Text(this.noteOf() !== '' ? this.noteOf() : '点这里添加备注…')
.fontSize(FbMetric.fontSmall) .fontSize(FbMetric.fontSmall)
.fontColor(this.noteOf() === '' ? FbColors.faint : FbColors.ink) .fontColor(this.noteOf() === '' ? FbColors.faint : FbColors.ink)
.maxLines(3)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.layoutWeight(1) .layoutWeight(1)
Text('✎') Text('✎')
.fontSize(FbMetric.fontTiny) .fontSize(FbMetric.fontTiny)
.fontColor(this.accent) .fontColor(this.inlineBusy ? FbColors.faint : this.accent)
} }
.width('100%')
.constraintSize({ minHeight: 40 })
.padding({ left: 12, right: 12, top: 11, bottom: 11 })
.backgroundColor(FbColors.inputBg)
.borderRadius(FbMetric.radiusS)
.alignItems(VerticalAlign.Top)
.onClick((): void => {
if (this.noteEdit || this.inlineBusy) {
return;
}
this.noteDraft = this.noteOf();
this.noteEdit = true;
})
} }
.width('100%')
.padding({ top: 7, bottom: 7 })
.alignItems(VerticalAlign.Center)
.onClick((): void => {
if (this.noteEdit || this.inlineBusy) {
return;
}
this.noteDraft = this.noteOf();
this.noteEdit = true;
})
} }
.width('100%') .width('100%')
.alignItems(HorizontalAlign.Start)
} }
.width('100%') .width('100%')
.alignItems(HorizontalAlign.Start)
.padding({ top: 4 }) .padding({ top: 4 })
} }
@@ -1343,26 +1381,35 @@ export struct FbTaskPanel {
*/ */
@Builder @Builder
fieldLb(t: string) { fieldLb(t: string) {
/* #77k:**不再写 width(48)** —— 现在标签独占一行(控件在它下面),
固定宽度反而会让它在 Column 里只占左边一小段,与下面的整行控件左缘对不齐。
字号用 fontTiny(11)而不是 fontSmall(13):
上下两行之后,标签再和控件同号就会抢视觉重心。 */
Text(t) Text(t)
.fontSize(FbMetric.fontSmall) .fontSize(FbMetric.fontTiny)
.fontWeight(FontWeight.Bold) .fontWeight(FontWeight.Bold)
.fontColor(this.accent) .fontColor(this.accent)
.letterSpacing(0.6) .letterSpacing(0.6)
.width(48) .width('100%')
.textAlign(TextAlign.Start)
} }
@Builder @Builder
kvRow(label: string, value: string) { kvRow(label: string, value: string) {
Row({ space: 8 }) { /* #77k:与截止/负责人/备注同形态(标签一行、值一行),
否则「分类」「循环」还是左右排,夹在中间会显得错位。 */
Column({ space: 6 }) {
this.fieldLb(label) this.fieldLb(label)
Text(value) Text(value)
.fontSize(FbMetric.fontSmall) .fontSize(FbMetric.fontSmall)
.fontColor(FbColors.ink) .fontColor(FbColors.ink)
.layoutWeight(1) .width('100%')
.padding({ left: 12, right: 12, top: 11, bottom: 11 })
.backgroundColor(FbColors.inputBg)
.borderRadius(FbMetric.radiusS)
} }
.width('100%') .width('100%')
.padding({ top: 7, bottom: 7 }) .alignItems(HorizontalAlign.Start)
.alignItems(VerticalAlign.Top)
} }
/** 共享给谁(工单 #26):列表 + 共享入口 + 逐条取消 */ /** 共享给谁(工单 #26):列表 + 共享入口 + 逐条取消 */