diff --git a/src/api/types/uni-halo.ts b/src/api/types/uni-halo.ts index a6a687a..8e58826 100644 --- a/src/api/types/uni-halo.ts +++ b/src/api/types/uni-halo.ts @@ -405,6 +405,12 @@ export interface ILoveAlbum { locked?: boolean cover?: string photos?: ILovePhoto[] + /** Halo 资源元数据(接口返回 metadata) */ + metadata?: { + name?: string + creationTimestamp?: string + [key: string]: unknown + } [key: string]: unknown } @@ -420,7 +426,14 @@ export interface ILoveAlbumListReq { [key: string]: unknown } -export type ILoveAlbumListRes = ILoveAlbum[] +/** 恋爱相册列表响应(插件分页包装) */ +export interface ILoveAlbumListRes { + page?: number + size?: number + total?: number + hasNext?: boolean + items: ILoveAlbum[] +} export interface ILoveAlbumDetailReq { [key: string]: unknown @@ -439,6 +452,32 @@ export interface ILoveDailyItem { id?: string content?: string date?: string + /** Halo 资源元数据(接口返回 metadata) */ + metadata?: { + name?: string + [key: string]: unknown + } + /** 清单项详情(接口返回 spec) */ + spec?: ILoveDailyItemSpec + [key: string]: unknown +} + +/** 恋爱清单项 spec(对齐插件 LoveDailyItemSpec) */ +export interface ILoveDailyItemSpec { + /** 清单标题 */ + title?: string + /** 清单内容 */ + content?: string + /** 状态:未开始/进行中/已完成 */ + status?: 'wait' | 'doing' | 'complete' + /** 计划时间 */ + planDate?: string + /** 完成时间 */ + completeDate?: string + /** 完成感想 */ + completeRemark?: string + /** 回忆图片 */ + images?: string[] [key: string]: unknown } @@ -448,13 +487,44 @@ export interface ILoveDailyItemListReq { [key: string]: unknown } -export type ILoveDailyItemListRes = ILoveDailyItem[] +/** 恋爱清单列表响应(插件分页包装) */ +export interface ILoveDailyItemListRes { + page?: number + size?: number + total?: number + hasNext?: boolean + items: ILoveDailyItem[] +} export interface ILoveStory { id?: string title?: string content?: string date?: string + /** Halo 资源元数据(接口返回 metadata) */ + metadata?: { + name?: string + [key: string]: unknown + } + /** 故事详情(接口返回 spec) */ + spec?: ILoveStorySpec + [key: string]: unknown +} + +/** 恋爱故事 spec(对齐插件 LoveStorySpec) */ +export interface ILoveStorySpec { + /** 故事标题 */ + title?: string + /** 故事内容(HTML) */ + content?: string + /** 故事日期 */ + date?: string + /** 故事地点 */ + location?: string + /** 故事图片 */ + images?: string[] + /** 排序优先级(越大越靠前) */ + priority?: number [key: string]: unknown } @@ -556,4 +626,11 @@ export interface IMiniProgramLinkSubmissionForm { email?: string } -export type ILoveStoryListRes = ILoveStory[] +/** 恋爱故事列表响应(插件分页包装) */ +export interface ILoveStoryListRes { + page?: number + size?: number + total?: number + hasNext?: boolean + items: ILoveStory[] +} diff --git a/src/pages-blog/love/album.vue b/src/pages-blog/love/album.vue index 8a20f07..1dcc4a5 100644 --- a/src/pages-blog/love/album.vue +++ b/src/pages-blog/love/album.vue @@ -10,11 +10,13 @@ import { getLoveAlbumByName, getLoveAlbums } from '@/api/uni-halo' import { useAppConfigStore } from '@/store/appConfig' import { checkImageUrl } from '@/utils/url' import { getCache, setCache } from '@/utils/storage' -import type { ILoveAlbum } from '@/api/types/uni-halo' +import { DataLoadingStatusEnum, useDataLoadingStatus } from '@/hooks/useDataLoadingStatus' +import type { ILoveAlbum, ILovePhoto } from '@/api/types/uni-halo' definePage({ style: { navigationBarTitleText: '恋爱相册', + navigationStyle: 'custom', enablePullDownRefresh: true, }, }) @@ -27,18 +29,48 @@ const UNLOCKED_ALBUMS_CACHE_KEY = 'unlocked_albums' /** 解锁 token 有效期(后端默认 30 分钟) */ const ALBUM_TOKEN_TTL_SECONDS = 30 * 60 +/* ---------------- 展示层类型 ---------------- */ +/** 相册展示卡片(script 预处理后的干净展示数据) */ +interface ILoveAlbumCard { + /** 相册 key(metadata.name,用于解锁/详情请求) */ + name: string + displayName: string + locked: boolean + photoCount: number + /** 封面图(已预处理 URL) */ + image: string + /** 创建时间(格式化展示) */ + takeTime: string + /** 相册照片(解锁后填充) */ + photos: ILovePhoto[] +} + +/** 相册卡片映射:字段取值 + 封面/时间预处理(模板不感知原始接口结构) */ +function mapAlbumCard(item: ILoveAlbum): ILoveAlbumCard { + const creationTimestamp = item.metadata?.creationTimestamp + return { + name: item.name || item.metadata?.name || '', + displayName: item.displayName || item.title || '', + locked: !!item.locked, + photoCount: Number(item.photoCount) || 0, + image: checkImageUrl(item.cover || ''), + takeTime: creationTimestamp ? dayjs(creationTimestamp).format('DD/MM/YYYY') : '', + photos: item.photos || [], + } +} + /* ---------------- 状态 ---------------- */ -const loading = ref<'loading' | 'success' | 'error'>('loading') -const dataList = ref<(ILoveAlbum & { image?: string, takeTime?: string })[]>([]) +const { loadingStatus, updateLoadingStatus } = useDataLoadingStatus() +const dataList = ref([]) const unlockedAlbums = ref>({}) /** 密码解锁弹窗 */ const showUnlockModal = ref(false) -const currentUnlockAlbum = ref<(ILoveAlbum & { image?: string }) | null>(null) +const currentUnlockAlbum = ref(null) /** 图片查看弹窗 */ const showPhotoViewer = ref(false) -const currentViewerAlbum = ref<(ILoveAlbum & { image?: string }) | null>(null) +const currentViewerAlbum = ref(null) const viewerLoading = ref(false) const unlockAlbumName = computed(() => currentUnlockAlbum.value?.displayName || '') @@ -70,30 +102,18 @@ function handleSaveUnlockedAlbums() { /* ---------------- 数据加载 ---------------- */ async function handleGetData() { - loading.value = 'loading' + updateLoadingStatus(DataLoadingStatusEnum.Loading) try { const res = await getLoveAlbums({}) - if (res.data && (res.data as unknown as { items?: unknown[] }).items) { - dataList.value = ((res.data as unknown as { items: ILoveAlbum[] }).items || []).map((item) => { - const creationTimestamp = (item.metadata as unknown as { creationTimestamp?: string } | undefined)?.creationTimestamp - return { - ...item, - image: checkImageUrl(item.cover), - takeTime: creationTimestamp ? dayjs(creationTimestamp).format('DD/MM/YYYY') : '', - } - }) - loading.value = 'success' + const items = res.data?.items || [] + dataList.value = items.map(mapAlbumCard) + updateLoadingStatus(dataList.value.length === 0 ? DataLoadingStatusEnum.Empty : DataLoadingStatusEnum.Success) + if (dataList.value.length > 0) handleLoadUnlockedAlbumPhotos() - } - else { - dataList.value = [] - loading.value = 'success' - } } catch (e) { console.error('获取相册失败', e) - loading.value = 'error' - uni.showToast({ icon: 'none', title: '加载失败,请下拉刷新重试!' }) + updateLoadingStatus(DataLoadingStatusEnum.Error) } finally { setTimeout(() => { @@ -105,12 +125,12 @@ async function handleGetData() { /** 加载已解锁相册的照片 */ async function handleLoadUnlockedAlbumPhotos() { for (const item of dataList.value) { - if (item.locked && unlockedAlbums.value[item.name || '']) { - const token = unlockedAlbums.value[item.name || ''] + const token = unlockedAlbums.value[item.name] + if (item.locked && token) { try { - const detail = await getLoveAlbumByName(item.name || '', { token }) + const detail = await getLoveAlbumByName(item.name, { token }) if (detail.locked) { - delete unlockedAlbums.value[item.name || ''] + delete unlockedAlbums.value[item.name] handleSaveUnlockedAlbums() } else if (detail.photos) { @@ -126,8 +146,8 @@ async function handleLoadUnlockedAlbumPhotos() { } /* ---------------- 交互 ---------------- */ -function handleOnAlbumClick(item: ILoveAlbum & { image?: string }) { - if (item.locked && !unlockedAlbums.value[item.name || '']) { +function handleOnAlbumClick(item: ILoveAlbumCard) { + if (item.locked && !unlockedAlbums.value[item.name]) { currentUnlockAlbum.value = item showUnlockModal.value = true return @@ -135,18 +155,18 @@ function handleOnAlbumClick(item: ILoveAlbum & { image?: string }) { handleOpenPhotoViewer(item) } -async function handleOpenPhotoViewer(item: ILoveAlbum & { image?: string }) { +async function handleOpenPhotoViewer(item: ILoveAlbumCard) { currentViewerAlbum.value = item showPhotoViewer.value = true - if (item.photos && item.photos.length > 0) + if (item.photos.length > 0) return viewerLoading.value = true try { - const token = unlockedAlbums.value[item.name || ''] || '' - const detail = await getLoveAlbumByName(item.name || '', { token }) + const token = unlockedAlbums.value[item.name] || '' + const detail = await getLoveAlbumByName(item.name, { token }) if (detail) { if (detail.locked) { - delete unlockedAlbums.value[item.name || ''] + delete unlockedAlbums.value[item.name] handleSaveUnlockedAlbums() } else if (detail.photos) { @@ -170,7 +190,7 @@ function handleOnUnlockSuccess(data: { albumKey: string, token: string, photos: const albumIndex = dataList.value.findIndex(a => a.name === data.albumKey) if (albumIndex !== -1) { - dataList.value[albumIndex].photos = data.photos as typeof dataList.value[number]['photos'] + dataList.value[albumIndex].photos = data.photos as ILovePhoto[] dataList.value[albumIndex].locked = false } currentUnlockAlbum.value = null @@ -181,7 +201,6 @@ function handleOnUnlockSuccess(data: { albumKey: string, token: string, photos: /* ---------------- 生命周期 ---------------- */ onLoad(() => { - uni.setNavigationBarTitle({ title: '恋爱相册' }) handleRestoreUnlockedAlbums() handleGetData() }) @@ -193,52 +212,38 @@ onPullDownRefresh(() => {