v79 端上:任务面板(首页/任务页共用)+ 任务模块功能补齐
用户原话:「鸿蒙端的功能,也需要同样适配,在首页上可以直接修改编辑任务,
另外任务模块的功能需要完善。」
端上原来只有"看列表 / 勾完成 / 新建改标题",网页 v78 那套「就地处理」
(改状态、挪分组、子任务、附件、留言、删除)一件都没有;首页点任务
弹的还是 v73 的只读卡。
一、新增 FbTaskPanel(首页与任务页共用同一组件)
· 改状态三段(待办/进行中/已完成)+ 标题左侧状态圈
· 挪看板 chips、勾/加子任务、加图片附件并删、发留言
· 编辑 → 交给宿主开 FbTaskEditSheet;删除要**点两次**(端上没有 undo)
· 每个动作成功后再 getTask() 重拉一次:一次动作会牵动子任务计数、
附件张数、看板色,逐处同步 DOM 必然漏一处
二、退役 FbTaskDetailSheet(v73 只读卡,387 行)
⚠️ 它已无人挂载,而守卫还在逐条"通过" —— 等于给死代码盖章。
三、任务模块补齐
· 卡片点击 → 面板(不再直接进编辑表单:误触一下就开始改标题,
且子任务/附件/留言没地方放)
· 「只看已完成」改真打 ?view=done:看板视图服务端就写死
status <> 'done',在客户端筛永远是空
· 看板列表改走 ?view=boards:原来从任务反推 ⇒ 空看板永远选不到
· 编辑表单补分类/循环两排
四、顺带修掉一个自查发现的真 bug
任务页里 sheetCount 有**两个** @Monitor 都监听 boardSheetOpen、都写同一个值
⇒ 关掉设置浮层时谁最后执行不确定,会把还开着的面板"顺便让位结束",
底部悬浮栏浮上来盖住面板按钮。已并成一个取并集的 monitor。
服务端(另一仓):新增 GET /tasks?view=boards、POST/DELETE /tasks/<id>/attach,
详情补 board_name/board_color_calc,越权删别条任务的附件 → 404。
验证:静态守卫 1055/0(新增 v79 一组,含"全页只许一个 sheetCount 赋值点")、
反向验证 215/0(新增 15 条注入,逐条证明新断言会红)、
服务端 e2e 1558/0、_fb_v79_api.py 26/0、编译通过并已装机。
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
import { FbColors, FbMetric, FB_MASK, fbAlpha, fbTint } from '../common/Theme';
|
||||
import { FbBoardOpt } from '../model/Types';
|
||||
import { FbBoardOpt, FbCatOpt } from '../model/Types';
|
||||
import { FbSheetClose } from './FbSheetClose';
|
||||
import { FbSheetRing } from './FbSheetRing';
|
||||
import { FbDateTimeRow, FbDateTimePicker, fbIsoOf, fbJoinDateTime } from './FbDateTimeField';
|
||||
@@ -25,14 +25,19 @@ import { FbApiResult } from '../data/FbHttp';
|
||||
export struct FbTaskEditSheet {
|
||||
/** 模块主题色(任务 = 赭红) */
|
||||
@Param accent: string = '#A8574F';
|
||||
/** 可选的看板(父页面从已加载任务里反推出来) */
|
||||
/** 可选的看板(父页面用 `?view=boards` 拿**全部**看板,含空看板) */
|
||||
@Param boards: FbBoardOpt[] = [];
|
||||
/** 可选的分类(v79;同上,来自 `?view=boards` 的 categories) */
|
||||
@Param cats: FbCatOpt[] = [];
|
||||
/** 编辑的这条(0 = 新建) */
|
||||
@Param editingId: number = 0;
|
||||
@Param editingTitle: string = '';
|
||||
@Param editingNote: string = '';
|
||||
@Param editingDueAt: string = '';
|
||||
@Param editingBoardId: number = 0;
|
||||
/** v79:分类 / 循环(编辑时回填) */
|
||||
@Param editingCatId: number = 0;
|
||||
@Param editingRepeat: string = '';
|
||||
|
||||
@Event onClose: () => void = (): void => {};
|
||||
@Event onSaved: () => void = (): void => {};
|
||||
@@ -40,6 +45,10 @@ export struct FbTaskEditSheet {
|
||||
@Local title: string = '';
|
||||
@Local note: string = '';
|
||||
@Local boardId: number = 0;
|
||||
/** v79:分类 id(0 = 不分类) */
|
||||
@Local catId: number = 0;
|
||||
/** v79:循环规则('' = 不循环) */
|
||||
@Local repeat: string = '';
|
||||
/** 截止日期 `YYYY-MM-DD`,空 = 没有期限 */
|
||||
@Local dueDate: string = '';
|
||||
/** 截止时分 */
|
||||
@@ -52,6 +61,8 @@ export struct FbTaskEditSheet {
|
||||
this.title = this.editingTitle;
|
||||
this.note = this.editingNote;
|
||||
this.boardId = this.editingBoardId;
|
||||
this.catId = this.editingCatId;
|
||||
this.repeat = this.editingRepeat;
|
||||
// `2026-10-25 18:00` → 日期 + 时分(服务端给的是空格分隔)
|
||||
const raw: string = this.editingDueAt.trim();
|
||||
if (raw.length >= 16) {
|
||||
@@ -196,11 +207,58 @@ export struct FbTaskEditSheet {
|
||||
}
|
||||
.width('100%')
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
// ---- 分类(v79)----
|
||||
if (this.cats.length > 0) {
|
||||
Column({ space: 6 }) {
|
||||
Text('分类')
|
||||
.fontSize(FbMetric.fontTiny)
|
||||
.fontColor(FbColors.faint)
|
||||
Scroll() {
|
||||
Row({ space: 8 }) {
|
||||
this.catChip(0, '不分类')
|
||||
ForEach(this.cats, (c: FbCatOpt) => {
|
||||
this.catChip(c.id, c.name)
|
||||
}, (c: FbCatOpt): string => 'tc_' + c.id.toString())
|
||||
}
|
||||
.padding({ right: 4 })
|
||||
}
|
||||
.scrollable(ScrollDirection.Horizontal)
|
||||
.scrollBar(BarState.Off)
|
||||
.width('100%')
|
||||
}
|
||||
.width('100%')
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
}
|
||||
|
||||
/* ---- 循环(v79)----
|
||||
⚠️ 循环的"生成下一条"是**服务端**做的(`Task::setStatus` 完成时
|
||||
spawnNext),端上只需要把 `repeat_rule` 存进去 —— 别在这儿
|
||||
自己再排一遍,否则会出现两条一模一样的任务。 */
|
||||
Column({ space: 6 }) {
|
||||
Text('循环')
|
||||
.fontSize(FbMetric.fontTiny)
|
||||
.fontColor(FbColors.faint)
|
||||
Scroll() {
|
||||
Row({ space: 8 }) {
|
||||
this.repeatChip('', '不循环')
|
||||
this.repeatChip('day', '每天')
|
||||
this.repeatChip('week', '每周')
|
||||
this.repeatChip('month', '每月')
|
||||
this.repeatChip('year', '每年')
|
||||
}
|
||||
.padding({ right: 4 })
|
||||
}
|
||||
.scrollable(ScrollDirection.Horizontal)
|
||||
.scrollBar(BarState.Off)
|
||||
.width('100%')
|
||||
}
|
||||
.width('100%')
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
}
|
||||
.width('100%')
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
}
|
||||
.constraintSize({ maxHeight: 360 })
|
||||
.constraintSize({ maxHeight: 430 })
|
||||
.width('100%')
|
||||
.scrollBar(BarState.Off)
|
||||
.align(Alignment.TopStart)
|
||||
@@ -274,7 +332,13 @@ export struct FbTaskEditSheet {
|
||||
// 没有期限就发空串(服务端 `Api::dt('due_at', '')` → null)
|
||||
dueAt: this.dueDate !== '' ? fbJoinDateTime(this.dueDate, this.dueTime) : '',
|
||||
boardId: this.boardId,
|
||||
status: 'todo'
|
||||
status: 'todo',
|
||||
/* 0 = 顶层任务(新建子任务走 `FbTaskPanel.addKid`,不在这里) */
|
||||
parentId: 0,
|
||||
/* -1 = 这次不改负责人:表单里没有这一项,传 0 会把已指派的负责人清空 */
|
||||
assigneeId: -1,
|
||||
categoryId: this.catId,
|
||||
repeat: this.repeat
|
||||
};
|
||||
const token: string = FB_TOKEN_STORE.get();
|
||||
const res: FbApiResult = this.editingId > 0
|
||||
@@ -302,6 +366,34 @@ export struct FbTaskEditSheet {
|
||||
})
|
||||
}
|
||||
|
||||
/** 分类单选胶囊(v79) */
|
||||
@Builder
|
||||
catChip(id: number, name: string) {
|
||||
Text(name)
|
||||
.fontSize(FbMetric.fontTiny)
|
||||
.fontColor(this.catId === id ? '#FFFFFF' : FbColors.muted)
|
||||
.padding({ left: 10, right: 10, top: 6, bottom: 6 })
|
||||
.backgroundColor(this.catId === id ? this.accent : FbColors.inputBg)
|
||||
.borderRadius(FbMetric.radiusPill)
|
||||
.onClick((): void => {
|
||||
this.catId = id;
|
||||
})
|
||||
}
|
||||
|
||||
/** 循环单选胶囊(v79;'' = 不循环) */
|
||||
@Builder
|
||||
repeatChip(v: string, name: string) {
|
||||
Text(name)
|
||||
.fontSize(FbMetric.fontTiny)
|
||||
.fontColor(this.repeat === v ? '#FFFFFF' : FbColors.muted)
|
||||
.padding({ left: 10, right: 10, top: 6, bottom: 6 })
|
||||
.backgroundColor(this.repeat === v ? this.accent : FbColors.inputBg)
|
||||
.borderRadius(FbMetric.radiusPill)
|
||||
.onClick((): void => {
|
||||
this.repeat = v;
|
||||
})
|
||||
}
|
||||
|
||||
@Builder
|
||||
textField(label: string, placeholder: string, value: string, onChange: (v: string) => void) {
|
||||
Row({ space: 8 }) {
|
||||
|
||||
Reference in New Issue
Block a user