Files
FamilyBook_harmonyos/entry/src/main/ets/pages/card/FbTaskCard4x4.ets
T

218 lines
6.5 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 家书 FamilyBook · 4×4 服务卡片(任务 · 上概述/新建,下滚动列表 + 卡上完成)
*
* 用户 2026-10-25:「任务卡片,也需要4x4和4x6,跟任务模块类似,列出所有任务,
* 可以在卡片直接点击完成。有新建按钮。」
* ⇒ 上半:标题 + 更新时间 + 「+ 新建」(路由进 app 直开「新建任务」);
* 下半:`List` 装全部待办(数据侧排序:逾期 > 进行中 > 普通),
* 每行右侧一颗「✓ 完成」→ `postCardAction({action:'message', taskDone:id})`
* → `FbFormAbility.markTaskDone()` 调接口 → 重算重推。
*
* ⚠️ 卡片不能自己发网络请求,完成动作必须借道 FormExtensionAbility。
* ⚠️ ForEach key 带 version 前缀(v89 教训)。
*/
let storageTkB = new LocalStorage();
/** 列表一行 */
class FbTaskRow9a {
id: number = 0;
key: string = '';
title: string = '';
dueText: string = '';
status: string = '';
boardColor: string = '#A8574F';
overdue: boolean = false;
}
@Entry(storageTkB)
@Component
struct FbTaskCard4x4 {
@LocalStorageProp('state') state: string = 'loading';
@LocalStorageProp('hint') hint: string = '';
@LocalStorageProp('updatedAt') updatedAt: string = '';
@LocalStorageProp('openCount') openCount: number = 0;
@LocalStorageProp('overdueCount') overdueCount: number = 0;
@LocalStorageProp('allJson') allJson: string = '[]';
@LocalStorageProp('version') version: string = '';
private rows(): FbTaskRow9a[] {
try {
const all: FbTaskRow9a[] = JSON.parse(this.allJson) as FbTaskRow9a[];
return all;
} catch (err) {
return [];
}
}
private openApp(): void {
postCardAction(this, {
action: 'router',
abilityName: 'EntryAbility',
params: { fbModule: 'tasks' }
});
}
/** 「+ 新建」→ 进 app 直开「新建任务」浮层(EntryAbility → modCreate 通道) */
private addOne(): void {
postCardAction(this, {
action: 'router',
abilityName: 'EntryAbility',
params: { fbModule: 'tasks', widgetAction: 'add' }
});
}
/** 卡上直接完成(id 必须转字符串:param 数值按 int32 传) */
private complete(item: FbTaskRow9a): void {
postCardAction(this, {
action: 'message',
params: { taskDone: `${item.id}` }
});
}
/** 列表单行:色条 + 标题/截止 + ✓ 完成 */
@Builder
listRow(item: FbTaskRow9a) {
Row({ space: 8 }) {
Column()
.width(3)
.height(34)
.borderRadius(2)
.backgroundColor(item.overdue ? '#C0533F' : item.boardColor)
Column({ space: 2 }) {
Text(item.title)
.fontSize(13)
.fontColor('#2C231D')
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Row({ space: 4 }) {
if (item.overdue) {
Text('逾期')
.fontSize(9)
.fontColor('#C0533F')
.maxLines(1)
}
if (item.dueText !== '') {
Text(item.dueText)
.fontSize(9)
.fontColor(item.overdue ? '#C0533F' : '#A8988A')
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.layoutWeight(1)
} else {
Text(item.status === 'doing' ? '进行中' : '待办')
.fontSize(9)
.fontColor('#A8988A')
.maxLines(1)
}
}
.width('100%')
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
/* ⭐ 卡上直接点完成(子组件 onClick 优先于整卡,不会连带进 app) */
Text('✓')
.fontSize(14)
.fontColor('#FFFFFF')
.width(26)
.height(26)
.textAlign(TextAlign.Center)
.borderRadius(13)
.backgroundColor(item.overdue ? '#C0533F' : '#A8574F')
.onClick((): void => this.complete(item))
}
.alignItems(VerticalAlign.Center)
.width('100%')
.padding({ left: 8, right: 8, top: 5, bottom: 5 })
.borderRadius(8)
.backgroundColor(item.overdue ? '#FBEDEA' : '#F7F2EC')
}
/** 空态 */
@Builder
emptyHint() {
Column() {
Text(this.hint !== '' ? this.hint : '没有待办任务')
.fontSize(12)
.fontColor(this.hint !== '' ? '#C0533F' : '#A8988A')
.maxLines(3)
.textAlign(TextAlign.Center)
}
.width('100%')
.layoutWeight(1)
.justifyContent(FlexAlign.Center)
}
build() {
Column({ space: 6 }) {
// ===== 顶栏:标题 + 更新时间 + + 新建 =====
Row({ space: 6 }) {
Text('任务')
.fontSize(15)
.fontWeight(FontWeight.Bold)
.fontColor('#2C231D')
.maxLines(1)
.layoutWeight(1)
Text(this.updatedAt)
.fontSize(9)
.fontColor('#A8988A')
.maxLines(1)
Button('+')
.fontSize(13)
.fontColor('#FFFFFF')
.width(26)
.height(26)
.borderRadius(13)
.padding(0)
.backgroundColor('#A8574F')
.onClick((): void => this.addOne())
}
.width('100%')
// ===== 概述行 =====
Row({ space: 8 }) {
Text(`待办 ${this.openCount} 条`)
.fontSize(11)
.fontColor('#A8574F')
.fontWeight(FontWeight.Medium)
Text(this.hint !== '' ? this.hint
: (this.overdueCount > 0 ? '逾期 ' + this.overdueCount.toString() + ' 条'
: '点 ✓ 直接完成'))
.fontSize(10)
.fontColor(this.hint !== '' || this.overdueCount > 0 ? '#C0533F' : '#A8988A')
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.layoutWeight(1)
}
.width('100%')
Divider()
.strokeWidth(0.5)
.color('#EFE6D8')
// ===== 全部待办(可滚动,可直接完成)=====
if (this.rows().length === 0) {
this.emptyHint()
} else {
List({ space: 5 }) {
ForEach(this.rows(), (item: FbTaskRow9a) => {
ListItem() {
this.listRow(item)
}
}, (item: FbTaskRow9a): string => `tl_${this.version}_${item.key}`)
}
.width('100%')
.layoutWeight(1)
.scrollBar(BarState.Off)
}
}
.width('100%')
.height('100%')
.padding(12)
.backgroundColor('#FFFFFF')
.borderRadius(16)
// ⭐ 整卡可点
.onClick((): void => this.openApp())
}
}