资源:点列表进只读详情,附件可预览/下载,编辑走底部按钮分离 laoyang/FamilyBook#29

用户原话(2026-10-28):「资源模块,点击资源后是编辑,那怎么下载资源
里面的文件呢?应该和名册一样,点击后是详情,属于谁、共享给谁、附件,
可以打开预览然后下载。下面有按钮可以编辑,点编辑之后才是编辑功能。」

原来 FbResourceSheet 是「查看=编辑」合体:点列表直接进可编辑框,附件区
点不动、没有预览/下载。这次拆成两级:

1) 新增 FbResourceDetailSheet(只读详情):标题/正文纯文本、归属人、
   共享列表、附件列表(图片点开全屏预览、非图片点开交给系统「打开方式」、
   每条附件可「下载」)。底部「编辑」按钮(仅 owner/write)→ 切编辑浮层。
2) FbResourcesPage 编排:点列表 → 详情;详情「编辑」→ 原 FbResourceSheet;
   编辑保存/删除回列表。 + 新建仍直接进编辑浮层。
3) 新增 common/FbAttachOpen.ets:附件「下载明文 / 打开发 / 存相册 / 另存为」
   的端上工具。走服务端 media.php 的移动端出口(能力早已就绪,纯端上改动)。
   · 存相册:photoAccessHelper.showAssetsCreationDialog(系统弹窗,无需 WRITE 权限)
   · 另存为:picker.DocumentViewPicker.save
   · 系统打开:隐式 Want viewData + 读授权 flag

编译 BUILD SUCCESSFUL;守卫 _fb_arkts_guard.js 1324/0(浮层计数清单已同步
resources 1→3 模板、books 3→4 补 #28 存量、cardN 42→44)。
This commit is contained in:
2026-10-28 23:53:53 +08:00
parent f5a979f5c8
commit fd3ea53086
3 changed files with 789 additions and 7 deletions
@@ -20,6 +20,11 @@ import { fbOnScroll, fbOnTouch } from '../../common/FbScroll';
import { fbMaskTransition, fbSheetTransition } from '../../common/FbAnim';
import { FbModuleSettingsSheet } from '../../components/FbModuleSettingsSheet';
import { FbResourceSheet } from '../../components/FbResourceSheet';
import { FbResourceDetailSheet } from '../../components/FbResourceDetailSheet';
import { fbAttachOpen, fbAttachSave } from '../../common/FbAttachOpen';
import { FB_TOKEN_STORE } from '../../data/FbTokenStore';
import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { FB_BACK } from '../../common/FbBack';
import { FB_SET_RESOURCES } from '../../model/FbSettingsMenus';
@@ -64,6 +69,15 @@ export struct FbResourcesPage {
@Local sheetOwner: string = '';
@Local sheetCanWrite: boolean = true;
// ---- 工单 #29:详情 / 编辑分离 ----
/** 只读详情浮层是否打开 */
@Local detailOpen: boolean = false;
@Local detailId: number = 0;
@Local detailTitle: string = '';
@Local detailContent: string = '';
@Local detailOwner: string = '';
@Local detailCanWrite: boolean = false;
/**
* 页面出现:先读缓存、再拉接口(本地优先,见 FbModuleRepo 的说明)。
*
@@ -80,6 +94,10 @@ export struct FbResourcesPage {
}
private backOnce(): boolean {
if (this.detailOpen) {
this.detailOpen = false;
return true;
}
if (this.sheetOpen) {
this.sheetOpen = false;
return true;
@@ -127,6 +145,12 @@ export struct FbResourcesPage {
fbAppState().sheetCount = this.sheetOpen ? 1 : 0;
}
/* 🔴 工单 #29:详情浮层开着也要让位(与编辑浮层同规则) */
@Monitor('detailOpen')
onResourceDetailChanged(): void {
fbAppState().sheetCount = (this.sheetOpen || this.detailOpen) ? 1 : 0;
}
/** 打开「新增资源」 */
private openNew(): void {
this.sheetId = 0;
@@ -139,16 +163,75 @@ export struct FbResourcesPage {
/** 打开某条资源(只读共享进来的锁输入框,但内容照看) */
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';
/* 🔴 工单 #29:点列表 → **只读详情**(不再直接进可编辑框)。
详情里归属人 / 正文 / 共享 / 附件一览无余,下面一个「编辑」按钮,
点了才进编辑浮层(`openEditFromDetail`)。 */
this.detailId = r.id;
this.detailTitle = r.name;
this.detailContent = r.content;
this.detailOwner = r.ownerName;
this.detailCanWrite = r.perm === 'owner' || r.perm === 'write';
this.detailOpen = true;
}
/** 从详情点「编辑」→ 关详情、开编辑浮层 */
private openEditFromDetail(): void {
this.sheetId = this.detailId;
this.sheetTitle = this.detailTitle;
this.sheetContent = this.detailContent;
this.sheetOwner = this.detailOwner;
this.sheetCanWrite = this.detailCanWrite;
this.detailOpen = false;
this.sheetOpen = true;
}
/** 拿稳妥的 UIAbilityContext(打开/保存附件要它;拿不到返回 undefined) */
private abilityCtx(): common.UIAbilityContext | undefined {
try {
return this.getUIContext().getHostContext() as common.UIAbilityContext | undefined;
} catch (err) {
hilog.warn(0x0000, 'FamilyBook', '取 Ability Context 失败:%{public}s', JSON.stringify(err));
return undefined;
}
}
/** 打开一个非图片附件(调系统打开方式) */
private async openFile(key: string, name: string): Promise<void> {
void name;
const ctx: common.UIAbilityContext | undefined = this.abilityCtx();
if (ctx === undefined) {
this.toast('打开的上下文不可用,请重进本页再试。');
return;
}
const err: string = await fbAttachOpen(FB_TOKEN_STORE.get(), key, false, ctx);
if (err !== '') {
this.toast(err);
}
}
/** 下载 / 保存一个附件(图片存相册、非图片另存为) */
private async saveAttach(key: string, name: string, isImage: boolean): Promise<void> {
const ctx: common.UIAbilityContext | undefined = this.abilityCtx();
if (ctx === undefined) {
this.toast('保存的上下文不可用,请重进本页再试。');
return;
}
const err: string = await fbAttachSave(FB_TOKEN_STORE.get(), key, name, isImage, ctx);
if (err !== '') {
this.toast(err);
} else {
this.toast('已保存。');
}
}
private toast(msg: string): void {
try {
this.getUIContext().getPromptAction().showToast({ message: msg, duration: 2600 });
} catch (err) {
// 忽略
}
}
build() {
// 🔴 外层 Stack:**模块设置浮层**要浮在页面之上
// (本页原来是 Scroll 直接作根,没有 Stack,这里补一层)
@@ -309,6 +392,31 @@ export struct FbResourcesPage {
})
.transition(fbSheetTransition())
}
// ---- 资源只读详情浮层(工单 #29:点列表进详情,编辑走底部按钮)----
if (this.detailOpen) {
FbResourceDetailSheet({
accent: this.accent,
editingId: this.detailId,
editingTitle: this.detailTitle,
editingContent: this.detailContent,
ownerName: this.detailOwner,
canWrite: this.detailCanWrite,
onClose: (): void => {
this.detailOpen = false;
},
onEdit: (): void => {
this.openEditFromDetail();
},
onOpenFile: (key: string, name: string): void => {
this.openFile(key, name);
},
onSaveAttach: (key: string, name: string, isImage: boolean): void => {
this.saveAttach(key, name, isImage);
}
})
.transition(fbSheetTransition())
}
}
.width('100%')
.height('100%')