import { request, AUTH_EXPIRED_CODES } from '../../utils/request' import { OutfitShareDetail, OutfitItem } from '../../types/models' import { ShareStatus } from '../../utils/config' import { navScroll } from '../../utils/nav' import { logger } from '../../utils/logger' // 日志模块名 const LOG = 'outfit-share-detail' Page({ data: { uuid: '', detail: null as OutfitShareDetail | null, outfit: { items: [] } as unknown as OutfitItem, loading: true, invalid: false, invalidTitle: '该分享已取消', invalidDesc: '分享链接已失效', needLogin: false, // 滚动收缩:由 utils/nav.ts 的共享 handler 驱动 navScrolled: false, // 取消分享确认:v2 玻璃弹窗 cancelVisible: false, cancelContent: '取消后该分享链接将失效', cancelButtons: [ { text: '再想想', value: '' }, { text: '取消分享', value: 'ok', type: 'main' }, ], }, // scroll-view 滚动 → 导航收缩为玻璃小标题 onNavScroll: navScroll, onLoad(query: Record) { const uuid = query.uuid || '' logger.debug(LOG, 'onLoad, uuid=', uuid) this.setData({ uuid }) if (!uuid) { // uuid 缺失时若不兜底,loading 会永久为 true,页面白屏且无法退出 logger.warn(LOG, 'onLoad 缺少 uuid 参数') this.setInvalid('链接不完整', '缺少分享标识,无法打开') return } this.fetchDetail() }, fetchDetail() { request({ url: `/outfit-share/${this.data.uuid}`, showError: false }) .then((detail) => { logger.debug(LOG, '详情加载成功, status=', detail && detail.status) if (this.checkInvalid(detail)) return this.setData({ detail, outfit: detail.outfit, loading: false }) }) .catch((e: any) => { const code = e && e.code logger.warn(LOG, '详情加载失败, code=', code) if (AUTH_EXPIRED_CODES.indexOf(code) >= 0) { // 查看分享需登录:给「去登录」出口,登录成功后回到本页 this.setData({ loading: false, invalid: true, needLogin: true, invalidTitle: '请先登录', invalidDesc: '登录后即可查看好友分享的穿搭', }) return } if (code === 90104) { this.setInvalid('分享已取消', '该分享已被创建者取消') } else if (code === 90103) { this.setInvalid('分享已失效', '该分享链接无效或对应穿搭已不可见') } else { // 兜底:任何未知错误都不能停在空白页 this.setInvalid('加载失败', '请稍后重试') } }) }, // 本地状态校验,返回 true 表示已置为失效态 checkInvalid(detail: OutfitShareDetail): boolean { if (detail.status === ShareStatus.CANCELLED) { this.setInvalid('分享已取消', '该分享已被创建者取消') return true } return false }, setInvalid(title: string, desc: string) { this.setData({ loading: false, invalid: true, needLogin: false, invalidTitle: title, invalidDesc: desc, }) }, onItemTap(e: WechatMiniprogram.TouchEvent) { const uuid = e.currentTarget.dataset.uuid as string // 只读查看:携带 share_uuid,后端据此放行非属主读取衣物详情 logger.debug(LOG, '点击衣物, uuid=', uuid) wx.navigateTo({ url: `/pages/clothes-detail/clothes-detail?uuid=${uuid}&share_uuid=${this.data.uuid}`, fail: (err) => logger.warn(LOG, 'navigateTo 单品详情失败, err=', err && err.errMsg), }) }, onCancel() { this.setData({ cancelVisible: true }) }, onCancelCancel() { this.setData({ cancelVisible: false }) }, onCancelConfirm(e: WechatMiniprogram.CustomEvent) { this.setData({ cancelVisible: false }) if (e.detail.value !== 'ok') return request({ url: `/outfit-share/${this.data.uuid}/cancel`, method: 'POST' }) .then(() => { logger.info(LOG, '取消分享成功') wx.showToast({ title: '已取消', icon: 'success' }) ;(this as any).backTimer = setTimeout( () => wx.navigateBack({ fail: (err: any) => logger.warn(LOG, 'navigateBack 失败, err=', err && err.errMsg), }), 500, ) }) .catch((err: any) => logger.warn(LOG, '取消分享失败, code=', err && err.code)) }, onBackHome() { wx.switchTab({ url: '/pages/wardrobe/wardrobe', fail: (e: any) => logger.warn(LOG, 'switchTab 衣橱失败, err=', e && e.errMsg), }) }, onGoLogin() { const redirect = `/pages/outfit-share-detail/outfit-share-detail?uuid=${this.data.uuid}` const loginUrl = `/pages/login/login?redirect=${encodeURIComponent(redirect)}` wx.navigateTo({ url: loginUrl, fail: () => { wx.redirectTo({ url: loginUrl, fail: () => wx.switchTab({ url: '/pages/profile/profile' }), }) }, }) }, onShareAppMessage() { const name = (this.data.outfit && this.data.outfit.outfit_name) || '好友的穿搭' const owner = (this.data.detail && this.data.detail.owner_name) || '好友' logger.debug(LOG, '转发分享, uuid=', this.data.uuid) return { title: `${owner} 向你分享了穿搭「${name}」`, path: `/pages/outfit-share-detail/outfit-share-detail?uuid=${this.data.uuid}`, } }, onUnload() { const timer = (this as any).backTimer if (timer) { clearTimeout(timer) ;(this as any).backTimer = null } }, })