diff --git a/damo/damo.json b/damo/damo.json new file mode 100644 index 0000000..465a668 --- /dev/null +++ b/damo/damo.json @@ -0,0 +1,164 @@ +{"items": [ + { + "source_file": "01_cream_sweater.jpg", + "clothes": { + "category_main": "上装", + "category_sub": "毛衣", + "style": "休闲风", + "color_main": "米色", + "color_sub": "红色", + "thickness": "厚", + "version": "宽松", + "material": "针织", + "pattern": "logo图案", + "sleeve_type": "长袖", + "clothes_type": "短款", + "neckline_type": "圆领", + "formality": "2", + "occasions": "日常通勤,校园上课", + "visual_impact": "3", + "name": "米色圆领针织毛衣", + "remark": "可见红色胸前图案。", + "processed_image": "01_cream_sweater.jpg" + } + }, + { + "source_file": "02_ivory_strap_dress.jpg", + "clothes": { + "category_main": "连衣裙", + "category_sub": "吊带裙", + "style": "优雅风", + "color_main": "米色", + "color_sub": "金色", + "thickness": "适中", + "version": "修身", + "material": "", + "pattern": "纯色", + "sleeve_type": "吊带", + "clothes_type": "短款", + "neckline_type": "", + "formality": "3", + "occasions": "约会聚会", + "visual_impact": "4", + "name": "象牙白金扣吊带连衣短裙", + "remark": "象牙白偏米色;胸部为心形领。", + "processed_image": "02_ivory_strap_dress.jpg" + } + }, + { + "source_file": "03_white_jk_blouse.jpg", + "clothes": { + "category_main": "上装", + "category_sub": "衬衫", + "style": "学院风", + "color_main": "白色", + "color_sub": "藏青色", + "thickness": "适中", + "version": "常规合身", + "material": "", + "pattern": "条纹", + "sleeve_type": "长袖", + "clothes_type": "短款", + "neckline_type": "翻领", + "formality": "2", + "occasions": "校园上课,约会聚会", + "visual_impact": "4", + "name": "白色长袖JK水手服上衣", + "remark": "藏青领口及袖口配白条纹,另有酒红色蝴蝶结;水手领归入翻领。", + "processed_image": "03_white_jk_blouse.jpg" + } + }, + { + "source_file": "04_pink_plaid_skirt.jpg", + "clothes": { + "category_main": "下装", + "category_sub": "半身裙", + "style": "学院风", + "color_main": "粉色", + "color_sub": "黑色", + "thickness": "适中", + "version": "常规合身", + "material": "", + "pattern": "格纹", + "sleeve_type": "", + "clothes_type": "短款", + "neckline_type": "", + "formality": "2", + "occasions": "校园上课,约会聚会", + "visual_impact": "4", + "name": "粉色格纹百褶短裙", + "remark": "另有白色格纹;百褶A字廓形。", + "processed_image": "04_pink_plaid_skirt.jpg" + } + }, + { + "source_file": "05_black_jk_blouse.jpg", + "clothes": { + "category_main": "上装", + "category_sub": "衬衫", + "style": "学院风", + "color_main": "黑色", + "color_sub": "酒红色", + "thickness": "适中", + "version": "常规合身", + "material": "", + "pattern": "条纹", + "sleeve_type": "短袖", + "clothes_type": "常规", + "neckline_type": "翻领", + "formality": "2", + "occasions": "校园上课,约会聚会", + "visual_impact": "4", + "name": "黑色短袖JK水手服上衣", + "remark": "酒红色蝴蝶结,领口另有白条纹;水手领归入翻领。", + "processed_image": "05_black_jk_blouse.jpg" + } + }, + { + "source_file": "06_navy_pleated_skirt.jpg", + "clothes": { + "category_main": "下装", + "category_sub": "半身裙", + "style": "学院风", + "color_main": "藏青色", + "color_sub": "", + "thickness": "适中", + "version": "常规合身", + "material": "", + "pattern": "纯色", + "sleeve_type": "", + "clothes_type": "短款", + "neckline_type": "", + "formality": "2", + "occasions": "校园上课,日常通勤", + "visual_impact": "2", + "name": "藏青色百褶半身裙", + "remark": "", + "processed_image": "06_navy_pleated_skirt.jpg" + } + }, + { + "source_file": "07_ivory_pearl_high_heels.jpg", + "clothes": { + "category_main": "鞋", + "category_sub": "高跟鞋", + "style": "优雅风", + "color_main": "米色", + "color_sub": "银色", + "thickness": "", + "version": "", + "material": "", + "pattern": "纯色", + "sleeve_type": "", + "clothes_type": "", + "neckline_type": "", + "formality": "4", + "occasions": "婚礼宴会,约会聚会", + "visual_impact": "4", + "name": "米白色珍珠踝链尖头细高跟鞋", + "remark": "可见珍珠式踝链、银色链条和同色立体纹理。", + "processed_image": "07_ivory_pearl_high_heels.jpg" + } + } + ] +} \ No newline at end of file diff --git a/damo/image/01_cream_sweater.jpg b/damo/image/01_cream_sweater.jpg new file mode 100644 index 0000000..27f9ad1 Binary files /dev/null and b/damo/image/01_cream_sweater.jpg differ diff --git a/damo/image/02_ivory_strap_dress.jpg b/damo/image/02_ivory_strap_dress.jpg new file mode 100644 index 0000000..7fd50cf Binary files /dev/null and b/damo/image/02_ivory_strap_dress.jpg differ diff --git a/damo/image/03_white_jk_blouse.jpg b/damo/image/03_white_jk_blouse.jpg new file mode 100644 index 0000000..73ba81a Binary files /dev/null and b/damo/image/03_white_jk_blouse.jpg differ diff --git a/damo/image/04_pink_plaid_skirt.jpg b/damo/image/04_pink_plaid_skirt.jpg new file mode 100644 index 0000000..6b6cc30 Binary files /dev/null and b/damo/image/04_pink_plaid_skirt.jpg differ diff --git a/damo/image/05_black_jk_blouse.jpg b/damo/image/05_black_jk_blouse.jpg new file mode 100644 index 0000000..11bc4dc Binary files /dev/null and b/damo/image/05_black_jk_blouse.jpg differ diff --git a/damo/image/06_navy_pleated_skirt.jpg b/damo/image/06_navy_pleated_skirt.jpg new file mode 100644 index 0000000..3051df1 Binary files /dev/null and b/damo/image/06_navy_pleated_skirt.jpg differ diff --git a/damo/image/07_ivory_pearl_high_heels.jpg b/damo/image/07_ivory_pearl_high_heels.jpg new file mode 100644 index 0000000..793e1a4 Binary files /dev/null and b/damo/image/07_ivory_pearl_high_heels.jpg differ diff --git a/miniprogram/app.wxss b/miniprogram/app.wxss index d8c0b8b..0b790ad 100644 --- a/miniprogram/app.wxss +++ b/miniprogram/app.wxss @@ -878,20 +878,6 @@ swiper-item { color: var(--ink); flex-shrink: 0; } -/* 示例内容角标:浅填充底 + 灰字,弱于业务状态胶囊 */ -.guest-flag { - position: absolute; - top: 14rpx; - left: 14rpx; - height: 38rpx; - padding: 0 14rpx; - border-radius: 20rpx; - background: var(--fill-2); - font-size: 19rpx; - font-weight: 500; - line-height: 38rpx; - color: var(--ink-2); -} /* 游客态底部一行登录引导 */ .guest-foot { display: flex; diff --git a/miniprogram/damo/damo.ts b/miniprogram/damo/damo.ts new file mode 100644 index 0000000..789f8fe --- /dev/null +++ b/miniprogram/damo/damo.ts @@ -0,0 +1,235 @@ +import { ClothesItem } from '../types/models' +import { ProcessStatus } from '../utils/config' + +/** + * damo 示例素材(游客态唯一数据源)。 + * + * 合规背景(微信审核整改):未登录用户必须能完整浏览与点击体验功能服务, + * 因此衣橱示例卡片可点开「示例衣物详情」,详情完全由本地数据渲染,零请求、只读。 + * + * 素材来源:项目根目录 damo/damo.json 与 damo/image/(原图 1024×1024), + * 图片已压缩为 512px / quality 82 并复制到 miniprogram/damo/image/ 随包发布, + * 页面通过包内绝对路径引用(如 /damo/image/01_cream_sweater.jpg)。 + */ + +// 包内图片目录(绝对路径,结尾不带斜杠) +const DAMO_IMAGE = '/damo/image' + +// 衣物属性:与 ClothesItem 除 uuid / 图片 / 处理状态之外的字段一一对应 +interface DamoAttr { + category_main: string + category_sub: string + style: string + color_main: string + color_sub: string + thickness: string + version: string + material: string + pattern: string + sleeve_type: string + clothes_type: string + neckline_type: string + formality: string + occasions: string + visual_impact: string + name: string + remark: string +} + +interface DamoRaw { + uuid: string + file: string + attr: DamoAttr +} + +const DAMO_RAW: DamoRaw[] = [ + { + uuid: 'damo-01', + file: '01_cream_sweater.jpg', + attr: { + category_main: '上装', + category_sub: '毛衣', + style: '休闲风', + color_main: '米色', + color_sub: '红色', + thickness: '厚', + version: '宽松', + material: '针织', + pattern: 'logo图案', + sleeve_type: '长袖', + clothes_type: '短款', + neckline_type: '圆领', + formality: '2', + occasions: '日常通勤,校园上课', + visual_impact: '3', + name: '米色圆领针织毛衣', + remark: '可见红色胸前图案。', + }, + }, + { + uuid: 'damo-02', + file: '02_ivory_strap_dress.jpg', + attr: { + category_main: '连衣裙', + category_sub: '吊带裙', + style: '优雅风', + color_main: '米色', + color_sub: '金色', + thickness: '适中', + version: '修身', + material: '', + pattern: '纯色', + sleeve_type: '吊带', + clothes_type: '短款', + neckline_type: '', + formality: '3', + occasions: '约会聚会', + visual_impact: '4', + name: '象牙白金扣吊带连衣短裙', + remark: '象牙白偏米色;胸部为心形领。', + }, + }, + { + uuid: 'damo-03', + file: '03_white_jk_blouse.jpg', + attr: { + category_main: '上装', + category_sub: '衬衫', + style: '学院风', + color_main: '白色', + color_sub: '藏青色', + thickness: '适中', + version: '常规合身', + material: '', + pattern: '条纹', + sleeve_type: '长袖', + clothes_type: '短款', + neckline_type: '翻领', + formality: '2', + occasions: '校园上课,约会聚会', + visual_impact: '4', + name: '白色长袖JK水手服上衣', + remark: '藏青领口及袖口配白条纹,另有酒红色蝴蝶结;水手领归入翻领。', + }, + }, + { + uuid: 'damo-04', + file: '04_pink_plaid_skirt.jpg', + attr: { + category_main: '下装', + category_sub: '半身裙', + style: '学院风', + color_main: '粉色', + color_sub: '黑色', + thickness: '适中', + version: '常规合身', + material: '', + pattern: '格纹', + sleeve_type: '', + clothes_type: '短款', + neckline_type: '', + formality: '2', + occasions: '校园上课,约会聚会', + visual_impact: '4', + name: '粉色格纹百褶短裙', + remark: '另有白色格纹;百褶A字廓形。', + }, + }, + { + uuid: 'damo-05', + file: '05_black_jk_blouse.jpg', + attr: { + category_main: '上装', + category_sub: '衬衫', + style: '学院风', + color_main: '黑色', + color_sub: '酒红色', + thickness: '适中', + version: '常规合身', + material: '', + pattern: '条纹', + sleeve_type: '短袖', + clothes_type: '常规', + neckline_type: '翻领', + formality: '2', + occasions: '校园上课,约会聚会', + visual_impact: '4', + name: '黑色短袖JK水手服上衣', + remark: '酒红色蝴蝶结,领口另有白条纹;水手领归入翻领。', + }, + }, + { + uuid: 'damo-06', + file: '06_navy_pleated_skirt.jpg', + attr: { + category_main: '下装', + category_sub: '半身裙', + style: '学院风', + color_main: '藏青色', + color_sub: '', + thickness: '适中', + version: '常规合身', + material: '', + pattern: '纯色', + sleeve_type: '', + clothes_type: '短款', + neckline_type: '', + formality: '2', + occasions: '校园上课,日常通勤', + visual_impact: '2', + name: '藏青色百褶半身裙', + remark: '', + }, + }, + { + uuid: 'damo-07', + file: '07_ivory_pearl_high_heels.jpg', + attr: { + category_main: '鞋', + category_sub: '高跟鞋', + style: '优雅风', + color_main: '米色', + color_sub: '银色', + thickness: '', + version: '', + material: '', + pattern: '纯色', + sleeve_type: '', + clothes_type: '', + neckline_type: '', + formality: '4', + occasions: '婚礼宴会,约会聚会', + visual_impact: '4', + name: '米白色珍珠踝链尖头细高跟鞋', + remark: '可见珍珠式踝链、银色链条和同色立体纹理。', + }, + }, +] + +// 示例衣物:处理状态固定为成功,详情页据此直接渲染正常视图 +export const DAMO_CLOTHES: ClothesItem[] = DAMO_RAW.map( + (it): ClothesItem => ({ + ...it.attr, + clothes_uuid: it.uuid, + processed_image: `${DAMO_IMAGE}/${it.file}`, + image_process_status: ProcessStatus.SUCCESS, + }), +) + +const DAMO_MAP: Record = DAMO_CLOTHES.reduce( + (acc, it) => { + acc[it.clothes_uuid] = it + return acc + }, + {} as Record, +) + +// 按 uuid 取示例衣物:未命中返回 null,由调用方决定降级展示 +export function findDamoClothes(uuid: string): ClothesItem | null { + return DAMO_MAP[uuid] || null +} + +// 游客态唯一一套示例搭配(黑色短袖JK水手服上衣 + 藏青色百褶半身裙) +export const DAMO_OUTFIT_ITEMS: ClothesItem[] = ['damo-05', 'damo-06'] + .map((uuid) => findDamoClothes(uuid)) + .filter((it): it is ClothesItem => !!it) diff --git a/miniprogram/damo/image/01_cream_sweater.jpg b/miniprogram/damo/image/01_cream_sweater.jpg new file mode 100644 index 0000000..bdc4bbc Binary files /dev/null and b/miniprogram/damo/image/01_cream_sweater.jpg differ diff --git a/miniprogram/damo/image/02_ivory_strap_dress.jpg b/miniprogram/damo/image/02_ivory_strap_dress.jpg new file mode 100644 index 0000000..a011ea7 Binary files /dev/null and b/miniprogram/damo/image/02_ivory_strap_dress.jpg differ diff --git a/miniprogram/damo/image/03_white_jk_blouse.jpg b/miniprogram/damo/image/03_white_jk_blouse.jpg new file mode 100644 index 0000000..cae4bbd Binary files /dev/null and b/miniprogram/damo/image/03_white_jk_blouse.jpg differ diff --git a/miniprogram/damo/image/04_pink_plaid_skirt.jpg b/miniprogram/damo/image/04_pink_plaid_skirt.jpg new file mode 100644 index 0000000..a792e59 Binary files /dev/null and b/miniprogram/damo/image/04_pink_plaid_skirt.jpg differ diff --git a/miniprogram/damo/image/05_black_jk_blouse.jpg b/miniprogram/damo/image/05_black_jk_blouse.jpg new file mode 100644 index 0000000..d8d8a86 Binary files /dev/null and b/miniprogram/damo/image/05_black_jk_blouse.jpg differ diff --git a/miniprogram/damo/image/06_navy_pleated_skirt.jpg b/miniprogram/damo/image/06_navy_pleated_skirt.jpg new file mode 100644 index 0000000..2117b42 Binary files /dev/null and b/miniprogram/damo/image/06_navy_pleated_skirt.jpg differ diff --git a/miniprogram/damo/image/07_ivory_pearl_high_heels.jpg b/miniprogram/damo/image/07_ivory_pearl_high_heels.jpg new file mode 100644 index 0000000..c568a00 Binary files /dev/null and b/miniprogram/damo/image/07_ivory_pearl_high_heels.jpg differ diff --git a/miniprogram/pages/ai-recommend/ai-recommend.ts b/miniprogram/pages/ai-recommend/ai-recommend.ts index 44fafcc..f2fdc61 100644 --- a/miniprogram/pages/ai-recommend/ai-recommend.ts +++ b/miniprogram/pages/ai-recommend/ai-recommend.ts @@ -95,9 +95,35 @@ Page({ this.setData({ scene: e.detail.value }) }, - onSkipScene() { - this.setData({ showSceneSheet: false }) - this.startGenerate(1, '') + // 取消场景选择:退出 AI 推荐页返回来源页(不再用「每日推荐」自动生成) + onCancelScene() { + logger.info(LOG, '取消场景选择,返回来源页') + this.backToSource() + }, + + // 取消的统一出口:优先返回来源页(从运势进回运势、从穿搭进回穿搭); + // 页面栈不足(分享卡片/深链直达)时兜底 switchTab 回运势页 + backToSource() { + const pages = typeof getCurrentPages === 'function' ? getCurrentPages() : [] + if (pages.length > 1) { + wx.navigateBack({ + delta: 1, + fail: (e) => { + logger.warn(LOG, 'navigateBack 失败,兜底回运势页, err=', e && e.errMsg) + this.switchToHoroscope() + }, + }) + return + } + logger.warn(LOG, '页面栈不足,兜底回运势页, 栈深=', pages.length) + this.switchToHoroscope() + }, + + switchToHoroscope() { + wx.switchTab({ + url: '/pages/horoscope/horoscope', + fail: (e) => logger.warn(LOG, 'switchTab 运势失败, err=', e && e.errMsg), + }) }, onStartGenerate() { @@ -112,16 +138,19 @@ Page({ this.setData({ confirmVisible: true }) }, - // 取消生成:回到场景选择抽屉,避免停在无任何可渲染内容的空页 + // 取消生成:退出 AI 推荐页返回来源页(与抽屉「取消」语义一致,避免停在空页) onConfirmCancel() { - this.setData({ confirmVisible: false, showSceneSheet: true }) + logger.info(LOG, '确认弹窗取消,返回来源页') + this.setData({ confirmVisible: false }) + this.backToSource() }, onConfirmGenerate(e: WechatMiniprogram.CustomEvent) { this.setData({ confirmVisible: false }) if (e.detail.value !== 'ok') { - // 兜底:非「开始生成」按钮同样回到场景抽屉(取消按钮已走 cancel 分支) - this.setData({ showSceneSheet: true }) + // 兜底:非「开始生成」按钮同样按取消处理(取消按钮已走 cancel 分支) + logger.info(LOG, '确认弹窗非主按钮,按取消处理,返回来源页') + this.backToSource() return } const pending = (this as any).pendingScene || { sceneType: 1, scene: '' } diff --git a/miniprogram/pages/ai-recommend/ai-recommend.wxml b/miniprogram/pages/ai-recommend/ai-recommend.wxml index 57557e4..ccca6be 100644 --- a/miniprogram/pages/ai-recommend/ai-recommend.wxml +++ b/miniprogram/pages/ai-recommend/ai-recommend.wxml @@ -95,13 +95,13 @@ module.exports = { cls: cls } - + 选择推荐场景 - 跳过 + 取消 diff --git a/miniprogram/pages/closet-share/closet-share.ts b/miniprogram/pages/closet-share/closet-share.ts index 3232fa5..5a8208e 100644 --- a/miniprogram/pages/closet-share/closet-share.ts +++ b/miniprogram/pages/closet-share/closet-share.ts @@ -275,8 +275,9 @@ Page({ }, onItemTap(e: WechatMiniprogram.TouchEvent) { + // 游客态示例条目仅作视觉展示:浏览路径上不要求登录(登录入口在页脚) if (this.data.guest) { - this.onGuestLogin() + logger.debug(LOG, '游客态点击示例分享条目,仅展示不跳转') return } const uuid = e.currentTarget.dataset.uuid as string diff --git a/miniprogram/pages/clothes-detail/clothes-detail.ts b/miniprogram/pages/clothes-detail/clothes-detail.ts index 2cc7c8b..c580191 100644 --- a/miniprogram/pages/clothes-detail/clothes-detail.ts +++ b/miniprogram/pages/clothes-detail/clothes-detail.ts @@ -3,6 +3,7 @@ import { ClothesItem } from '../../types/models' import { ProcessStatus } from '../../utils/config' import { isProcessTerminal } from '../../utils/clothes-status' import { removePendingClothes } from '../../utils/pending-clothes' +import { findDamoClothes } from '../../damo/damo' import { navScroll } from '../../utils/nav' import { logger } from '../../utils/logger' @@ -108,6 +109,8 @@ Page({ shareUUID: '', outfitUUID: '', readonly: false, + // 游客态示例:由本地 damo 素材渲染的只读详情,零请求 + demo: false, attrGroups: ATTR_GROUPS, colorPresets: COLOR_PRESETS, detail: {} as ClothesItem, @@ -144,6 +147,25 @@ Page({ noop() {}, onLoad(query: Record) { + const demo = query.demo || '' + // 示例模式:游客从衣橱示例卡片进入,本地数据只读渲染,不发请求、不轮询 + if (demo) { + const detail = findDamoClothes(demo) + logger.info(LOG, '示例模式加载, demo=', demo, '命中=', !!detail) + if (!detail) { + this.setData({ demo: true, readonly: true, loading: false, notFound: true }) + return + } + this.setData({ + demo: true, + readonly: true, + uuid: detail.clothes_uuid, + detail, + loading: false, + }) + return + } + const uuid = query.uuid || '' const shareUUID = query.share_uuid || '' const outfitUUID = query.outfit_uuid || '' diff --git a/miniprogram/pages/clothes-detail/clothes-detail.wxml b/miniprogram/pages/clothes-detail/clothes-detail.wxml index 5509684..ace4260 100644 --- a/miniprogram/pages/clothes-detail/clothes-detail.wxml +++ b/miniprogram/pages/clothes-detail/clothes-detail.wxml @@ -119,6 +119,12 @@ module.exports = { hex: hex, tags: tags } + + + + 示例内容 · 登录后可上传并识别你自己的衣物 + + diff --git a/miniprogram/pages/clothes-detail/clothes-detail.wxss b/miniprogram/pages/clothes-detail/clothes-detail.wxss index 7fcabf6..28611be 100644 --- a/miniprogram/pages/clothes-detail/clothes-detail.wxss +++ b/miniprogram/pages/clothes-detail/clothes-detail.wxss @@ -176,3 +176,22 @@ width: auto; display: block; } + +/* 示例内容说明:游客态只读浏览(不引导、不打断) */ +.cd-demo { + display: flex; + align-items: center; + gap: 12rpx; + margin: 28rpx var(--pad) 0; + font-size: 22rpx; + line-height: 1.5; + color: var(--ink-3); + letter-spacing: .01em; +} + +.cd-demo .icon { + width: 28rpx; + height: 28rpx; + color: var(--ink-4); + flex-shrink: 0; +} diff --git a/miniprogram/pages/outfit/outfit.ts b/miniprogram/pages/outfit/outfit.ts index 849728c..31b6aee 100644 --- a/miniprogram/pages/outfit/outfit.ts +++ b/miniprogram/pages/outfit/outfit.ts @@ -8,7 +8,7 @@ import { OutfitStatusPill, isPendingSave, outfitStatusPill } from '../../utils/o import { setTabBarSelected } from '../../utils/tabbar' import { formatRelativeTime } from '../../utils/format' import { navScroll } from '../../utils/nav' -import { GUEST_OUTFITS, goLogin } from '../../utils/guest' +import { GUEST_OUTFIT, goLogin } from '../../utils/guest' import { logger } from '../../utils/logger' // 日志模块名 @@ -45,9 +45,11 @@ Page({ pendingCount: 0, // 滚动收缩:由 utils/nav.ts 的共享 handler 驱动 navScrolled: false, - // 游客态(未登录):展示本地示例穿搭,不发需要授权的请求 + // 游客态(未登录):只展示本地示例穿搭,不发需要授权的请求 guest: false, - guestList: GUEST_OUTFITS, + guestOutfit: GUEST_OUTFIT, + // 游客态示例搭配抽屉:可完整浏览示例单品,浏览路径上不要求登录 + guestSheetVisible: false, }, // scroll-view 滚动 → 导航收缩为玻璃小标题 @@ -72,7 +74,7 @@ Page({ if (this.data.guest) { logger.info(LOG, '检测到登录态,从游客态切换为真实穿搭列表') ;(this as any).firstShown = true - this.setData({ guest: false, guestList: [], list: [], loading: true }) + this.setData({ guest: false, guestSheetVisible: false, list: [], loading: true }) this.refresh() this.fetchPendingCount() return @@ -116,12 +118,32 @@ Page({ this.refresh() }, - // 游客态点击示例穿搭 / 受限入口:统一进入登录页,由用户自行选择是否登录 + // 游客态点击受限入口:进入登录页,由用户自行选择是否登录 onGuestLogin() { logger.debug(LOG, '游客态点击受限入口,引导登录') goLogin() }, + // 抽屉内容点击不穿透到遮罩 + noop() {}, + + // 游客态点击示例搭配:打开只读示例抽屉(浏览路径上不要求登录) + onGuestOutfitTap() { + logger.debug(LOG, '游客态打开示例搭配抽屉') + this.setData({ guestSheetVisible: true }) + }, + + onGuestSheetClose() { + this.setData({ guestSheetVisible: false }) + }, + + // 抽屉底部入口:用户主动选择登录时才进入登录页 + onGuestSheetLogin() { + logger.info(LOG, '示例搭配抽屉内主动登录') + this.setData({ guestSheetVisible: false }) + goLogin() + }, + refresh() { this.setData({ page: 1, hasMore: true, loading: this.data.list.length === 0 }) this.fetchList(1) diff --git a/miniprogram/pages/outfit/outfit.wxml b/miniprogram/pages/outfit/outfit.wxml index dc7225e..25b1a32 100644 --- a/miniprogram/pages/outfit/outfit.wxml +++ b/miniprogram/pages/outfit/outfit.wxml @@ -63,26 +63,25 @@ bind:action="onCreate" /> - + - - - - + + + + - 示例 - {{item.name}} - {{item.scene}} + {{guestOutfit.name}} + {{guestOutfit.scene}} - {{item.desc}} + {{guestOutfit.desc}} - {{item.icons.length}} 件衣物 + 示例 + {{guestOutfit.items.length}} 件衣物 - - - + @@ -151,4 +150,38 @@ 创建穿搭 AI 推荐 + + + + + + + + 示例搭配 + 关闭 + + + + {{guestOutfit.name}} + + {{guestOutfit.scene}} + 示例 + + + {{guestOutfit.desc}} + + + + + + {{item.name}} + {{item.category_main}}{{item.category_sub ? ' · ' + item.category_sub : ''}} + + + + + 登录后可创建你的穿搭 + + + diff --git a/miniprogram/pages/outfit/outfit.wxss b/miniprogram/pages/outfit/outfit.wxss index 163b086..00be00b 100644 --- a/miniprogram/pages/outfit/outfit.wxss +++ b/miniprogram/pages/outfit/outfit.wxss @@ -192,3 +192,45 @@ width: 26rpx; height: 26rpx; } + +/* ===== 游客态:示例搭配抽屉(只读浏览,不要求登录) ===== */ +.gd-hd { + padding: 8rpx var(--pad) 0; +} + +.gd-tags { + display: flex; + gap: 12rpx; + margin-top: 18rpx; +} + +.gd-desc { + margin-top: 18rpx; + padding: 0 var(--pad); + font-size: 26rpx; + line-height: 1.6; + color: var(--ink-2); +} + +.gd-items { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 32rpx 26rpx; + padding: 40rpx var(--pad) 0; +} + +.gd-item-img { + width: 100%; + aspect-ratio: 1 / 1; + background: var(--paper-2); + border-radius: var(--r-img); + overflow: hidden; + display: flex; + align-items: center; + justify-content: center; +} + +.gd-item-img .pic { + width: 100%; + height: 100%; +} diff --git a/miniprogram/pages/wardrobe/wardrobe.ts b/miniprogram/pages/wardrobe/wardrobe.ts index 1fdcd41..ee9a6f6 100644 --- a/miniprogram/pages/wardrobe/wardrobe.ts +++ b/miniprogram/pages/wardrobe/wardrobe.ts @@ -7,7 +7,7 @@ import { clothesStatusFlag } from '../../utils/clothes-status' import { resolvePendingClothes } from '../../utils/pending-clothes' import { setTabBarSelected } from '../../utils/tabbar' import { navScroll } from '../../utils/nav' -import { GUEST_WARDROBE, GuestClothes, goLogin } from '../../utils/guest' +import { GUEST_WARDROBE, goLogin } from '../../utils/guest' import { logger } from '../../utils/logger' // 日志模块名 @@ -24,9 +24,9 @@ const CATEGORIES = [ ] // 游客态分类筛选:与分类条 value 对齐,「全部」返回完整示例 -function filterGuestClothes(index: number): GuestClothes[] { +function filterGuestClothes(index: number): ClothesItem[] { const cat = CATEGORIES[index] ? CATEGORIES[index].value : '' - return cat ? GUEST_WARDROBE.filter((it) => it.category === cat) : GUEST_WARDROBE + return cat ? GUEST_WARDROBE.filter((it) => it.category_main === cat) : GUEST_WARDROBE } Page({ @@ -73,14 +73,22 @@ Page({ // 未登录:游客态浏览,零请求,不再强制跳登录(微信审核合规要求: // 用户可先浏览体验功能服务,登录与否由用户自行选择) if (!auth.isLoggedIn()) { - if (!this.data.guest) this.setData({ guest: true, list: [], loading: false }) + if (!this.data.guest) { + // 重新回到游客态(如登录态失效后选择先逛逛):按当前分类还原示例数据 + this.setData({ + guest: true, + guestList: filterGuestClothes(this.data.activeCategory), + list: [], + loading: false, + }) + } return } // 登录成功回到首页:清空示例数据,切回真实衣橱 if (this.data.guest) { logger.info(LOG, '检测到登录态,从游客态切换为真实衣橱') ;(this as any).firstShown = true - this.setData({ guest: false, guestList: [], list: [], total: 0, uploadRemain: 0, loading: true }) + this.setData({ guest: false, list: [], total: 0, uploadRemain: 0, loading: true }) this.resolvePending() this.refresh() return @@ -237,11 +245,16 @@ Page({ }, onClothesTap(e: WechatMiniprogram.CustomEvent) { + const item = e.detail.item as ClothesItem + // 游客态:打开本地示例衣物详情(只读、零请求),浏览路径上不要求登录 if (this.data.guest) { - this.onGuestLogin() + logger.debug(LOG, '游客态点击示例衣物, uuid=', item && item.clothes_uuid) + wx.navigateTo({ + url: `/pages/clothes-detail/clothes-detail?demo=${item.clothes_uuid}`, + fail: (err) => logger.warn(LOG, 'navigateTo 示例衣物详情失败, err=', err && err.errMsg), + }) return } - const item = e.detail.item as ClothesItem logger.debug(LOG, '点击衣物, uuid=', item && item.clothes_uuid) wx.navigateTo({ url: `/pages/clothes-detail/clothes-detail?uuid=${item.clothes_uuid}`, diff --git a/miniprogram/pages/wardrobe/wardrobe.wxml b/miniprogram/pages/wardrobe/wardrobe.wxml index 3c8f681..905d75e 100644 --- a/miniprogram/pages/wardrobe/wardrobe.wxml +++ b/miniprogram/pages/wardrobe/wardrobe.wxml @@ -60,15 +60,14 @@ bind:action="onUpload" /> - + - - - - 示例 - - {{item.name}} - {{item.category}} · {{item.color}}色 + + 该分类暂无示例内容 diff --git a/miniprogram/pages/wardrobe/wardrobe.wxss b/miniprogram/pages/wardrobe/wardrobe.wxss index 5a88661..a4f78f8 100644 --- a/miniprogram/pages/wardrobe/wardrobe.wxss +++ b/miniprogram/pages/wardrobe/wardrobe.wxss @@ -53,26 +53,7 @@ transform: scale(.975); } -/* ===== 游客态:示例衣物瓦片(线稿占位 + 示例角标) ===== */ -.gd-img { - position: relative; - width: 100%; - aspect-ratio: 1 / 1; - background: var(--paper-2); - border-radius: var(--r-img); - display: flex; - align-items: center; - justify-content: center; - overflow: hidden; -} - -.gd-img .gd-ph { - width: 56%; - height: 56%; - color: var(--art); -} - -/* 分类下无示例时的整行占位 */ +/* ===== 游客态:示例衣物网格(复用 clothes-card,仅保留无示例时的占位) ===== */ .gd-none { grid-column: 1 / -1; padding: 72rpx 0; diff --git a/miniprogram/utils/guest.ts b/miniprogram/utils/guest.ts index 5aa2f4d..a5dbacf 100644 --- a/miniprogram/utils/guest.ts +++ b/miniprogram/utils/guest.ts @@ -1,4 +1,5 @@ -import { HoroscopeData } from '../types/models' +import { ClothesItem, HoroscopeData } from '../types/models' +import { DAMO_CLOTHES, DAMO_OUTFIT_ITEMS } from '../damo/damo' import { logger } from './logger' // 日志模块名 @@ -7,29 +8,32 @@ const LOG = 'guest' /** * 游客态唯一数据源:未登录浏览时展示的本地示例内容 + 统一登录引导。 * - * 合规背景(微信审核驳回整改): + * 合规背景(微信审核整改): * 1. 打开小程序不得直接要求授权登录,用户应能先浏览体验功能服务; - * 2. 仅在用户主动点击受限功能时,才由用户自行选择是否登录。 + * 2. 示例内容必须能完整浏览与点开查看详情,不得在浏览路径上要求登录; + * 3. 仅在用户主动使用受限功能时,才由用户自行选择是否登录。 * - * 本模块不发起任何网络请求、不改动登录态,只提供静态示例数据与登录跳转入口。 + * 本模块不发起任何网络请求、不改动登录态:示例数据全部来自本地 damo 素材。 */ -// 衣物示例:icon 取 styles/icons.wxss 的线稿图标类名 -export interface GuestClothes { - key: string - name: string - category: string // 与衣橱分类条 value 对齐 - color: string - icon: string -} +// 衣橱示例:damo 素材(含包内图片路径),分类筛选由调用方按 category_main 本地完成 +export const GUEST_WARDROBE: ClothesItem[] = DAMO_CLOTHES -// 穿搭示例:icons 为拼图封面里的线稿占位图标 +// 穿搭示例:游客态只展示这一套(黑色短袖JK水手服上衣 + 藏青色百褶半身裙) export interface GuestOutfit { key: string name: string scene: string desc: string - icons: string[] + items: ClothesItem[] +} + +export const GUEST_OUTFIT: GuestOutfit = { + key: 'damo-outfit-1', + name: '藏青学院一套', + scene: '校园上课', + desc: '黑色短袖水手服上衣配藏青百褶半身裙,酒红蝴蝶结与白条纹作点缀', + items: DAMO_OUTFIT_ITEMS, } // 分享示例 @@ -41,44 +45,9 @@ export interface GuestShare { expireText: string } -export const GUEST_WARDROBE: GuestClothes[] = [ - { key: 'g1', name: '白衬衫', category: '上装', color: '白', icon: 'icon-shirt' }, - { key: 'g2', name: '直筒牛仔裤', category: '下装', color: '蓝', icon: 'icon-hanger' }, - { key: 'g3', name: '针织开衫', category: '外套', color: '灰', icon: 'icon-shirt' }, - { key: 'g4', name: '黑色连衣裙', category: '连衣裙', color: '黑', icon: 'icon-hanger' }, - { key: 'g5', name: '小白鞋', category: '鞋', color: '白', icon: 'icon-image' }, - { key: 'g6', name: '丝巾', category: '配饰', color: '米', icon: 'icon-sparkles' }, - { key: 'g7', name: '风衣', category: '外套', color: '卡其', icon: 'icon-shirt' }, - { key: 'g8', name: '半身裙', category: '下装', color: '棕', icon: 'icon-hanger' }, -] - -export const GUEST_OUTFITS: GuestOutfit[] = [ - { - key: 'go1', - name: '通勤的干净线条', - scene: '通勤', - desc: '衬衫配直筒裤,外搭一件风衣', - icons: ['icon-shirt', 'icon-hanger', 'icon-image'], - }, - { - key: 'go2', - name: '周末的松弛感', - scene: '周末', - desc: '针织开衫配半身裙,鞋选小白鞋', - icons: ['icon-shirt', 'icon-hanger'], - }, - { - key: 'go3', - name: '晚间约会的黑色', - scene: '约会', - desc: '黑色连衣裙加一条丝巾点亮', - icons: ['icon-hanger', 'icon-sparkles'], - }, -] - export const GUEST_SHARES: GuestShare[] = [ { key: 'gs1', kind: 'closet', title: '衣柜分享 · 12 件', typeText: '全量衣橱', expireText: '示例内容' }, - { key: 'gs2', kind: 'outfit', title: '通勤的干净线条', typeText: '穿搭分享 · 3 件', expireText: '示例内容' }, + { key: 'gs2', kind: 'outfit', title: '藏青学院一套', typeText: '穿搭分享 · 2 件', expireText: '示例内容' }, ] // 运势示例:日期取当天,保证页头日期不出现过去时间 @@ -107,7 +76,7 @@ let lastNavAt = 0 * * 与 utils/request.ts 的 redirectToLogin 的区别: * - redirectToLogin 用于「登录态失效」的被动兜底,reLaunch 清栈; - * - goLogin 用于用户主动点击受限功能的场景,navigateTo 保留返回路径, + * - goLogin 用于用户主动使用受限功能的场景,navigateTo 保留返回路径, * 用户可随时返回继续浏览,不会被强制清栈。 */ export function goLogin(options: { redirect?: string } = {}): void {