feat(viewer): 相册页广告轮播——4s 自动/暂停/滑动/徽标/会话级关闭

Task 10(广告位轮播实施计划):
- ads/carousel.ts 纯逻辑:nextIndex 环形推进(末→首、单条恒 0)+ swipeStep
  滑动判定(≥40px 且水平分量严格大于垂直),carousel.spec 直测 7 例
- AdCarousel.vue:10:3 轮播,4s 自动推进(本地常量 ROTATE_MS);pointerenter/
  pointerdown 暂停、pointerleave 恢复;圆点跳页;touchstart/touchend 滑动翻页
  (cancel 合成 click);单条静态无圆点;左上角常驻「广告」徽标 + 右上角 ≥44px
  ✕ 关闭(emit close,组件无副作用);视觉一律 var(--viewer-*)(半透明层经
  color-mix 自 token 派生)
- client.ts:PublicAd/PublicAdListResponse 契约类型 + getPublicAds(同形
  apiRequest);__tests__/ad-carousel.spec.ts 组件级 6 例(圆点/关闭/window.open
  spy/假时钟自动轮播与暂停/滑动/单条静态)
- ActivityPage:load() 成功分支独立拉取广告(失败静默、会话级关闭记忆
  viewer:ads-dismissed 先行、沿用 sequence 防跨相册竞态);AlbumHeader 与
  PhotoFeed 之间挂 AdCarousel;i18n zh-CN/en 补 ads.* 词条

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-29 00:58:48 +08:00
parent 80405cfcc1
commit f1c13bff7c
8 changed files with 428 additions and 0 deletions
+8
View File
@@ -19,6 +19,14 @@ export default {
},
lang: { switch: 'Switch language' },
prefs: { reduceMotion: 'Reduce motion' },
// Ad carousel (Task 10): badge text = label (compliance, always visible).
ads: {
label: 'Ad',
close: 'Close ads',
open: 'Open ad link',
dots: 'Carousel position',
goto: 'Go to {n}',
},
// Embed carousel iframe page (P4b Task 4): subset driven by the lang query.
embed: {
comingSoon: 'Photos coming soon',
+8
View File
@@ -19,6 +19,14 @@ export default {
},
lang: { switch: '切换语言' },
prefs: { reduceMotion: '减少动画' },
// 广告位轮播(Task 10):徽标文案=label(合规可识别性,随轮播恒可见)。
ads: {
label: '广告',
close: '关闭广告',
open: '打开广告链接',
dots: '轮播位置',
goto: '第 {n} 张',
},
// 嵌入轮播 iframe 页(P4b Task 4;UI-01 补全):独立于宿主语言的词条子集
// (lang 查询驱动)。图片无真实描述时只给上下文标签(§5.3 不编造画面)。
embed: {