v65/v66:六个空壳模块接线 + 桌面服务卡片
用户 2026-10-20:
「做几个和 syncCalendar 差不多的卡片。另外其他的功能也逐步完成……旅程的
新建旅程啊,车辆管理、出行方式、节点设置……资源也点不进去……任务也点不
进去,也没法完成……纪念日、新增纪念日……财务的显示也有问题……笔记现在
也点不进去,记笔记也记不了。」
v65 —— 六个模块(任务 / 资源 / 纪念日 / 笔记 / 账本 / 旅程)原本是**同一套
空壳模板**复制出来的:`FbPrimaryButton` 没有 `onTap`、`ListItem` 没有
`onClick`、设置菜单的 `action` 全是空串。这一版把它们全部接上真实接口:
· 任务:新建 / 编辑(`FbTaskEditSheet` + `FbTaskRepo`)、列表可点、勾完成
(走 `/tasks/<id>/status` —— 服务端 `PATCH` **显式忽略** status,走 Patch
会得到"看起来成功的假成功")、按看板筛选
· 资源:新增 / 查看 / 改 / 删(`FbResourceSheet` + `FbResourceRepo`);
过滤维度从**并不存在的**「证件 / 资料」改成按权限与归属
(`resources` 表没有 category 列,那个筛选一直是筛空的)
· 纪念日:新增 / 编辑(`FbDayEditSheet` + `FbDayRepo`);派生生日
(id=0、来自名册)只给提示不给编辑 —— 点开 `/days/0` 必然 404
· 笔记:记一条 / 打开 / 改(`FbNoteSheet` + `FbNoteRepo`),正文按 blocks 存
· 账本:记一笔(`FbLedgerEntrySheet` + `FbLedgerRepo`);修掉财务显示自相
矛盾 —— 资产/负债改回**服务端 summary**(原来端上按金额正负号重算,与
服务端"负债取绝对值"的口径打架,会算出 净资产 ≠ 资产 − 负债)
· 旅程:题图卡片(封面 + 标题 + 城市)+ 行程 + 新建旅程 + 新建节点
服务端同时修掉两处**静默数据丢失**(网页端因提交格式凑巧没暴露,只有走
API 的客户端会中招):
· 新建笔记传的是 `body`,而 `Note::create()` 只读 `blocks` ⇒ 新笔记只有标题
· 改笔记时 `blocks` 恒为空,而 `Note::update()` 是整组替换 ⇒ 只改标题就把
正文全删光;另修 `annivPeopleOf()`(`find()` 的 SQL 不含 people,原来那个
兜底恒为空 ⇒ 只改纪念日标题会清空关联人)
v66 —— 桌面服务卡片(用户选了「桌面服务卡片」这一项):
· `FbFormAbility`(FormExtensionAbility)+ `form_config.json` 三块尺寸:
2×2 今日概览 / 2×4 左右分栏 / 4×4 今日全景
· `FbCardData` 只打 `/home` 一个接口(与网页首页同源),数据**扁平化**后
由 `formBindingData` 推给卡片;断网时用上次成功的缓存并注明"离线"
· 卡片是后台进程 ⇒ 请求带 `authProbe: true`:401 **不能**触发全局"踢回
登录页"(那会顺手把正在用应用的人踢下线,v62 那次事故同一个坑)
· 点卡片 → `postCardAction(router, fbModule)` → `EntryAbility` 读 Want 参数
直接落到对应模块;补了 `onNewWant`(没有它,第二次点卡片"什么也没发生")
· 4×4 右上角 ↻ 走 `postAction(message)` → `onFormEvent` 重取数再推回
验证:`hvigorw assembleHap` BUILD SUCCESSFUL;打包后的 hap 里确认
`FbFormAbility`(type=form)与 `$profile:form_config` 都在,卡片代码进了
`ets/widgets.abc`。静态守卫 730 条全绿,反向验证 110 条注入全部能让守卫变红。
⚠️ 设备仍断连(`hdc list targets` 为空),真机尚未验收。
This commit is contained in:
@@ -9,9 +9,9 @@
|
||||
* 看板名仍保留(卡片上那个小色块标签),点它可以切到别的看板。
|
||||
*/
|
||||
|
||||
import { FbColors, FbMetric, fbTint, FbTint, FB_MASK } from '../../common/Theme';
|
||||
import { FbColors, FbMetric, fbTint, FbTint, FB_MASK, fbAlpha } from '../../common/Theme';
|
||||
import { FbAppState, fbAppState } from '../../common/Store';
|
||||
import { FbGroup, FbTaskItem } from '../../model/Types';
|
||||
import { FbBoardOpt, FbGroup, FbTaskItem } from '../../model/Types';
|
||||
import { fbGroupTask } from '../../model/DemoData';
|
||||
import { parseTasks } from '../../data/FbParse';
|
||||
import { loadModule } from '../../data/FbModuleLoad';
|
||||
@@ -20,8 +20,14 @@ import { FB_DOCK_RESERVE } from '../../components/FloatDock';
|
||||
import { fbOnScroll, fbOnTouch, fbOnHScroll } from '../../common/FbScroll';
|
||||
import { fbMaskTransition, fbSheetTransition } from '../../common/FbAnim';
|
||||
import { FbModuleSettingsSheet } from '../../components/FbModuleSettingsSheet';
|
||||
import { FbSheetRing } from '../../components/FbSheetRing';
|
||||
import { FbSheetClose } from '../../components/FbSheetClose';
|
||||
import { FB_BACK } from '../../common/FbBack';
|
||||
import { FB_SET_TASKS } from '../../model/FbSettingsMenus';
|
||||
import { FbTaskEditSheet } from '../../components/FbTaskEditSheet';
|
||||
import { setTaskStatus } from '../../data/FbTaskRepo';
|
||||
import { FB_TOKEN_STORE } from '../../data/FbTokenStore';
|
||||
import { FbApiResult } from '../../data/FbHttp';
|
||||
|
||||
@ComponentV2
|
||||
export struct FbTasksPage {
|
||||
@@ -33,7 +39,6 @@ export struct FbTasksPage {
|
||||
@BuilderParam topBar: () => void;
|
||||
@Param app: FbAppState = fbAppState();
|
||||
|
||||
private boards: string[] = [];
|
||||
/** 模块主题色(任务 = 赭红) */
|
||||
private accent: string = '#A8574F';
|
||||
/**
|
||||
@@ -48,6 +53,36 @@ export struct FbTasksPage {
|
||||
@Local tasks: FbTaskItem[] = [];
|
||||
/** 当前筛选的看板('' = 全部) */
|
||||
@Local boardFilter: string = '';
|
||||
/**
|
||||
* 状态筛选('' = 全部;'done' = 只看已完成)。
|
||||
*
|
||||
* 🔴 v65:设置菜单里的「已完成」原来 `action === ''` ⇒ 点了不响应。
|
||||
* 网页版是 `?view=done`(`Task::doneList`),端上不换接口,
|
||||
* 直接在已拉到的整份列表上筛(数据本来就是全量,没必要多打一次网络)。
|
||||
*/
|
||||
@Local statusFilter: string = '';
|
||||
/**
|
||||
* 新建 / 编辑任务浮层是否打开。
|
||||
*
|
||||
* 🔴 v65(用户 2026-10-20):「任务也是一样啊,任务也点不进去,也没法那个完成,
|
||||
* 新建任务、设置这些东西都这都没有。」
|
||||
* ⇒ 原来「新建任务」按钮**没有 `onTap`**、列表项**没有 `onClick`**,
|
||||
* 勾完成的那个圈也**没有热区** —— 三件事一件都没接。现在都接上了。
|
||||
*/
|
||||
@Local editOpen: boolean = false;
|
||||
/** 正在编辑的任务(0 = 新建) */
|
||||
@Local editingId: number = 0;
|
||||
@Local editingTitle: string = '';
|
||||
@Local editingNote: string = '';
|
||||
/** `2026-10-25 18:00`;空 = 没有期限 */
|
||||
@Local editingDueAt: string = '';
|
||||
@Local editingBoardId: number = 0;
|
||||
/** 正在改状态的那条(防连点打重复请求) */
|
||||
@Local busyId: number = 0;
|
||||
/** 「分类与看板」浮层是否打开 */
|
||||
@Local boardSheetOpen: boolean = false;
|
||||
/** 操作失败时的一行红字(如勾完成失败) */
|
||||
@Local opNote: string = '';
|
||||
|
||||
/**
|
||||
* 页面出现:先读缓存、再拉接口(本地优先,见 FbModuleRepo 的说明)。
|
||||
@@ -65,6 +100,16 @@ export struct FbTasksPage {
|
||||
}
|
||||
|
||||
private backOnce(): boolean {
|
||||
/* v65:返回手势要**先关新的浮层**,再关设置菜单 ——
|
||||
顺序按"后打开的在前",否则按一次返回会跳关两层。 */
|
||||
if (this.editOpen) {
|
||||
this.editOpen = false;
|
||||
return true;
|
||||
}
|
||||
if (this.boardSheetOpen) {
|
||||
this.boardSheetOpen = false;
|
||||
return true;
|
||||
}
|
||||
if (this.settingsOpen) {
|
||||
this.settingsOpen = false;
|
||||
return true;
|
||||
@@ -102,6 +147,103 @@ export struct FbTasksPage {
|
||||
fbAppState().sheetCount = this.settingsOpen ? 1 : 0;
|
||||
}
|
||||
|
||||
/** 新建/编辑浮层开着 ⇒ 底部悬浮快捷栏也要让位(与 `settingsOpen` 不会同时开) */
|
||||
@Monitor('editOpen')
|
||||
onEditChanged(): void {
|
||||
fbAppState().sheetCount = this.editOpen ? 1 : 0;
|
||||
}
|
||||
|
||||
/** 「分类与看板」浮层同理 */
|
||||
@Monitor('boardSheetOpen')
|
||||
onBoardSheetChanged(): void {
|
||||
fbAppState().sheetCount = this.boardSheetOpen ? 1 : 0;
|
||||
}
|
||||
|
||||
/** 打开「新建」浮层(清空回填字段) */
|
||||
private openNew(): void {
|
||||
this.editingId = 0;
|
||||
this.editingTitle = '';
|
||||
this.editingNote = '';
|
||||
this.editingDueAt = '';
|
||||
this.editingBoardId = 0;
|
||||
this.opNote = '';
|
||||
this.editOpen = true;
|
||||
}
|
||||
|
||||
/** 打开「编辑」浮层(把这条任务的字段回填进去) */
|
||||
private openEdit(t: FbTaskItem): void {
|
||||
this.editingId = t.id;
|
||||
this.editingTitle = t.title;
|
||||
this.editingNote = t.note;
|
||||
this.editingDueAt = t.dueAt;
|
||||
this.editingBoardId = t.boardId;
|
||||
this.opNote = '';
|
||||
this.editOpen = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 勾选 / 取消完成。
|
||||
*
|
||||
* 🔴 **必须走 `/tasks/<id>/status`**:服务端 `PATCH /tasks/<id>` 会把
|
||||
* 请求里的 status **原样忽略**(见 `FbTaskRepo` 文件头的说明)
|
||||
* ⇒ 走 PATCH 会"看起来保存成功,但状态没变"。
|
||||
*
|
||||
* ⚠️ 已完成 → 取消完成统一回 `todo`(不回 `doing`:用户只想撤销一次误勾,
|
||||
* 把它标成"进行中"是替用户做了他没表达的决定)。
|
||||
*/
|
||||
private async toggleDone(t: FbTaskItem): Promise<void> {
|
||||
if (this.busyId !== 0) {
|
||||
return;
|
||||
}
|
||||
this.busyId = t.id;
|
||||
this.opNote = '';
|
||||
const next: string = t.status === 'done' ? 'todo' : 'done';
|
||||
const res: FbApiResult = await setTaskStatus(FB_TOKEN_STORE.get(), t.id, next);
|
||||
this.busyId = 0;
|
||||
if (!res.ok) {
|
||||
this.opNote = res.error !== '' ? res.error : '改状态失败,请稍后再试。';
|
||||
return;
|
||||
}
|
||||
// 本地先把这条改掉(列表立刻有反馈),再重拉一遍对齐服务端派生字段(逾期等)
|
||||
this.tasks = this.tasks.map((x: FbTaskItem): FbTaskItem => {
|
||||
if (x.id !== t.id) {
|
||||
return x;
|
||||
}
|
||||
const y: FbTaskItem = {
|
||||
id: x.id, title: x.title, status: next, board: x.board, boardColor: x.boardColor,
|
||||
dueText: x.dueText, overdue: next === 'done' ? false : x.overdue,
|
||||
assignee: x.assignee, childDone: x.childDone, childTotal: x.childTotal,
|
||||
boardId: x.boardId, note: x.note, dueAt: x.dueAt
|
||||
};
|
||||
return y;
|
||||
});
|
||||
this.load();
|
||||
}
|
||||
|
||||
/** 看板列表(从已加载的任务里反推:`/tasks` 的 boards 里没任务的那些画出来也没用) */
|
||||
private boardOpts(): FbBoardOpt[] {
|
||||
const out: FbBoardOpt[] = [];
|
||||
const seen: number[] = [];
|
||||
for (const t of this.tasks) {
|
||||
if (seen.indexOf(t.boardId) >= 0) {
|
||||
continue;
|
||||
}
|
||||
seen.push(t.boardId);
|
||||
out.push({ id: t.boardId, name: t.board, color: t.boardColor });
|
||||
}
|
||||
// 没归看板的「其他」放最后(它不是一个真的看板)
|
||||
return out.sort((a: FbBoardOpt, b: FbBoardOpt): number => {
|
||||
const ka: number = a.id === 0 ? 999999 : a.id;
|
||||
const kb: number = b.id === 0 ? 999999 : b.id;
|
||||
return ka - kb;
|
||||
});
|
||||
}
|
||||
|
||||
/** 某个看板下的任务数(「分类与看板」浮层里显示) */
|
||||
private countOf(boardName: string): number {
|
||||
return this.tasks.filter((t: FbTaskItem): boolean => t.board === boardName).length;
|
||||
}
|
||||
|
||||
build() {
|
||||
// 🔴 外层 Stack:**模块设置浮层**要浮在页面之上
|
||||
// (本页原来是 Scroll 直接作根,没有 Stack,这里补一层)
|
||||
@@ -129,7 +271,11 @@ export struct FbTasksPage {
|
||||
FbPrimaryButton({
|
||||
label: '新建任务',
|
||||
bg: this.accent,
|
||||
icon: $r('app.media.fb_ic_plus')
|
||||
icon: $r('app.media.fb_ic_plus'),
|
||||
/* 🔴 v65:接上回调。原来这颗按钮**没有 `onTap`** —— 纯摆设。 */
|
||||
onTap: (): void => {
|
||||
this.openNew();
|
||||
}
|
||||
})
|
||||
// 🔴 设置按钮 = 网页版那种**三条横线**(☰)—— 用户 2026-10-16。
|
||||
// 点开是本模块的设置菜单(条目照网页版 `templates/<模块>/_settings_menu.php`)。
|
||||
@@ -145,13 +291,43 @@ export struct FbTasksPage {
|
||||
.padding({ left: FbMetric.pagePad, right: FbMetric.pagePad, top: 12, bottom: 8 })
|
||||
.alignItems(VerticalAlign.Center)
|
||||
|
||||
// 操作失败的一行红字(如勾完成失败)—— 不弹 toast,就地说明
|
||||
if (this.opNote !== '') {
|
||||
Text(this.opNote)
|
||||
.fontSize(FbMetric.fontTiny)
|
||||
.fontColor(FbColors.red)
|
||||
.width('100%')
|
||||
.padding({ left: FbMetric.pagePad, right: FbMetric.pagePad, bottom: 6 })
|
||||
}
|
||||
|
||||
// ---- 看板筛选条(横向滚动)----
|
||||
Scroll() {
|
||||
Row({ space: 8 }) {
|
||||
this.boardChip('全部', '')
|
||||
ForEach(this.boards, (b: string) => {
|
||||
this.boardChip(b, b)
|
||||
}, (b: string): string => 'bd_' + b)
|
||||
/* v65:看板从已加载的任务里反推(原来这个数组**从来没被赋值** ⇒
|
||||
这条筛选条永远是空的,只剩一个「全部」) */
|
||||
ForEach(this.boardOpts(), (b: FbBoardOpt) => {
|
||||
this.boardChip(b.name, b.name)
|
||||
}, (b: FbBoardOpt): string => 'bd_' + b.id.toString())
|
||||
// 「只看已完成」是设置菜单打开的筛选 ⇒ 这里给个能取消的胶囊
|
||||
if (this.statusFilter === 'done') {
|
||||
Row({ space: 4 }) {
|
||||
Text('只看已完成')
|
||||
.fontSize(FbMetric.fontTiny)
|
||||
.fontColor(this.accent)
|
||||
Image($r('app.media.fb_ic_close'))
|
||||
.width(10)
|
||||
.height(10)
|
||||
.renderMode(ImageRenderMode.Template)
|
||||
.colorFilter(fbTint(this.accent))
|
||||
}
|
||||
.padding({ left: 10, right: 10, top: 6, bottom: 6 })
|
||||
.backgroundColor(fbAlpha(this.accent, 0.1))
|
||||
.borderRadius(FbMetric.radiusPill)
|
||||
.onClick((): void => {
|
||||
this.statusFilter = '';
|
||||
})
|
||||
}
|
||||
}
|
||||
.padding({ left: FbMetric.pagePad, right: FbMetric.pagePad })
|
||||
}
|
||||
@@ -222,17 +398,155 @@ export struct FbTasksPage {
|
||||
this.settingsOpen = false;
|
||||
},
|
||||
onPick: (action: string): void => {
|
||||
// 条目里 `action === ''` 的是「暂未开放」(组件里已画灰、点了不响应)
|
||||
// ⇒ 这里只需处理已实现的;目前都还没有,保持浮层开着即可。
|
||||
/* v65:这两条原来 `action === ''`(画灰、点了不响应)。
|
||||
现在都接上了:
|
||||
· taskdone → 只看已完成(对应网页版 `?view=done`)
|
||||
· taskboards → 看板列表(挑一个看板只看它;增删改看板仍在网页端) */
|
||||
if (action === 'taskdone') {
|
||||
this.statusFilter = 'done';
|
||||
this.settingsOpen = false;
|
||||
return;
|
||||
}
|
||||
if (action === 'taskboards') {
|
||||
this.boardSheetOpen = true;
|
||||
this.settingsOpen = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
})
|
||||
.transition(fbSheetTransition())
|
||||
}
|
||||
|
||||
// ---- 新建 / 编辑任务浮层(v65)----
|
||||
if (this.editOpen) {
|
||||
FbTaskEditSheet({
|
||||
accent: this.accent,
|
||||
boards: this.boardOpts(),
|
||||
editingId: this.editingId,
|
||||
editingTitle: this.editingTitle,
|
||||
editingNote: this.editingNote,
|
||||
editingDueAt: this.editingDueAt,
|
||||
editingBoardId: this.editingBoardId,
|
||||
onClose: (): void => {
|
||||
this.editOpen = false;
|
||||
},
|
||||
onSaved: (): void => {
|
||||
this.editOpen = false;
|
||||
// 服务端会派生逾期/看板色,保存后重拉一遍
|
||||
this.load();
|
||||
}
|
||||
})
|
||||
.transition(fbSheetTransition())
|
||||
}
|
||||
|
||||
// ---- 「分类与看板」浮层(v65)----
|
||||
if (this.boardSheetOpen) {
|
||||
/* 🔴 遮罩与卡片必须**叠**(`Stack`),不能当 `Column` 的子项"排" ——
|
||||
排会把卡片挤出屏幕(本项目 2026-10-20 真机事故,见 FbTaskEditSheet 同一说明)。 */
|
||||
Stack({ alignContent: Alignment.Center }) {
|
||||
Column()
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor(FB_MASK)
|
||||
.onClick((): void => {
|
||||
this.boardSheetOpen = false;
|
||||
})
|
||||
|
||||
Column() {
|
||||
FbSheetRing({ radius: FbMetric.radius, ringColor: this.accent }) {
|
||||
Column({ space: 12 }) {
|
||||
Row({ space: 8 }) {
|
||||
Column({ space: 2 }) {
|
||||
Text('切换看板')
|
||||
.fontSize(FbMetric.fontTitle)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.fontColor(FbColors.ink)
|
||||
Text('挑一个看板,只看它的任务')
|
||||
.fontSize(FbMetric.fontTiny)
|
||||
.fontColor(this.accent)
|
||||
}
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
.layoutWeight(1)
|
||||
.flexShrink(1)
|
||||
|
||||
FbSheetClose({
|
||||
onClose: (): void => {
|
||||
this.boardSheetOpen = false;
|
||||
},
|
||||
color: this.accent
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.alignItems(VerticalAlign.Center)
|
||||
|
||||
Scroll() {
|
||||
Column({ space: 2 }) {
|
||||
this.boardRow('全部', '', '', this.tasks.length)
|
||||
ForEach(this.boardOpts(), (b: FbBoardOpt) => {
|
||||
this.boardRow(b.name, b.name, b.color, this.countOf(b.name))
|
||||
}, (b: FbBoardOpt): string => 'bs_' + b.id.toString())
|
||||
}
|
||||
.width('100%')
|
||||
}
|
||||
.constraintSize({ maxHeight: 340 })
|
||||
.width('100%')
|
||||
.scrollBar(BarState.Off)
|
||||
.align(Alignment.TopStart)
|
||||
|
||||
Text('增删改看板、改分类,仍在网页端「任务 → 分类与看板」里做。')
|
||||
.fontSize(FbMetric.fontTiny)
|
||||
.fontColor(FbColors.faint)
|
||||
.width('100%')
|
||||
.maxLines(2)
|
||||
}
|
||||
.width('100%')
|
||||
.padding({ left: 18, right: 18, top: 18, bottom: 18 })
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
}
|
||||
}
|
||||
.width('92%')
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.hitTestBehavior(HitTestMode.Transparent)
|
||||
.transition(fbSheetTransition())
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
}
|
||||
|
||||
/** 「分类与看板」浮层里的一行:色点 + 名字 + 条数(点它切筛选) */
|
||||
@Builder
|
||||
boardRow(label: string, key: string, color: string, count: number) {
|
||||
Row({ space: 8 }) {
|
||||
FbDot({ dia: 8, fillC: color !== '' ? color : this.accent })
|
||||
Text(label)
|
||||
.fontSize(FbMetric.fontSmall)
|
||||
.fontColor(this.boardFilter === key ? this.accent : FbColors.ink)
|
||||
.layoutWeight(1)
|
||||
.maxLines(1)
|
||||
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||
Text(count.toString())
|
||||
.fontSize(FbMetric.fontTiny)
|
||||
.fontColor(FbColors.faint)
|
||||
if (this.boardFilter === key) {
|
||||
Image($r('app.media.fb_ic_check'))
|
||||
.width(12)
|
||||
.height(12)
|
||||
.renderMode(ImageRenderMode.Template)
|
||||
.colorFilter(fbTint(this.accent))
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.padding({ left: 6, right: 6, top: 11, bottom: 11 })
|
||||
.alignItems(VerticalAlign.Center)
|
||||
.onClick((): void => {
|
||||
this.boardFilter = key;
|
||||
this.boardSheetOpen = false;
|
||||
})
|
||||
}
|
||||
|
||||
/** 看板筛选胶囊 */
|
||||
@Builder
|
||||
boardChip(label: string, key: string) {
|
||||
@@ -265,17 +579,30 @@ export struct FbTasksPage {
|
||||
.backgroundColor(FbColors.paper)
|
||||
}
|
||||
|
||||
/** 一张任务卡 */
|
||||
/** 一张任务卡(整卡可点 → 打开编辑;左边的圈单独点 → 勾完成) */
|
||||
@Builder
|
||||
taskCard(t: FbTaskItem) {
|
||||
Column({ space: 8 }) {
|
||||
Row({ space: 10 }) {
|
||||
// 状态圈:完成=实心+勾、进行中=实心+白点、待办=空心
|
||||
FbCheckCircle({
|
||||
dia: 16,
|
||||
done: t.status === 'done',
|
||||
doing: t.status === 'doing',
|
||||
color: this.accent
|
||||
/* 状态圈 + 一块透明热区。
|
||||
🔴 v65:原来这个圈只有 16vp 且**没有 `onClick`** ⇒
|
||||
「没法那个完成」就是这条 —— 点它什么都不发生。
|
||||
⇒ 外面包一层 32×32 的热区(手指点得中),并接上改状态。
|
||||
⚠️ 内层有点击时父级的整卡点击**不会**再触发(ArkUI 由最内层消费),
|
||||
所以勾完成不会顺带弹出编辑浮层。 */
|
||||
Stack({ alignContent: Alignment.Center }) {
|
||||
FbCheckCircle({
|
||||
dia: 16,
|
||||
done: t.status === 'done',
|
||||
doing: t.status === 'doing',
|
||||
color: this.accent
|
||||
})
|
||||
}
|
||||
.width(32)
|
||||
.height(32)
|
||||
.flexShrink(0)
|
||||
.onClick((): void => {
|
||||
this.toggleDone(t);
|
||||
})
|
||||
|
||||
Text(t.title)
|
||||
@@ -336,16 +663,42 @@ export struct FbTasksPage {
|
||||
.borderRadius(FbMetric.radius)
|
||||
.margin({ bottom: 8 })
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
/* 🔴 v65:整卡可点 → 打开编辑(原来列表项**没有 `onClick`** ⇒ "点不进去") */
|
||||
.onClick((): void => {
|
||||
this.openEdit(t);
|
||||
})
|
||||
}
|
||||
|
||||
private filtered(): FbTaskItem[] {
|
||||
if (this.boardFilter.length === 0) {
|
||||
return this.tasks;
|
||||
let list: FbTaskItem[] = this.tasks;
|
||||
if (this.boardFilter.length > 0) {
|
||||
list = list.filter((t: FbTaskItem): boolean => t.board === this.boardFilter);
|
||||
}
|
||||
return this.tasks.filter((t: FbTaskItem): boolean => t.board === this.boardFilter);
|
||||
/* v65:设置里的「已完成」(对应网页版 `?view=done`)。
|
||||
⚠️ 只看已完成时**不再按状态分组**(一份列表里只有一个组,分组头就没意义了),
|
||||
见 `groups()`。 */
|
||||
if (this.statusFilter === 'done') {
|
||||
list = list.filter((t: FbTaskItem): boolean => t.status === 'done');
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private groups(): FbGroup<FbTaskItem>[] {
|
||||
if (this.statusFilter === 'done') {
|
||||
const items: FbTaskItem[] = this.filtered();
|
||||
if (items.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const one: FbGroup<FbTaskItem> = {
|
||||
key: 'done',
|
||||
title: '已完成',
|
||||
items: items,
|
||||
count: items.length.toString() + ' 项'
|
||||
};
|
||||
const only: FbGroup<FbTaskItem>[] = [];
|
||||
only.push(one);
|
||||
return only;
|
||||
}
|
||||
return fbGroupTask(this.filtered());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user