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:
@@ -19,6 +19,7 @@ import { FB_DOCK_RESERVE } from '../../components/FloatDock';
|
||||
import { fbOnScroll, fbOnTouch } from '../../common/FbScroll';
|
||||
import { fbMaskTransition, fbSheetTransition } from '../../common/FbAnim';
|
||||
import { FbModuleSettingsSheet } from '../../components/FbModuleSettingsSheet';
|
||||
import { FbResourceSheet } from '../../components/FbResourceSheet';
|
||||
import { FB_BACK } from '../../common/FbBack';
|
||||
import { FB_SET_RESOURCES } from '../../model/FbSettingsMenus';
|
||||
|
||||
@@ -44,8 +45,24 @@ export struct FbResourcesPage {
|
||||
@Local settingsOpen: boolean = false;
|
||||
|
||||
@Local all: FbResourceItem[] = [];
|
||||
/** 当前筛选类别('' = 全部) */
|
||||
@Local kindFilter: string = '';
|
||||
/**
|
||||
* 当前筛选范围:'' = 全部 / 'shared' = 共享给我的 / 'mine' = 我名下的。
|
||||
*
|
||||
* 🔴 v65:原来这里是「证件 / 资料」两个类别 —— 服务端 `resources` 表
|
||||
* **没有类别列**(`app/Schema.php` 只有 title / content / owner_id),
|
||||
* 解析时 kind 只能全填 `other` ⇒ 这两个胶囊点了永远是空列表。
|
||||
* 改成按**权限/归属**筛:这两个维度服务端真的给(`perm` / `owner_id`)。
|
||||
*/
|
||||
@Local scopeFilter: string = '';
|
||||
|
||||
/** 资源浮层(新建 / 查看 / 编辑 / 删除)是否打开 */
|
||||
@Local sheetOpen: boolean = false;
|
||||
/** 浮层里那条(0 = 新建) */
|
||||
@Local sheetId: number = 0;
|
||||
@Local sheetTitle: string = '';
|
||||
@Local sheetContent: string = '';
|
||||
@Local sheetOwner: string = '';
|
||||
@Local sheetCanWrite: boolean = true;
|
||||
|
||||
/**
|
||||
* 页面出现:先读缓存、再拉接口(本地优先,见 FbModuleRepo 的说明)。
|
||||
@@ -63,6 +80,10 @@ export struct FbResourcesPage {
|
||||
}
|
||||
|
||||
private backOnce(): boolean {
|
||||
if (this.sheetOpen) {
|
||||
this.sheetOpen = false;
|
||||
return true;
|
||||
}
|
||||
if (this.settingsOpen) {
|
||||
this.settingsOpen = false;
|
||||
return true;
|
||||
@@ -100,6 +121,34 @@ export struct FbResourcesPage {
|
||||
fbAppState().sheetCount = this.settingsOpen ? 1 : 0;
|
||||
}
|
||||
|
||||
/** 资源浮层开着 ⇒ 底部悬浮快捷栏同样让位(两个浮层不会同时开) */
|
||||
@Monitor('sheetOpen')
|
||||
onResourceSheetChanged(): void {
|
||||
fbAppState().sheetCount = this.sheetOpen ? 1 : 0;
|
||||
}
|
||||
|
||||
/** 打开「新增资源」 */
|
||||
private openNew(): void {
|
||||
this.sheetId = 0;
|
||||
this.sheetTitle = '';
|
||||
this.sheetContent = '';
|
||||
this.sheetOwner = '';
|
||||
this.sheetCanWrite = true;
|
||||
this.sheetOpen = true;
|
||||
}
|
||||
|
||||
/** 打开某条资源(只读共享进来的锁输入框,但内容照看) */
|
||||
private openDetail(r: FbResourceItem): void {
|
||||
this.sheetId = r.id;
|
||||
this.sheetTitle = r.name;
|
||||
this.sheetContent = r.content;
|
||||
this.sheetOwner = r.ownerName;
|
||||
/* `perm` 是服务端 `Resource::all` 里算好的:owner / write / read。
|
||||
⚠️ 只有 owner 与 write 能改(服务端 `Resource::canWrite` 同一口径)。 */
|
||||
this.sheetCanWrite = r.perm === 'owner' || r.perm === 'write';
|
||||
this.sheetOpen = true;
|
||||
}
|
||||
|
||||
build() {
|
||||
// 🔴 外层 Stack:**模块设置浮层**要浮在页面之上
|
||||
// (本页原来是 Scroll 直接作根,没有 Stack,这里补一层)
|
||||
@@ -126,7 +175,12 @@ export struct FbResourcesPage {
|
||||
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`)。
|
||||
@@ -142,11 +196,11 @@ export struct FbResourcesPage {
|
||||
.padding({ left: FbMetric.pagePad, right: FbMetric.pagePad, top: 12, bottom: 8 })
|
||||
.alignItems(VerticalAlign.Center)
|
||||
|
||||
// ---- 类别筛选 ----
|
||||
// ---- 筛选(全部 / 共享给我 / 我名下)----
|
||||
Row({ space: 8 }) {
|
||||
this.kindChip('全部', '')
|
||||
this.kindChip('证件', 'document')
|
||||
this.kindChip('资料', 'material')
|
||||
this.scopeChip('全部', '')
|
||||
this.scopeChip('共享给我', 'shared')
|
||||
this.scopeChip('我名下', 'mine')
|
||||
Blank()
|
||||
Text('共享给我 ' + this.sharedCount().toString() + ' 项')
|
||||
.fontSize(FbMetric.fontTiny)
|
||||
@@ -216,8 +270,41 @@ export struct FbResourcesPage {
|
||||
this.settingsOpen = false;
|
||||
},
|
||||
onPick: (action: string): void => {
|
||||
// 条目里 `action === ''` 的是「暂未开放」(组件里已画灰、点了不响应)
|
||||
// ⇒ 这里只需处理已实现的;目前都还没有,保持浮层开着即可。
|
||||
/* v65:两条都接上了(原来都是空串 ⇒ 画灰、点了不响应) */
|
||||
if (action === 'resourceShared') {
|
||||
this.scopeFilter = 'shared';
|
||||
this.settingsOpen = false;
|
||||
return;
|
||||
}
|
||||
if (action === 'resourceMine') {
|
||||
this.scopeFilter = 'mine';
|
||||
this.settingsOpen = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
})
|
||||
.transition(fbSheetTransition())
|
||||
}
|
||||
|
||||
// ---- 资源浮层:新建 / 查看 / 编辑 / 删除(v65)----
|
||||
if (this.sheetOpen) {
|
||||
FbResourceSheet({
|
||||
accent: this.accent,
|
||||
editingId: this.sheetId,
|
||||
editingTitle: this.sheetTitle,
|
||||
editingContent: this.sheetContent,
|
||||
ownerName: this.sheetOwner,
|
||||
canWrite: this.sheetCanWrite,
|
||||
onClose: (): void => {
|
||||
this.sheetOpen = false;
|
||||
},
|
||||
onSaved: (): void => {
|
||||
this.sheetOpen = false;
|
||||
this.load();
|
||||
},
|
||||
onDeleted: (): void => {
|
||||
this.sheetOpen = false;
|
||||
this.load();
|
||||
}
|
||||
})
|
||||
.transition(fbSheetTransition())
|
||||
@@ -227,13 +314,13 @@ export struct FbResourcesPage {
|
||||
.height('100%')
|
||||
}
|
||||
|
||||
/** 一项资源卡 */
|
||||
/** 一项资源卡(整卡可点 → 打开详情/编辑) */
|
||||
@Builder
|
||||
resourceCard(r: FbResourceItem) {
|
||||
Row({ space: 12 }) {
|
||||
// 类别图标底
|
||||
// 图标底:共享来的用「共享」图标,自己名下的用「锁」
|
||||
Stack({ alignContent: Alignment.Center }) {
|
||||
Image(this.kindIcon(r.kind))
|
||||
Image(r.shared ? $r('app.media.fb_ic_share') : $r('app.media.fb_ic_lock'))
|
||||
.width(19)
|
||||
.height(19)
|
||||
.renderMode(ImageRenderMode.Template)
|
||||
@@ -254,26 +341,26 @@ export struct FbResourcesPage {
|
||||
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||
.layoutWeight(1)
|
||||
if (r.shared) {
|
||||
FbTag({ text: '已共享', tone: 'green' })
|
||||
FbTag({ text: r.perm === 'write' ? '可改' : '只读', tone: 'green' })
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.alignItems(VerticalAlign.Center)
|
||||
|
||||
// 正文预览:资源的正文就是"编号、有效期、放在哪" —— 比附件数有用得多
|
||||
if (r.content !== '') {
|
||||
Text(r.content)
|
||||
.fontSize(10)
|
||||
.fontColor(FbColors.muted)
|
||||
.maxLines(1)
|
||||
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||
.width('100%')
|
||||
}
|
||||
|
||||
Row({ space: 10 }) {
|
||||
Text('归属 ' + r.ownerName)
|
||||
.fontSize(10)
|
||||
.fontColor(FbColors.muted)
|
||||
Row({ space: 3 }) {
|
||||
Image($r('app.media.fb_ic_resources'))
|
||||
.width(11)
|
||||
.height(11)
|
||||
.renderMode(ImageRenderMode.Template)
|
||||
.colorFilter(fbTint(FbTint.faint))
|
||||
Text(r.fileCount.toString() + ' 个附件')
|
||||
.fontSize(10)
|
||||
.fontColor(FbColors.faint)
|
||||
}
|
||||
Text(r.updatedAt)
|
||||
.fontSize(10)
|
||||
.fontColor(FbColors.faint)
|
||||
@@ -295,18 +382,23 @@ export struct FbResourcesPage {
|
||||
.borderRadius(FbMetric.radius)
|
||||
.margin({ bottom: 8 })
|
||||
.alignItems(VerticalAlign.Center)
|
||||
/* 🔴 v65:整卡可点 → 打开详情(原来列表项**没有 `onClick`** ⇒ "点不进去") */
|
||||
.onClick((): void => {
|
||||
this.openDetail(r);
|
||||
})
|
||||
}
|
||||
|
||||
/** 筛选胶囊(全部 / 共享给我 / 我名下) */
|
||||
@Builder
|
||||
kindChip(label: string, key: string) {
|
||||
scopeChip(label: string, key: string) {
|
||||
Text(label)
|
||||
.fontSize(FbMetric.fontSmall)
|
||||
.fontColor(this.kindFilter === key ? Color.White : FbColors.muted)
|
||||
.backgroundColor(this.kindFilter === key ? this.accent : FbColors.inputBg)
|
||||
.fontColor(this.scopeFilter === key ? Color.White : FbColors.muted)
|
||||
.backgroundColor(this.scopeFilter === key ? this.accent : FbColors.inputBg)
|
||||
.padding({ left: 12, right: 12, top: 6, bottom: 6 })
|
||||
.borderRadius(FbMetric.radiusPill)
|
||||
.onClick(() => {
|
||||
this.kindFilter = key;
|
||||
this.scopeFilter = key;
|
||||
})
|
||||
}
|
||||
|
||||
@@ -327,21 +419,15 @@ export struct FbResourcesPage {
|
||||
.backgroundColor(FbColors.paper)
|
||||
}
|
||||
|
||||
private kindIcon(kind: string): Resource {
|
||||
if (kind === 'document') {
|
||||
return $r('app.media.fb_ic_lock');
|
||||
}
|
||||
if (kind === 'material') {
|
||||
return $r('app.media.fb_ic_book');
|
||||
}
|
||||
return $r('app.media.fb_ic_resources');
|
||||
}
|
||||
|
||||
private filtered(): FbResourceItem[] {
|
||||
if (this.kindFilter.length === 0) {
|
||||
if (this.scopeFilter.length === 0) {
|
||||
return this.all;
|
||||
}
|
||||
return this.all.filter((r: FbResourceItem): boolean => r.kind === this.kindFilter);
|
||||
if (this.scopeFilter === 'shared') {
|
||||
// 共享给我的 = 权限不是 owner 的那些
|
||||
return this.all.filter((r: FbResourceItem): boolean => r.shared);
|
||||
}
|
||||
return this.all.filter((r: FbResourceItem): boolean => !r.shared);
|
||||
}
|
||||
|
||||
private groups(): FbGroup<FbResourceItem>[] {
|
||||
|
||||
Reference in New Issue
Block a user