/** * 家书 FamilyBook · 资源模块(鸿蒙端) * * 对应 Web 端 `templates/resources/index.php`。 * 资源 = 证件 / 资料 / 附件的集合(户口本、房产证、学籍资料…),可共享给某个成员。 * * 端上形态:**按类别分组的卡片列表**,卡片右侧显示归属人与附件数; * 那一排「类别筛选胶囊」对应 Web 端页头的分类入口。 */ import { FbColors, FbMetric } from '../../common/Theme'; import { FbAppState, fbAppState } from '../../common/Store'; import { FbGroup, FbResourceItem } from '../../model/Types'; import { FB_DEMO_RESOURCES, fbGroupResource } from '../../model/DemoData'; import { FbEmptyBox, FbIconButton, FbPrimaryButton, FbTag } from '../../components/Widgets'; @ComponentV2 export struct FbResourcesPage { @Param app: FbAppState = fbAppState(); /** 模块主题色(资源 = 靛蓝) */ private accent: string = '#5566A8'; private all: FbResourceItem[] = FB_DEMO_RESOURCES; /** 当前筛选类别('' = 全部) */ @Local kindFilter: string = ''; build() { Column() { // ---- 页头 ---- Row({ space: 8 }) { Column({ space: 2 }) { Text(this.all.length.toString() + ' 项资源') .fontSize(FbMetric.fontTitle) .fontWeight(FontWeight.Medium) .fontColor(FbColors.ink) Text('证件 / 资料 / 附件,可共享给家庭成员') .fontSize(FbMetric.fontTiny) .fontColor(FbColors.faint) } .alignItems(HorizontalAlign.Start) .layoutWeight(1) FbPrimaryButton({ label: '添加', bg: this.accent, icon: $r('app.media.fb_ic_plus') }) FbIconButton({ icon: $r('app.media.fb_ic_gear'), tint: FbColors.muted }) } .width('100%') .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') Blank() Text('共享给我 ' + this.sharedCount().toString() + ' 项') .fontSize(FbMetric.fontTiny) .fontColor(FbColors.faint) } .width('100%') .padding({ left: FbMetric.pagePad, right: FbMetric.pagePad, bottom: 8 }) .alignItems(VerticalAlign.Center) // ---- 列表 ---- if (this.filtered().length === 0) { FbEmptyBox({ title: '这里还没有资源', hint: '家里的证件、资料和附件都可以收进来,需要时一键共享', icon: $r('app.media.fb_ic_resources') }) } else { List({ space: 0 }) { ForEach(this.groups(), (g: FbGroup) => { ListItemGroup({ header: this.groupHeader(g.title, g.items.length.toString() + ' 项') }) { ForEach(g.items, (r: FbResourceItem) => { ListItem() { this.resourceCard(r) } }, (r: FbResourceItem): string => 'res_' + r.id.toString()) } }, (g: FbGroup): string => 'rsg_' + g.key) } .layoutWeight(1) .width('100%') .padding({ left: FbMetric.pagePad, right: FbMetric.pagePad, bottom: 24 }) .scrollBar(BarState.Off) .edgeEffect(EdgeEffect.Spring) } } .width('100%') .height('100%') .backgroundColor(FbColors.paper) .alignItems(HorizontalAlign.Start) } /** 一项资源卡 */ @Builder resourceCard(r: FbResourceItem) { Row({ space: 12 }) { // 类别图标底 Stack({ alignContent: Alignment.Center }) { Image(this.kindIcon(r.kind)) .width(19) .height(19) .renderMode(ImageRenderMode.Template) .fillColor(this.accent) } .width(42) .height(42) .borderRadius(FbMetric.radiusS) .backgroundColor(this.accent + '14') Column({ space: 4 }) { Row({ space: 6 }) { Text(r.name) .fontSize(FbMetric.fontBody) .fontWeight(FontWeight.Medium) .fontColor(FbColors.ink) .maxLines(1) .textOverflow({ overflow: TextOverflow.Ellipsis }) .layoutWeight(1) if (r.shared) { FbTag({ text: '已共享', tone: 'green' }) } } .width('100%') .alignItems(VerticalAlign.Center) 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) .fillColor(FbColors.faint) Text(r.fileCount.toString() + ' 个附件') .fontSize(10) .fontColor(FbColors.faint) } Text(r.updatedAt) .fontSize(10) .fontColor(FbColors.faint) } .alignItems(VerticalAlign.Center) } .alignItems(HorizontalAlign.Start) .layoutWeight(1) Image($r('app.media.fb_ic_forward')) .width(13) .height(13) .renderMode(ImageRenderMode.Template) .fillColor(FbColors.faint) } .width('100%') .padding(14) .backgroundColor(FbColors.surface) .borderRadius(FbMetric.radius) .margin({ bottom: 8 }) .alignItems(VerticalAlign.Center) } @Builder kindChip(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) .padding({ left: 12, right: 12, top: 6, bottom: 6 }) .borderRadius(FbMetric.radiusPill) .onClick(() => { this.kindFilter = key; }) } @Builder groupHeader(title: string, count: string) { Row({ space: 8 }) { Text(title) .fontSize(FbMetric.fontSmall) .fontWeight(FontWeight.Medium) .fontColor(FbColors.ink) Text(count) .fontSize(FbMetric.fontTiny) .fontColor(FbColors.faint) Blank() } .width('100%') .padding({ left: 4, right: 4, top: 12, bottom: 8 }) .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) { return this.all; } return this.all.filter((r: FbResourceItem): boolean => r.kind === this.kindFilter); } private groups(): FbGroup[] { return fbGroupResource(this.filtered()); } private sharedCount(): number { return this.all.filter((r: FbResourceItem): boolean => r.shared).length; } }