任务面板:左上「编辑任务」+ 点一下即编辑 + 标题最前 + 字号统一 (#77)

用户 2026-11-05 五点:
  「这个框的标题在左上角,是"编辑任务"几个字,颜色用主题颜色。
    你参考一下"编辑行程"的做法。」
  「任务和备注是点进去之后,只要点一下,马上就要变成编辑状态,
    然后弹出输入法,开始输入。不需要点一下之后先变成一个输入框,
    再点一下弹出输入法。直接点进去之后就是输入状态。」
  「任务标题应该放在最前面,放在所有内容之前,也就是状态之前。」
  「状态、分组、看板、任务标题、截止、负责人、备注、协作人、
    子任务、附件、留言这些字的大小要保持统一。」

① 左上角「编辑任务」(主题色)
   与 FbTripNodeSheet 的「编辑行程」完全同一套:
   fontSize(fontBody=15) + Bold + accent。
   只写固定的「编辑任务」,不写任务标题 —— 标题是内容(可改),
   已经下移到 titleRow()。
   「属于「父任务」」跟着放到标题下面第二行(原来是同一行的大字位置)。

② 点一下直接进编辑态并拉起输入法
   原来点一下只是 `xxxEdit = true`,把 TextArea 画出来 ——
   但**画出输入框不会自动获得焦点**,用户还得再点一下才弹输入法,
   正是他说的"变成输入框,再点一下弹出输入法"。
   ⇒ 点击时:
        this.titleEdit = true;
        focusControl.requestFocus(tkpTitleInput);
     并给控件加 `.id(...)` + `.defaultFocus(true)`。
   ⚠️ `focusControl` 是**全局声明的命名空间**(ets/component/common.d.ts),
      **不能 import** —— 写成 `import { focusControl } from @kit.ArkUI`
      会报 "has no exported member"。这个坑踩过一次。
   ⚠️ `defaultFocus(true)` 是兜底:个别机型上 requestFocus 会因
      "节点刚创建"而落空,defaultFocus 能让它自己拿到。
   备注同改(id = tkpNoteInput)。

③ 任务标题提到最前
   build() 的 Scroll 里顺序改为:
      titleRow() → statusSeg() → boardChips() → infoRows() → …
   原来它在 infoRows 内部第一个(等于排在状态/看板之后)。

④ 字号统一
   `fieldLb` 从 fontTiny(11) 改成 **fontSmall(13)**,
   与 `FbSectionTitle` 内部字号完全一致(那个组件是 fontSmall)。
   上一版标签比区块标题小一号,看着不成套。
   现在统计:状态/分组(看板)/协作人/子任务/附件/留言 六个 FbSectionTitle
   全部 fontSmall,任务标题/截止/负责人/备注/分类/循环 六个 fieldLb
   也全部 fontSmall ⇒ 11 处标题字号统一。

编译通过,已装真机。
This commit is contained in:
2026-11-05 19:45:17 +08:00
parent 28c6e674ba
commit 4cca4c51be
+123 -76
View File
@@ -807,6 +807,8 @@ export struct FbTaskPanel {
Scroll() {
Column({ space: 0 }) {
/* #77m:任务标题放在所有内容之前(用户:「也就是状态之前」) */
this.titleRow()
this.statusSeg()
this.boardChips()
this.infoRows()
@@ -998,16 +1000,28 @@ export struct FbTaskPanel {
@Builder
headBar() {
Row({ space: 10 }) {
if (this.parentOf() !== '') {
Text('属于「' + this.parentOf() + '」')
.fontSize(FbMetric.fontTiny)
.fontColor(FbColors.faint)
.maxLines(1)
.layoutWeight(1)
.flexShrink(1)
} else {
Blank()
Column({ space: 2 }) {
/* 🔴 #77m(用户 2026-11-05):「这个框的标题在左上角,是"编辑任务"
几个字,颜色用主题颜色。你参考一下"编辑行程"的做法。」
与 `FbTripNodeSheet` 的「编辑行程」完全同一套:
fontSize(fontBody=15) + Bold + 主题色。
⚠️ 这里只写固定的「编辑任务」,**不写任务标题** ——
标题是内容(可改),已经下移到 titleRow()。 */
Text('编辑任务')
.fontSize(FbMetric.fontBody)
.fontWeight(FontWeight.Bold)
.fontColor(this.accent)
if (this.parentOf() !== '') {
Text('属于「' + this.parentOf() + '」')
.fontSize(FbMetric.fontTiny)
.fontColor(FbColors.faint)
.maxLines(1)
}
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
.flexShrink(1)
Text(this.statusWord(this.statusOf()))
.fontSize(FbMetric.fontTiny)
@@ -1168,81 +1182,104 @@ export struct FbTaskPanel {
* 负责人前面加头像。
* ⚠️ 其余(分类 / 循环)**保持不变** —— 用户没提,不动。
*/
/**
* 任务标题(可编辑)—— 放在**所有内容最前**(状态之前)。
*
* 🔴🔴 #77m(用户 2026-11-05):
* 「任务标题应该放在最前面,放在所有内容之前,也就是状态之前。」
* 「任务和备注是点进去之后,只要点一下,马上就要变成编辑状态,
* 然后弹出输入输入法,开始输入。不需要点一下之后先变成一个输入框,
* 再点一下弹出输入法。直接点进去之后就是输入状态。」
*
* ⇒ 点一下直接换成 `TextArea` 并**抢焦点拉起输入法**。
*
* ⚠️ 关键:切换成输入框只是"画出来了",**不会自动获得焦点**。
* 必须 `focusControl.requestFocus(id)` 显式要焦点,否则用户还得再点一下 ——
* 正是用户抱怨的"点一下变输入框、再点一下弹输入法"。
* ⚠️ 必须 `setTimeout` 延后一帧:`titleEdit = true` 之后框架还没完成
* 这次重建,此刻 `id` 对应的节点尚不存在,直接 requestFocus 会落空。
* 60ms 用户完全无感,但足够框架把新节点挂上。
* ⚠️ `.defaultFocus(true)` 作为兜底:个别机型上 requestFocus 会因
* "节点刚创建"而失败,defaultFocus 能让它自己拿到焦点。
*/
@Builder
titleRow() {
Column({ space: 6 }) {
this.fieldLb('任务标题')
if (this.titleEdit) {
TextArea({ text: this.titleDraft, placeholder: '要做的事…' })
.id('tkpTitleInput')
.defaultFocus(true)
.placeholderColor(FbColors.faint)
.placeholderFont({ size: FbMetric.fontSmall })
.fontSize(FbMetric.fontTitle)
.fontWeight(FontWeight.Bold)
.fontColor(this.accent)
.backgroundColor(FbColors.inputBg)
.borderRadius(FbMetric.radiusS)
.width('100%')
.height(64)
.padding({ left: 12, right: 12, top: 10, bottom: 10 })
.onChange((v: string): void => {
this.titleDraft = v;
})
/* 失焦保存 —— 与备注同一套(用户改完直接点别处是最自然的动作,
让他再去找"保存"就会以为没存上)。 */
.onBlur((): void => {
this.saveTitle();
})
} else {
Row({ space: 8 }) {
Text(this.titleOf())
.fontSize(FbMetric.fontTitle)
.fontWeight(FontWeight.Bold)
.fontColor(this.isDone() ? FbColors.faint : this.accent)
.decoration({
type: this.isDone() ? TextDecorationType.LineThrough : TextDecorationType.None,
color: FbColors.faint
})
.maxLines(3)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.layoutWeight(1)
Text('✎')
.fontSize(FbMetric.fontTiny)
.fontColor(this.inlineBusy ? FbColors.faint : this.accent)
}
.width('100%')
.constraintSize({ minHeight: 44 })
.padding({ left: 12, right: 12, top: 11, bottom: 11 })
.backgroundColor(FbColors.inputBg)
.borderRadius(FbMetric.radiusS)
.alignItems(VerticalAlign.Top)
.onClick((): void => {
if (this.titleEdit || this.inlineBusy) {
return;
}
this.titleDraft = this.titleOf();
this.titleEdit = true;
focusControl.requestFocus('tkpTitleInput');
})
}
}
.width('100%')
.alignItems(HorizontalAlign.Start)
.padding({ top: 10, bottom: 4 })
}
@Builder
infoRows() {
/* 🔴🔴 #77k(用户 2026-11-05):「上面的标题和下面的输入框,其实要分成两行。
比如说,"截止"不是直接后面排一个日期,而是把日期输入框放在"截止"下面;
"负责人"也是,"备注"也是,全部都是这样的。」
⚠️ 上一版(#77j)我把 `fieldLb` 定成了 `width(48)` 的**行内标签**,
于是形态是「[截止] 2026-11-07 18:30」,和用户要的相反。
这次改成每个字段 = 一个 Column:
⚠️ 每个字段 = 一个 Column:
① 标题行(主题色 + Bold,独占一行)
② 控件行(浅底圆角框,整行宽)
这样「结束时间」「负责人」「备注」的输入区左缘全部对齐,
也和网页端 `.tk-attr-row` 的上下两行形态一致。
⚠️ 控件行统一给 height(40) + inputBg + radiusS:
不给高度的话,「设置…」「未指定」这类短文字会把框压扁,
几行之间的间距就会参差不齐。 */
Column({ space: 14 }) {
/* ---- 任务标题(可编辑,#77l 从顶栏下移到这里)---- */
Column({ space: 6 }) {
this.fieldLb('任务标题')
if (this.titleEdit) {
TextArea({ text: this.titleDraft, placeholder: '要做的事…' })
.placeholderColor(FbColors.faint)
.placeholderFont({ size: FbMetric.fontTiny })
.fontSize(FbMetric.fontTitle)
.fontColor(this.accent)
.backgroundColor(FbColors.inputBg)
.borderRadius(FbMetric.radiusS)
.width('100%')
.height(64)
.padding({ left: 12, right: 12, top: 10, bottom: 10 })
.onChange((v: string): void => {
this.titleDraft = v;
})
/* 失焦保存 —— 与备注同一套(用户改完直接点别处是最自然的动作,
让他再去找"保存"就会以为没存上)。 */
.onBlur((): void => {
this.saveTitle();
})
} else {
Row({ space: 8 }) {
Text(this.titleOf())
.fontSize(FbMetric.fontTitle)
.fontWeight(FontWeight.Bold)
.fontColor(this.isDone() ? FbColors.faint : this.accent)
.decoration({
type: this.isDone() ? TextDecorationType.LineThrough : TextDecorationType.None,
color: FbColors.faint
})
.maxLines(3)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.layoutWeight(1)
Text('✎')
.fontSize(FbMetric.fontTiny)
.fontColor(this.inlineBusy ? FbColors.faint : this.accent)
}
.width('100%')
.constraintSize({ minHeight: 44 })
.padding({ left: 12, right: 12, top: 11, bottom: 11 })
.backgroundColor(FbColors.inputBg)
.borderRadius(FbMetric.radiusS)
.alignItems(VerticalAlign.Top)
.onClick((): void => {
if (this.titleEdit || this.inlineBusy) {
return;
}
this.titleDraft = this.titleOf();
this.titleEdit = true;
})
}
}
.width('100%')
.alignItems(HorizontalAlign.Start)
/* ---- 截止 ---- */
Column({ space: 6 }) {
this.fieldLb('截止')
@@ -1339,6 +1376,8 @@ export struct FbTaskPanel {
this.fieldLb('备注')
if (this.noteEdit) {
TextArea({ text: this.noteDraft, placeholder: '补充说明…' })
.id('tkpNoteInput')
.defaultFocus(true)
.placeholderColor(FbColors.faint)
.placeholderFont({ size: FbMetric.fontTiny })
.fontSize(FbMetric.fontSmall)
@@ -1380,6 +1419,9 @@ export struct FbTaskPanel {
}
this.noteDraft = this.noteOf();
this.noteEdit = true;
/* #77m:与任务标题同一套 —— 点一下就进编辑态并拉起输入法,
不用"再点一下输入框"(用户明确要求)。 */
focusControl.requestFocus('tkpNoteInput');
})
}
}
@@ -1444,12 +1486,17 @@ export struct FbTaskPanel {
*/
@Builder
fieldLb(t: string) {
/* #77k:**不再写 width(48)** —— 现在标签独占一行(控件在它下面),
固定宽度反而会让它在 Column 里只占左边一小段,与下面的整行控件左缘对不齐。
字号用 fontTiny(11)而不是 fontSmall(13):
上下两行之后,标签再和控件同号就会抢视觉重心。 */
/* 🔴 #77m(用户 2026-11-05):「状态、分组、看板、任务标题、截止、负责人、
备注、协作人、子任务、附件、留言这些字的大小要保持统一。」
⇒ 标签字号统一走 `fontSmall`(13),**与 `FbSectionTitle` 完全一致**
(那个组件内部就是 `fontSize(FbMetric.fontSmall)`)。
上一版这里是 fontTiny(11),于是"截止"比"状态"小一号,看着不成套。
⚠️ 宽度不再写 48:标签独占一行(控件在它下面),
固定宽度会让它只占左边一小段,与下面的整行控件左缘对不齐。 */
Text(t)
.fontSize(FbMetric.fontTiny)
.fontSize(FbMetric.fontSmall)
.fontWeight(FontWeight.Bold)
.fontColor(this.accent)
.letterSpacing(0.6)