Files
juzi/taobao/pages/report/report.axml
T
xsl 774376fa16 feat: 完善淘宝小程序拍照、报告与登录流程
接入本地实时识别和自动三连拍,调整报告裁切、商品跳转、分享标题及居中页眉;完善游客会话、后台渠道隔离、部署脚本与回归测试。
2026-11-04 15:07:51 +08:00

189 lines
12 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<import src="../../components/brand-header.axml" />
<template is="brand-header" data="{{brandHeader: brandHeader}}" />
<!-- ═════ 08 报告页 —— 对照 H5 index.html #s-report L174-291 ═════
结构逐块对应:.report-title → .card.card-summary(环形评分 + 生物可视年龄 + 三维度)
→ 三组 .dimension-title + .card.card-detail(紧塑力 2 视图 / 透亮感 3 视图 / 稳韧力 2 视图)
→ .prod-title → .card.report-care-products(日常护理 + 推荐产品)→ .report-disclaimer。
样式见 report.acss;数据仍由 utils/report-model.js 的 model()/layers()/marks() 产出。 -->
<view class="report" style="padding-top:{{brandHeader.height}}px;">
<view class="session-guard" a:if="{{identityChecking || identityError}}">
<view>{{identityChecking ? '正在确认当前淘宝账号…' : identityError}}</view>
<button a:if="{{identityError}}" class="btn-primary" onTap="onRetryIdentity">重新验证</button>
</view>
<!-- H5 #s-report: background:#efefef url(bg-report-h5.webp) center top/100% auto。
该 webp 为 1080×7512 的纯 #EFEFEF 单色图(全图仅一种颜色 239,239,239),
与 app.acss 里 page 的底色完全等价;acss 侧不再引 32MB 解码量的空图,
直接用 page 底色(否则 <image> 还会把页面滚动高度撑到 2608px)。 -->
<view class="report-body" hidden="{{identityChecking || identityError}}">
<!-- H5 h1.report-title -->
<view class="report-title">您的肌肤状态表现</view>
<!-- H5 .card.card-summary -->
<view class="card card-summary">
<view class="sum-score">
<view class="score-dial">
<!-- H5 <svg class="ring"><circle class="ring-bg">+<circle class="ring-fg">:
环轨道 + conic-gradient 进度弧 + 圆头补点(acss 无 svg,几何等价) -->
<view class="ring-track"></view>
<view class="ring-arc" style="background-image: conic-gradient(#F5F078 0deg {{ringDeg}}deg, rgba(0,0,0,0) {{ringDeg}}deg);"></view>
<view class="ring-cap" a:if="{{ringCap}}" style="left:108rpx;top:14.4rpx;"></view>
<view class="ring-cap" a:if="{{ringCap}}" style="{{ringCapEnd}}"></view>
<view class="ring-hole"></view>
<view class="ring-center">
<view class="stat-value"><text class="stat-b">{{total != null ? total : '--'}}</text><text class="stat-i">分</text></view>
<view class="stat-label">综合评分</view>
</view>
</view>
</view>
<view class="sum-age">
<!-- H5 .sum-age > .stat-label -->
<view class="stat-label">生物可视年龄</view>
<view class="age-dial">
<view class="stat-value stat-age"><text class="stat-b">{{skinAge != null ? skinAge : '--'}}</text><text class="stat-i">岁</text></view>
</view>
<!-- H5 ui-20261009.css 把 .age-pill 置为 display:none !important(新版设计不再展示对比胶囊);
report-model 仍产出 ageNote,这里与 H5 一样保留数据但不展示 -->
<view class="age-pill" a:if="{{ageNote}}">{{ageNote}}</view>
</view>
<!-- H5 .card-dims:grid-column 1/-1,占满总分卡整行 -->
<view class="card-dims">
<view class="dims-row">
<view class="dim {{item.rank}}" a:for="{{dims}}" a:key="key">
<view class="dim-name">{{item.name}}</view>
<view class="dim-score {{item.rank === 'worst' ? 'dim-bad' : ''}}"><text class="dim-int">{{item.int}}</text><text class="dim-dec">.{{item.dec ? item.dec : '-'}}</text></view>
<view class="dim-bar"><view class="dim-fill" style="width:{{item.barWidth}}%;"></view></view>
<!-- H5 用 visibility 占位,非最低分维度也保留 12px 高度 -->
<view class="dim-flag">优先关注</view>
</view>
</view>
<!-- H5 #dims-note(ui-20261012 恢复了这块「近期优先关注」) -->
<view class="dims-note" a:if="{{focusName}}">
<view class="dims-note-l1">近期优先关注:<text class="dims-focus">{{focusName}}</text></view>
<view class="dims-note-l2">{{focusSlogan}}</view>
</view>
</view>
</view>
<!-- H5 三组 <h2 class="dimension-title"> + <div class="card card-detail"> -->
<block a:for="{{cards}}" a:for-item="card" a:for-index="ci" a:key="key">
<view class="dimension-title {{card.titleCls}}">{{card.title}}</view>
<view class="card card-detail {{card.cardCls}}">
<!-- H5 .detail-tabs > button.dtab > span.dtab-tx -->
<view class="detail-tabs">
<view class="dtab {{card.index === vi ? 'active' : ''}}" a:for="{{card.views}}" a:for-item="tab" a:for-index="vi" a:key="key"
data-card="{{card.key}}" data-index="{{vi}}" onTap="onTabTap">
<text class="dtab-tx">{{tab.name}}</text>
</view>
</view>
<view class="detail-viewport {{card.dragging ? 'dragging' : ''}}" style="{{card.height ? 'height:' + card.height + 'px;' : ''}}">
<view class="detail-panels {{card.dragging ? 'dragging' : ''}}" style="transform:translateX(-{{card.index * 100}}%) translateX({{card.dragOffset || 0}}px);">
<block a:for="{{card.views}}" a:for-item="view" a:for-index="vi" a:key="key">
<!-- Keep all panels mounted for the H5 finger-following track. -->
<view class="dpanel {{card.index === vi ? 'active' : ''}}" aria-hidden="{{card.index !== vi}}">
<view class="ditem">
<view class="viz-frame {{view.frameCls}}" data-card="{{card.key}}" data-view="{{view.key}}"
onTouchStart="onPanelTouchStart" onTouchMove="onPanelTouchMove" onTouchEnd="onPanelTouchEnd" onTouchCancel="onPanelTouchCancel" onTap="onZoomPhoto">
<!-- hasVisual=false 时整块画框只留占位文案(H5 renderViz 的降级:轮廓/肤色/平滑度/痘痘
必须有人脸照片,皱纹/水分/泛红可只挂 face_maps 图层) -->
<view class="viz-stage" a:if="{{view.hasVisual}}">
<!-- 照片与 face_maps 图层共用 view.photoStyle(人脸裁切窗口),保证叠加层位置一致 -->
<image class="viz-photo" a:if="{{frontPhoto}}" src="{{frontPhoto}}" mode="{{view.fit}}" style="{{view.photoStyle}}" onLoad="onPhotoLoad" />
<view class="viz-dim" a:if="{{view.dark}}"></view>
<image class="viz-layer {{view.blend ? 'viz-blend' : ''}}" a:for="{{view.layers}}" a:for-item="layer" a:key="*this"
src="{{layer}}" mode="scaleToFill" style="opacity:{{view.alpha}};{{view.photoStyle}}" />
<!-- H5 canvas 里按矩形坐标描边的痘/斑标记 -->
<view class="viz-mark" a:for="{{view.marks}}" a:for-item="mark" a:key="id"
style="left:{{mark.left}}%;top:{{mark.top}}%;width:{{mark.width}}%;height:{{mark.height}}%;border-color:{{mark.color}};"></view>
</view>
<view class="viz-missing" a:if="{{!view.hasVisual}}">本次未获取{{view.name}}检测图</view>
</view>
<!-- H5 .contour-sides(轮廓=原图;皱纹=原图压暗 + 侧脸皱纹图层 / 加载态) -->
<view class="contour-sides contour-sides-reversed {{view.dim ? 'wrinkle-sides' : ''}}" a:if="{{sidesShown && (view.dim || view.key === 'contour')}}">
<block a:for="{{sides}}" a:for-item="side" a:key="key">
<view class="contour-side {{side.key === 'right' ? 'right' : ''}}" a:if="{{side.photo}}"
data-card="{{card.key}}" data-view="{{view.key}}" data-side="{{side.key}}" onTap="onZoomPhoto">
<image class="side-img" src="{{side.photo}}" mode="{{side.photoStyle ? 'scaleToFill' : 'aspectFill'}}" style="{{side.photoStyle}}"
data-side="{{side.key}}" data-photo="{{side.photo}}" onLoad="onSidePhotoLoad" />
<block a:if="{{view.dim}}">
<view class="side-dim"></view>
<image class="side-img" a:if="{{side.layer}}" src="{{side.layer}}" mode="{{side.photoStyle ? 'scaleToFill' : 'aspectFill'}}" style="{{side.photoStyle}}" />
<view class="side-loading" a:if="{{side.loading}}"><view>皱纹标注</view><view>加载中…</view></view>
</block>
</view>
</block>
</view>
<view class="wrinkle-layer-note" a:if="{{view.dim && wrinkleNote}}">{{wrinkleNote}}</view>
<!-- H5 .ditem-text > p.ditem-para -->
<view class="ditem-text">
<view class="ditem-para" a:if="{{view.text}}">{{view.text}}</view>
</view>
<!-- H5 #smooth-map-note(仅平滑度面板) -->
<view class="viz-caption" a:if="{{view.caption}}">{{view.caption}}</view>
</view>
</view>
</block>
</view>
</view>
</view>
</block>
<!-- H5 h2.prod-title(两行固定文案) -->
<view class="prod-title">
<view>感受高光时刻</view>
<view>从日常的好状态开始</view>
</view>
<!-- H5 .card.card-care.report-care-products -->
<view class="card report-care-products">
<view class="card-heading">日常护理</view>
<view class="care-list">
<view class="care-item {{ci === careAdvice.length - 1 ? 'last' : ''}}" a:for="{{careAdvice}}" a:for-item="care" a:for-index="ci" a:key="key">{{ci + 1}}、{{care.text}}</view>
<view class="care-item last" a:if="{{!careAdvice.length}}">本次有效数据不足,暂无个性化护理建议。</view>
</view>
<view class="product-section-heading">推荐产品</view>
<view class="care-item product-unavailable" a:if="{{!product}}">本次未获取有效肌龄,暂无法推荐产品,建议重新检测。</view>
<view class="card-product" a:if="{{product}}" onTap="onMore">
<view class="prod-card">
<view class="prod-info">
<view class="prod-card-title">{{product.title}}</view>
<view class="prod-name">{{product.name}}</view>
<image class="prod-badge" src="{{productBadgeUrl}}" mode="widthFix" />
</view>
<view class="prod-scroll"><image class="prod-img" src="{{product.image}}" mode="scaleToFill" /></view>
</view>
</view>
</view>
<!-- H5 p.report-disclaimer(三行固定文案) -->
<view class="report-disclaimer">
<view class="report-disclaimer-line">*您的肌肤状态会随年龄、环境、作息和生活节奏动态变化。</view>
<view class="report-disclaimer-line">*本次检测仅代表当前肌肤状态参考。</view>
<view class="report-disclaimer-line">*仅根据您最近的测肤记录推荐。</view>
</view>
</view>
<!-- H5: tap an inspection image to enlarge; tap again to return. -->
<view class="report-zoom" a:if="{{zoom && !identityChecking && !identityError}}" onTap="onCloseZoom" catchTouchMove="noop">
<view class="report-zoom-enter">
<view class="report-zoom-frame" style="{{zoom.frameStyle}}">
<view class="viz-stage" a:if="{{!zoom.side}}">
<image class="viz-photo" a:if="{{zoom.photo}}" src="{{zoom.photo}}" mode="{{zoom.fit}}" style="{{zoom.photoStyle}}" />
<view class="viz-dim" a:if="{{zoom.dark}}"></view>
<image class="viz-layer {{zoom.blend ? 'viz-blend' : ''}}" a:for="{{zoom.layers}}" a:for-item="layer" a:key="*this" src="{{layer}}" mode="scaleToFill" style="opacity:{{zoom.alpha}};{{zoom.photoStyle}}" />
<view class="viz-mark" a:for="{{zoom.marks}}" a:for-item="mark" a:key="id" style="left:{{mark.left}}%;top:{{mark.top}}%;width:{{mark.width}}%;height:{{mark.height}}%;border-color:{{mark.color}};"></view>
</view>
<block a:else>
<image class="report-zoom-side report-zoom-bitmap" src="{{zoom.bakedPhoto || zoom.photo}}" mode="aspectFit"
data-photo="{{zoom.photo}}" data-generation="{{zoom.generation}}" onLoad="onZoomSideLoad" />
</block>
</view>
</view>
</view>
<canvas id="report-side-zoom-canvas" canvas-id="report-side-zoom-canvas" width="835" height="738" class="report-zoom-canvas" />
</view>