From fb92782c92684dba1c9e0327a4f1707bf88a1316 Mon Sep 17 00:00:00 2001 From: zhengchiliu <857493511@qq.com> Date: Wed, 16 Sep 2026 02:28:58 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E7=A9=BF=E6=90=AD=E8=AF=A6=E6=83=85):=20?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=A4=BE=E5=8C=BA=E5=85=AC=E5=BC=80=E7=A9=BF?= =?UTF-8?q?=E6=90=AD=E5=8F=AA=E8=AF=BB=E8=AE=BF=E9=97=AE=E5=8D=95=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 非属主查看社区公开穿搭时携带 outfit_uuid 凭证请求单品详情, 放行后端只读读取,避免名称退化为「未命名」;单品详情页同步 支持 outfit_uuid 只读凭证。点赞增加防连点,来源胶囊与状态 胶囊文案重复时只保留一个。 --- .../pages/clothes-detail/clothes-detail.ts | 18 +++--- .../pages/outfit-detail/outfit-detail.ts | 56 +++++++++++-------- .../pages/outfit-detail/outfit-detail.wxml | 7 ++- 3 files changed, 49 insertions(+), 32 deletions(-) diff --git a/miniprogram/pages/clothes-detail/clothes-detail.ts b/miniprogram/pages/clothes-detail/clothes-detail.ts index f64184c..2cc7c8b 100644 --- a/miniprogram/pages/clothes-detail/clothes-detail.ts +++ b/miniprogram/pages/clothes-detail/clothes-detail.ts @@ -104,8 +104,9 @@ function statusToStep(status: number): number { Page({ data: { uuid: '', - // 来自穿搭分享的只读查看:携带 share_uuid,隐藏编辑/删除 + // 只读查看的两个凭证:share_uuid(穿搭分享)/ outfit_uuid(社区公开穿搭),命中即隐藏编辑/删除 shareUUID: '', + outfitUUID: '', readonly: false, attrGroups: ATTR_GROUPS, colorPresets: COLOR_PRESETS, @@ -145,9 +146,10 @@ Page({ onLoad(query: Record) { const uuid = query.uuid || '' const shareUUID = query.share_uuid || '' - const readonly = !!shareUUID + const outfitUUID = query.outfit_uuid || '' + const readonly = !!(shareUUID || outfitUUID) logger.debug(LOG, 'onLoad, uuid=', uuid, 'readonly=', readonly) - this.setData({ uuid, shareUUID, readonly }) + this.setData({ uuid, shareUUID, outfitUUID, readonly }) if (!uuid) { // uuid 缺失时不请求不轮询,否则会停在空白页且无法退出 logger.warn(LOG, 'onLoad 缺少 uuid 参数') @@ -155,7 +157,7 @@ Page({ return } this.fetchDetail().then(() => { - // 只读(来自穿搭分享)场景无需轮询 AI 处理状态 + // 只读(来自穿搭分享 / 社区公开穿搭)场景无需轮询 AI 处理状态 if (readonly) return // 详情响应已带处理状态:成功/失败等终态直接定态,仅处理中才轮询 if (isProcessTerminal(this.data.detail)) return @@ -171,10 +173,10 @@ Page({ }, fetchDetail(): Promise { - // 只读场景携带 share_uuid,后端据此放行非属主读取衣物详情 - const url = this.data.readonly - ? `/clothes/${this.data.uuid}?share_uuid=${this.data.shareUUID}` - : `/clothes/${this.data.uuid}` + // 只读场景需携带放行凭证:穿搭分享用 share_uuid,社区公开穿搭用 outfit_uuid + let url = `/clothes/${this.data.uuid}` + if (this.data.shareUUID) url += `?share_uuid=${this.data.shareUUID}` + else if (this.data.outfitUUID) url += `?outfit_uuid=${this.data.outfitUUID}` return request({ url }) .then((detail) => { logger.debug(LOG, '详情加载成功, name=', detail && detail.name) diff --git a/miniprogram/pages/outfit-detail/outfit-detail.ts b/miniprogram/pages/outfit-detail/outfit-detail.ts index e900674..0f02187 100644 --- a/miniprogram/pages/outfit-detail/outfit-detail.ts +++ b/miniprogram/pages/outfit-detail/outfit-detail.ts @@ -227,27 +227,30 @@ Page({ statePill: outfitStatusPill(outfit), }) - // 封面与衣物缩略图直接使用穿搭明细里的抠图(processed_image), - // 避免非属主逐件请求 /clothes/:uuid 被拒(50005)导致图片与名称全部丢失。 + // 封面与衣物缩略图先直接使用穿搭明细里的抠图(processed_image), + // 即使后续单品详情拉取失败,图片也不会丢。 const baseClothes = (outfit.items || []).map( (it) => ({ clothes_uuid: it.clothes_uuid, processed_image: it.processed_image }) as ClothesItem, ) this.setData({ clothes: baseClothes }) - // 属主可进一步拉取衣物详情补充名称;非属主无权限,跳过。 - if (this.data.isOwner) { - const clothes = await Promise.all( - (outfit.items || []).map(async (it) => { - try { - return await request({ url: `/clothes/${it.clothes_uuid}`, showError: false }) - } catch (e: any) { - logger.warn(LOG, '单品详情拉取失败, uuid=', it.clothes_uuid, 'code=', e && e.code) - return { clothes_uuid: it.clothes_uuid, processed_image: it.processed_image } as ClothesItem - } - }) - ) - this.setData({ clothes }) - } + // 拉取单品详情补充名称与属性:属主直接读;非属主(社区公开穿搭 / 他人分享)携带本穿搭 uuid, + // 由后端只读放行,避免被拒(50005)导致名称全部退化成「未命名」。 + const clothesQuery = this.data.isOwner ? '' : `?outfit_uuid=${this.data.uuid}` + const clothes = await Promise.all( + (outfit.items || []).map(async (it) => { + try { + return await request({ + url: `/clothes/${it.clothes_uuid}${clothesQuery}`, + showError: false, + }) + } catch (e: any) { + logger.warn(LOG, '单品详情拉取失败, uuid=', it.clothes_uuid, 'code=', e && e.code) + return { clothes_uuid: it.clothes_uuid, processed_image: it.processed_image } as ClothesItem + } + }) + ) + this.setData({ clothes }) // 点赞状态:失败静默保持默认,不影响详情展示 request<{ is_liked: boolean; like_count: number }>({ @@ -267,6 +270,12 @@ Page({ }, onLike() { + // 防连点:请求进行中忽略后续点击,避免误触/连点并发发出多条点赞、取消请求 + if ((this as any).liking) { + logger.debug(LOG, '点赞请求进行中,忽略重复点击') + return + } + ;(this as any).liking = true const action = this.data.isLiked ? 2 : 1 request({ url: '/like', method: 'POST', data: { target_uuid: this.data.uuid, action } }) .then(() => { @@ -277,6 +286,9 @@ Page({ }) }) .catch((e: any) => logger.warn(LOG, '点赞操作失败, action=', action, 'code=', e && e.code)) + .finally(() => { + ;(this as any).liking = false + }) }, onCollect() { @@ -416,14 +428,12 @@ Page({ onItemTap(e: WechatMiniprogram.TouchEvent) { const uuid = e.currentTarget.dataset.uuid as string - // 非属主无权读取衣物详情(50005),点击仅提示;属主正常跳转。 - if (!this.data.isOwner) { - logger.debug(LOG, '非属主点击衣物,仅可查看穿搭, uuid=', uuid) - wx.showToast({ title: '仅可查看穿搭', icon: 'none' }) - return - } + // 非属主(社区公开穿搭 / 他人分享)携带本穿搭 uuid 进入只读详情, + // 后端据此放行;不携带时后端会按无权限拒绝(50005)。 + const query = this.data.isOwner ? '' : `&outfit_uuid=${this.data.uuid}` + logger.debug(LOG, '点击单品, uuid=', uuid, 'isOwner=', this.data.isOwner) wx.navigateTo({ - url: `/pages/clothes-detail/clothes-detail?uuid=${uuid}`, + url: `/pages/clothes-detail/clothes-detail?uuid=${uuid}${query}`, fail: (err) => logger.warn(LOG, 'navigateTo 单品详情失败, err=', err && err.errMsg), }) }, diff --git a/miniprogram/pages/outfit-detail/outfit-detail.wxml b/miniprogram/pages/outfit-detail/outfit-detail.wxml index 87c048e..f1ad831 100644 --- a/miniprogram/pages/outfit-detail/outfit-detail.wxml +++ b/miniprogram/pages/outfit-detail/outfit-detail.wxml @@ -71,7 +71,12 @@ module.exports = { cls: cls } {{outfit.outfit_name}} {{outfit.scene}} - {{outfit.source === 2 ? 'AI 推荐' : '自建'}} + + {{outfit.source === 2 ? 'AI 推荐' : '自建'}} {{statePill.text}} {{outfit.outfit_desc}}