From b21d7fb163a4ef531316e53aeb6c4262b8d41927 Mon Sep 17 00:00:00 2001 From: liuyun Date: Wed, 21 Oct 2026 11:41:41 +0800 Subject: [PATCH] =?UTF-8?q?feat(record):=20=E7=95=99=E7=97=95=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E7=85=A7=E7=89=87=E9=A2=84=E8=A7=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- src/api/record.ts | 5 ++++ src/pages/ltc/record/index.vue | 49 +++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/api/record.ts b/src/api/record.ts index d45a309..4599ff5 100644 --- a/src/api/record.ts +++ b/src/api/record.ts @@ -122,6 +122,11 @@ export function getRecord(id: string): Promise { return http.get(`/record/${id}`) } +/** 照片 GET 预签名 URL(临时预览/下载,默认 1 小时有效)。 */ +export function getPhotoUrl(photoId: string): Promise<{ url: string }> { + return http.get<{ url: string }>(`/record/photo/${photoId}/url`) +} + /** 垫付台账:某老人 is_prepaid=1 的留痕列表。 */ export function listPrepaidRecords(elderId: string): Promise { return http.get('/record/prepaid-list', { params: { elderId } }) diff --git a/src/pages/ltc/record/index.vue b/src/pages/ltc/record/index.vue index 84ee690..7c3bfc9 100644 --- a/src/pages/ltc/record/index.vue +++ b/src/pages/ltc/record/index.vue @@ -70,7 +70,21 @@ 照片 - + + + @@ -115,6 +129,7 @@ import { EXEC_RESULT_TAG_MAP, LOCATE_STATUS_TAG_MAP, RECORD_STATUS_TAG_MAP, + getPhotoUrl, getRecord, listRecords, type ServiceRecord, @@ -177,6 +192,8 @@ const list = ref([]) const detailVisible = ref(false) const detailLoading = ref(false) const detail = ref(null) +/** photoId → presigned url;null 表示获取失败,缺失表示加载中。 */ +const photoUrls = ref>({}) const str = (v: unknown): string | undefined => (typeof v === 'string' && v !== '' ? v : undefined) @@ -246,9 +263,11 @@ async function loadMaps(): Promise { async function openDetail(row: Record): Promise { detailVisible.value = true detail.value = null + photoUrls.value = {} detailLoading.value = true try { detail.value = await getRecord(String(row.id)) + if (detail.value) void loadPhotoUrls(detail.value.photos) } catch (e) { if (e instanceof ApiError) ElMessage.error(e.message) } finally { @@ -256,6 +275,30 @@ async function openDetail(row: Record): Promise { } } +/** 为每张照片并发取 presigned url;失败置 null → 模板显示「获取失败」。 */ +async function loadPhotoUrls(photos: ServiceRecordDetail['photos']): Promise { + const next: Record = {} + await Promise.all( + photos.map(async (p) => { + try { + const { url } = await getPhotoUrl(p.id) + next[p.id] = url + } catch { + next[p.id] = null + } + }), + ) + photoUrls.value = next +} + +function photoUrlOf(id: string): string { + return photoUrls.value[id] ?? '' +} + +function photoFailed(id: string): boolean { + return photoUrls.value[id] === null +} + onMounted(() => { void loadMaps() fetchList() @@ -278,4 +321,8 @@ onMounted(() => { .record-page__detail { @apply max-h-[60vh] overflow-auto; } + +.record-page__photo { + @apply block h-16 w-16 cursor-zoom-in rounded object-cover; +}