资源附件+共享:浮层补「附件」「共享」两个真功能 laoyang/FamilyBook#25
用户原话(2026-10-28):「鸿蒙端对齐网页端」。资源浮层原来「附件与共享 还在网页端,App 暂未开放」,现在服务端补齐 API 后: 1) FbResourceRepo 补 attach/share 写操作(上传走 fbUploadOne 字段 file; 删除走 query 传 attachment_id / person_id —— DELETE 带 JSON body 服务端读不到) 2) FbResourceSheet:附件区块(列表 + 缩略图/图标 + 「+传附件」+ 逐条删)+ 共享区块(列表 + 「共享给…」复用选人组件 + 逐条取消) · 只读共享来的不摆入口(与 canWrite 对齐) 编译 BUILD SUCCESSFUL;服务端冒烟 _i25_resource_api.py 21/0 + 反证命中。
This commit is contained in:
@@ -9,18 +9,54 @@
|
|||||||
* ⇒ 端上原来既没有新建、也没有详情:`FbPrimaryButton` 无 `onTap`、
|
* ⇒ 端上原来既没有新建、也没有详情:`FbPrimaryButton` 无 `onTap`、
|
||||||
* 列表项无 `onClick`。这个浮层把两件事一次补齐。
|
* 列表项无 `onClick`。这个浮层把两件事一次补齐。
|
||||||
*
|
*
|
||||||
* ⚠️⚠️ 服务端只有 title / content(详见 `data/FbResourceRepo` 文件头):
|
* 🔴 工单 #25(2026-10-28):附件与共享原来「故意不摆假入口」(服务端没 API)。
|
||||||
* 归属人固定是当前登录的人、附件与共享**没有 API**。
|
* 服务端补齐 `attach` / `shares` 子端点后,这里补上两个真功能:
|
||||||
* ⇒ 这里**故意不摆**「选归属人」「传附件」「共享给谁」这些入口 ——
|
* · 附件:列表 + 「+ 传附件」+ 逐条删除
|
||||||
* 摆了也存不进去,用户会以为存上了。
|
* · 共享:列表 + 「共享给…」+ 逐条取消(复用选人组件)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { FbColors, FbMetric, FB_MASK, fbAlpha } from '../common/Theme';
|
import { FbColors, FbMetric, FB_MASK, fbAlpha } from '../common/Theme';
|
||||||
import { FbSheetClose } from './FbSheetClose';
|
import { FbSheetClose } from './FbSheetClose';
|
||||||
import { FbSheetRing } from './FbSheetRing';
|
import { FbSheetRing } from './FbSheetRing';
|
||||||
|
import { FbPersonPickSheet } from './FbPersonPickSheet';
|
||||||
|
import { FbPersonRepo, FbRosterPerson } from '../data/FbPersonRepo';
|
||||||
import { FB_TOKEN_STORE } from '../data/FbTokenStore';
|
import { FB_TOKEN_STORE } from '../data/FbTokenStore';
|
||||||
import { createResource, updateResource, deleteResource } from '../data/FbResourceRepo';
|
import {
|
||||||
|
createResource, updateResource, deleteResource,
|
||||||
|
fetchResourceAttach, delResourceAttach,
|
||||||
|
fetchResourceShares, shareResource, unshareResource,
|
||||||
|
} from '../data/FbResourceRepo';
|
||||||
|
import { fbUploadOne } from '../data/FbUpload';
|
||||||
|
import { fbImageSrc } from '../data/FbAttachQueue';
|
||||||
import { FbApiResult } from '../data/FbHttp';
|
import { FbApiResult } from '../data/FbHttp';
|
||||||
|
import { picker } from '@kit.CoreFileKit';
|
||||||
|
import { BusinessError } from '@kit.BasicServicesKit';
|
||||||
|
import { hilog } from '@kit.PerformanceAnalysisKit';
|
||||||
|
|
||||||
|
/** 一条附件(服务端 `Attachment::list`) */
|
||||||
|
interface FbResourceAttach {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
key: string;
|
||||||
|
isImage: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 一条共享(服务端 `Resource::shares()`) */
|
||||||
|
interface FbResourceShareRow {
|
||||||
|
personId: number;
|
||||||
|
name: string;
|
||||||
|
perm: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 附件原始行 */
|
||||||
|
interface RawAttach {
|
||||||
|
id?: number; key?: string | null; name?: string | null; is_image?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 共享原始行 */
|
||||||
|
interface RawShareRow {
|
||||||
|
person_id?: number; name?: string | null; perm?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
@ComponentV2
|
@ComponentV2
|
||||||
export struct FbResourceSheet {
|
export struct FbResourceSheet {
|
||||||
@@ -45,10 +81,22 @@ export struct FbResourceSheet {
|
|||||||
/** 删除的二次确认(网页也是先点一次再确认,避免误删证件) */
|
/** 删除的二次确认(网页也是先点一次再确认,避免误删证件) */
|
||||||
@Local confirmingDelete: boolean = false;
|
@Local confirmingDelete: boolean = false;
|
||||||
@Local note: string = '';
|
@Local note: string = '';
|
||||||
|
// ---- 附件(工单 #25)----
|
||||||
|
@Local attachs: FbResourceAttach[] = [];
|
||||||
|
@Local uploading: boolean = false;
|
||||||
|
// ---- 共享(工单 #25)----
|
||||||
|
@Local shares: FbResourceShareRow[] = [];
|
||||||
|
@Local roster: FbRosterPerson[] = [];
|
||||||
|
@Local picking: boolean = false;
|
||||||
|
|
||||||
aboutToAppear(): void {
|
aboutToAppear(): void {
|
||||||
this.title = this.editingTitle;
|
this.title = this.editingTitle;
|
||||||
this.content = this.editingContent;
|
this.content = this.editingContent;
|
||||||
|
/* 已有资源才拉附件与共享(新建时还没有 id) */
|
||||||
|
if (this.editingId > 0) {
|
||||||
|
this.reloadAttach();
|
||||||
|
this.reloadShares();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
@@ -153,13 +201,128 @@ export struct FbResourceSheet {
|
|||||||
.maxLines(3)
|
.maxLines(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 附件 / 共享:服务端没有接口,照实说明(不摆假入口)
|
// ---- 附件(工单 #25)----
|
||||||
if (this.editingId > 0) {
|
if (this.editingId > 0) {
|
||||||
Text('附件与共享还在网页端「资源」里管 —— App 这边暂未开放。')
|
Column({ space: 6 }) {
|
||||||
|
Row({ space: 8 }) {
|
||||||
|
Text('附件')
|
||||||
.fontSize(FbMetric.fontTiny)
|
.fontSize(FbMetric.fontTiny)
|
||||||
.fontColor(FbColors.faint)
|
.fontColor(FbColors.faint)
|
||||||
|
.width(34)
|
||||||
|
Text(this.attachs.length > 0 ? this.attachs.length.toString() + ' 个' : '还没有附件')
|
||||||
|
.fontSize(FbMetric.fontTiny)
|
||||||
|
.fontColor(FbColors.muted)
|
||||||
|
}
|
||||||
.width('100%')
|
.width('100%')
|
||||||
.maxLines(3)
|
.alignItems(VerticalAlign.Center)
|
||||||
|
|
||||||
|
if (this.attachs.length > 0) {
|
||||||
|
ForEach(this.attachs, (a: FbResourceAttach) => {
|
||||||
|
Row({ space: 8 }) {
|
||||||
|
if (a.isImage) {
|
||||||
|
Image(fbImageSrc(a.key, FB_TOKEN_STORE.get()))
|
||||||
|
.width(40).height(40)
|
||||||
|
.objectFit(ImageFit.Cover)
|
||||||
|
.borderRadius(FbMetric.radiusS)
|
||||||
|
.backgroundColor(FbColors.inputBg)
|
||||||
|
} else {
|
||||||
|
Text('📎')
|
||||||
|
.fontSize(20)
|
||||||
|
}
|
||||||
|
Text(a.name)
|
||||||
|
.fontSize(FbMetric.fontSmall)
|
||||||
|
.fontColor(FbColors.ink)
|
||||||
|
.layoutWeight(1)
|
||||||
|
.maxLines(1)
|
||||||
|
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||||
|
if (this.canWrite) {
|
||||||
|
Text('删')
|
||||||
|
.fontSize(FbMetric.fontTiny)
|
||||||
|
.fontColor(FbColors.red)
|
||||||
|
.padding({ left: 6, right: 2, top: 2, bottom: 2 })
|
||||||
|
.onClick((): void => {
|
||||||
|
this.dropAttach(a);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.width('100%')
|
||||||
|
.padding({ top: 4, bottom: 4 })
|
||||||
|
.alignItems(VerticalAlign.Center)
|
||||||
|
}, (a: FbResourceAttach): string => 'ratt_' + a.id.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.canWrite) {
|
||||||
|
Text(this.uploading ? '正在上传…' : '+ 传附件')
|
||||||
|
.fontSize(FbMetric.fontSmall)
|
||||||
|
.fontColor(this.accent)
|
||||||
|
.padding({ left: 10, right: 10, top: 6, bottom: 6 })
|
||||||
|
.borderRadius(FbMetric.radiusS)
|
||||||
|
.backgroundColor(fbAlpha(this.accent, 0.08))
|
||||||
|
.onClick((): void => {
|
||||||
|
this.pickAttach();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.width('100%')
|
||||||
|
.alignItems(HorizontalAlign.Start)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 共享(工单 #25)----
|
||||||
|
if (this.editingId > 0) {
|
||||||
|
Column({ space: 6 }) {
|
||||||
|
Row({ space: 8 }) {
|
||||||
|
Text('共享')
|
||||||
|
.fontSize(FbMetric.fontTiny)
|
||||||
|
.fontColor(FbColors.faint)
|
||||||
|
.width(34)
|
||||||
|
Text(this.shares.length > 0 ? this.shares.length.toString() + ' 人' : '还没有共享给谁')
|
||||||
|
.fontSize(FbMetric.fontTiny)
|
||||||
|
.fontColor(FbColors.muted)
|
||||||
|
}
|
||||||
|
.width('100%')
|
||||||
|
.alignItems(VerticalAlign.Center)
|
||||||
|
|
||||||
|
if (this.shares.length > 0) {
|
||||||
|
ForEach(this.shares, (s: FbResourceShareRow) => {
|
||||||
|
Row({ space: 8 }) {
|
||||||
|
Text(s.name)
|
||||||
|
.fontSize(FbMetric.fontSmall)
|
||||||
|
.fontColor(FbColors.ink)
|
||||||
|
.layoutWeight(1)
|
||||||
|
.maxLines(1)
|
||||||
|
Text(s.perm === 'write' ? '可改' : '只看')
|
||||||
|
.fontSize(FbMetric.fontTiny)
|
||||||
|
.fontColor(FbColors.faint)
|
||||||
|
if (this.canWrite) {
|
||||||
|
Text('取消')
|
||||||
|
.fontSize(FbMetric.fontTiny)
|
||||||
|
.fontColor(FbColors.red)
|
||||||
|
.padding({ left: 6, right: 2, top: 2, bottom: 2 })
|
||||||
|
.onClick((): void => {
|
||||||
|
this.dropShare(s);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.width('100%')
|
||||||
|
.padding({ top: 4, bottom: 4 })
|
||||||
|
.alignItems(VerticalAlign.Center)
|
||||||
|
}, (s: FbResourceShareRow): string => 'rsh_' + s.personId.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.canWrite) {
|
||||||
|
Text('共享给…')
|
||||||
|
.fontSize(FbMetric.fontSmall)
|
||||||
|
.fontColor(this.accent)
|
||||||
|
.padding({ left: 10, right: 10, top: 6, bottom: 6 })
|
||||||
|
.borderRadius(FbMetric.radiusS)
|
||||||
|
.backgroundColor(fbAlpha(this.accent, 0.08))
|
||||||
|
.onClick((): void => {
|
||||||
|
this.openPicker();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.width('100%')
|
||||||
|
.alignItems(HorizontalAlign.Start)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.width('100%')
|
.width('100%')
|
||||||
@@ -240,6 +403,22 @@ export struct FbResourceSheet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.width('92%')
|
.width('92%')
|
||||||
|
|
||||||
|
/* 选人浮层:共享给谁(工单 #25,复用名册多选组件) */
|
||||||
|
if (this.picking) {
|
||||||
|
FbPersonPickSheet({
|
||||||
|
people: this.roster,
|
||||||
|
selected: [],
|
||||||
|
title: '共享给谁',
|
||||||
|
accent: this.accent,
|
||||||
|
onConfirm: (ids: number[]): void => {
|
||||||
|
this.addShares(ids);
|
||||||
|
},
|
||||||
|
onClose: (): void => {
|
||||||
|
this.picking = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.width('100%')
|
.width('100%')
|
||||||
.height('100%')
|
.height('100%')
|
||||||
@@ -251,6 +430,136 @@ export struct FbResourceSheet {
|
|||||||
return this.canWrite;
|
return this.canWrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 附件(工单 #25)====================
|
||||||
|
private async reloadAttach(): Promise<void> {
|
||||||
|
const res: FbApiResult = await fetchResourceAttach(FB_TOKEN_STORE.get(), this.editingId);
|
||||||
|
if (!res.ok) {
|
||||||
|
this.note = res.error !== '' ? res.error : '附件列表没拉到。';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const out: FbResourceAttach[] = [];
|
||||||
|
try {
|
||||||
|
const o: Record<string, Object> = JSON.parse(res.data) as Record<string, Object>;
|
||||||
|
const items: Object | undefined = o['items'];
|
||||||
|
const rows: RawAttach[] = (items !== undefined && items !== null)
|
||||||
|
? (items as RawAttach[]) : [];
|
||||||
|
for (const a of rows) {
|
||||||
|
out.push({
|
||||||
|
id: a.id !== undefined ? a.id : 0,
|
||||||
|
name: a.name !== undefined && a.name !== null ? a.name : '附件',
|
||||||
|
key: a.key !== undefined && a.key !== null ? a.key : '',
|
||||||
|
isImage: a.is_image !== undefined ? a.is_image !== 0 : false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// 解析失败就当空列表
|
||||||
|
}
|
||||||
|
this.attachs = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async pickAttach(): Promise<void> {
|
||||||
|
if (this.uploading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const opts: picker.PhotoSelectOptions = new picker.PhotoSelectOptions();
|
||||||
|
opts.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;
|
||||||
|
opts.maxSelectNumber = 1;
|
||||||
|
const p: picker.PhotoViewPicker = new picker.PhotoViewPicker();
|
||||||
|
const sel: picker.PhotoSelectResult = await p.select(opts);
|
||||||
|
if (sel.photoUris.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.uploading = true;
|
||||||
|
this.note = '';
|
||||||
|
// 资源附件字段名 `file`,与任务附件同
|
||||||
|
const err: string = await fbUploadOne('/api/v1/resources/' + this.editingId.toString() + '/attach',
|
||||||
|
'file', sel.photoUris[0], FB_TOKEN_STORE.get());
|
||||||
|
this.uploading = false;
|
||||||
|
if (err !== '') {
|
||||||
|
this.note = err;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.reloadAttach();
|
||||||
|
} catch (e) {
|
||||||
|
const be: BusinessError = e as BusinessError;
|
||||||
|
hilog.warn(0x0000, 'FamilyBook', '资源传附件失败:%{public}s', JSON.stringify(be));
|
||||||
|
this.uploading = false;
|
||||||
|
this.note = '传附件失败,请再试一次。';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async dropAttach(a: FbResourceAttach): Promise<void> {
|
||||||
|
const res: FbApiResult = await delResourceAttach(FB_TOKEN_STORE.get(), this.editingId, a.id);
|
||||||
|
if (!res.ok) {
|
||||||
|
this.note = res.error !== '' ? res.error : '附件没删掉。';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.reloadAttach();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 共享(工单 #25)====================
|
||||||
|
private async reloadShares(): Promise<void> {
|
||||||
|
const res: FbApiResult = await fetchResourceShares(FB_TOKEN_STORE.get(), this.editingId);
|
||||||
|
if (!res.ok) {
|
||||||
|
this.note = res.error !== '' ? res.error : '共享列表没拉到。';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const out: FbResourceShareRow[] = [];
|
||||||
|
try {
|
||||||
|
const o: Record<string, Object> = JSON.parse(res.data) as Record<string, Object>;
|
||||||
|
const items: Object | undefined = o['items'];
|
||||||
|
const rows: RawShareRow[] = (items !== undefined && items !== null)
|
||||||
|
? (items as RawShareRow[]) : [];
|
||||||
|
for (const s of rows) {
|
||||||
|
out.push({
|
||||||
|
personId: s.person_id !== undefined ? s.person_id : 0,
|
||||||
|
name: s.name !== undefined && s.name !== null ? s.name : '(无名)',
|
||||||
|
perm: s.perm !== undefined && s.perm !== null ? s.perm : 'read',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// 解析失败就当空列表
|
||||||
|
}
|
||||||
|
this.shares = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async openPicker(): Promise<void> {
|
||||||
|
if (this.roster.length === 0) {
|
||||||
|
try {
|
||||||
|
this.roster = await FbPersonRepo.inst().list();
|
||||||
|
} catch (e) {
|
||||||
|
this.roster = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.picking = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async addShares(ids: number[]): Promise<void> {
|
||||||
|
this.picking = false;
|
||||||
|
if (ids.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let bad: string = '';
|
||||||
|
for (const pid of ids) {
|
||||||
|
const res: FbApiResult = await shareResource(FB_TOKEN_STORE.get(), this.editingId, pid, 'read');
|
||||||
|
if (!res.ok && bad === '') {
|
||||||
|
bad = res.error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.note = bad !== '' ? bad : '';
|
||||||
|
await this.reloadShares();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async dropShare(s: FbResourceShareRow): Promise<void> {
|
||||||
|
const res: FbApiResult = await unshareResource(FB_TOKEN_STORE.get(), this.editingId, s.personId);
|
||||||
|
if (!res.ok) {
|
||||||
|
this.note = res.error !== '' ? res.error : '没取消成。';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.reloadShares();
|
||||||
|
}
|
||||||
|
|
||||||
private async save(): Promise<void> {
|
private async save(): Promise<void> {
|
||||||
if (this.saving) {
|
if (this.saving) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -5,19 +5,21 @@
|
|||||||
* POST /api/v1/resources 新建(title / content)
|
* POST /api/v1/resources 新建(title / content)
|
||||||
* PATCH /api/v1/resources/<id> 改(title / content / category)
|
* PATCH /api/v1/resources/<id> 改(title / content / category)
|
||||||
* DELETE /api/v1/resources/<id> 删
|
* DELETE /api/v1/resources/<id> 删
|
||||||
|
* GET /api/v1/resources/<id>/attach 附件列表(工单 #25)
|
||||||
|
* POST /api/v1/resources/<id>/attach 传附件(multipart,字段 `file`)
|
||||||
|
* DELETE /api/v1/resources/<id>/attach 删附件(attachment_id)
|
||||||
|
* GET /api/v1/resources/<id>/shares 共享给了谁
|
||||||
|
* POST /api/v1/resources/<id>/shares 共享给某人(person_id / perm)
|
||||||
|
* DELETE /api/v1/resources/<id>/shares 取消共享(person_id)
|
||||||
*
|
*
|
||||||
* 🔴 用户 2026-10-20:「资源也是啊,新增加资源,资源也点不进去。
|
* 🔴 用户 2026-10-20:「资源也是啊,新增加资源,资源也点不进去。
|
||||||
* 设置也没有任何的东西。」
|
* 设置也没有任何的东西。」⇒ 端上「添加」按钮**没有 onTap**、列表项**没有 onClick**。
|
||||||
* ⇒ 端上「添加」按钮**没有 `onTap`**、列表项**没有 `onClick`** —— 两件都没接。
|
|
||||||
*
|
*
|
||||||
* ⚠️⚠️ **服务端只认 title / content 两个字段**(其它字段会被静默忽略):
|
* 🔴 工单 #25(2026-10-28):原来这里只有 title/content(附件与共享没 API,
|
||||||
* · `Resource::create()` 的 INSERT 只有 `title` / `content`;
|
* 端上「故意不摆假入口」)。现在服务端补齐了 attach + shares 子端点,
|
||||||
* · `resources` 表**没有 category 列**(见 `app/Schema.php`),
|
* 这里也把三组写操作补上,端上终于能管附件与共享。
|
||||||
* 接口里那个 `category` 参数是历史遗留,写下去不会落库;
|
*
|
||||||
* · 归属人(`owner_id`)由接口固定成**当前登录的人**,没法从端上指定;
|
* ⚠️ 归属人(owner_id)仍由接口固定成当前登录的人,端上不选。
|
||||||
* · **附件与共享没有 API**(`Attachment::list/save` 只有网页在用)。
|
|
||||||
* ⇒ 端上就只做「标题 + 正文」,别在界面上摆出家能选归属人/传附件的假入口 ——
|
|
||||||
* 用户填了、保存了、却没落库,比没做更糟。
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { fbApi, FbApiResult, FbApiOptions } from './FbHttp';
|
import { fbApi, FbApiResult, FbApiOptions } from './FbHttp';
|
||||||
@@ -48,3 +50,41 @@ export async function deleteResource(token: string, id: number): Promise<FbApiRe
|
|||||||
const opts: FbApiOptions = { method: 'DELETE', token: token };
|
const opts: FbApiOptions = { method: 'DELETE', token: token };
|
||||||
return await fbApi('/api/v1/resources/' + id.toString(), opts);
|
return await fbApi('/api/v1/resources/' + id.toString(), opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 附件列表(工单 #25) */
|
||||||
|
export async function fetchResourceAttach(token: string, id: number): Promise<FbApiResult> {
|
||||||
|
const opts: FbApiOptions = { token: token, authProbe: true };
|
||||||
|
return await fbApi('/api/v1/resources/' + id.toString() + '/attach', opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删附件(⚠️ 附件 id 走 query,DELET 带 JSON body 服务端读不到 —— 见任务删附件同款注释) */
|
||||||
|
export async function delResourceAttach(token: string, id: number, aid: number): Promise<FbApiResult> {
|
||||||
|
const q: Record<string, string> = {};
|
||||||
|
q['attachment_id'] = aid.toString();
|
||||||
|
const opts: FbApiOptions = { method: 'DELETE', token: token, query: q };
|
||||||
|
return await fbApi('/api/v1/resources/' + id.toString() + '/attach', opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 共享给了谁(工单 #25) */
|
||||||
|
export async function fetchResourceShares(token: string, id: number): Promise<FbApiResult> {
|
||||||
|
const opts: FbApiOptions = { token: token, authProbe: true };
|
||||||
|
return await fbApi('/api/v1/resources/' + id.toString() + '/shares', opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 共享给某人(perm = read / write) */
|
||||||
|
export async function shareResource(token: string, id: number, personId: number,
|
||||||
|
perm: string): Promise<FbApiResult> {
|
||||||
|
const body: Record<string, Object> = {};
|
||||||
|
body['person_id'] = personId;
|
||||||
|
body['perm'] = perm;
|
||||||
|
const opts: FbApiOptions = { method: 'POST', token: token, body: body };
|
||||||
|
return await fbApi('/api/v1/resources/' + id.toString() + '/shares', opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 取消某人的共享(person_id 走 query,DELETE 带 body 服务端读不到) */
|
||||||
|
export async function unshareResource(token: string, id: number, personId: number): Promise<FbApiResult> {
|
||||||
|
const q: Record<string, string> = {};
|
||||||
|
q['person_id'] = personId.toString();
|
||||||
|
const opts: FbApiOptions = { method: 'DELETE', token: token, query: q };
|
||||||
|
return await fbApi('/api/v1/resources/' + id.toString() + '/shares', opts);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user