feat: 完善淘宝小程序拍照、报告与登录流程

接入本地实时识别和自动三连拍,调整报告裁切、商品跳转、分享标题及居中页眉;完善游客会话、后台渠道隔离、部署脚本与回归测试。
This commit is contained in:
xsl
2026-11-04 15:07:51 +08:00
parent 381da60ae4
commit 774376fa16
147 changed files with 17420 additions and 597 deletions
+63 -24
View File
@@ -1,23 +1,41 @@
<!-- ═════ 05-07 拍照页 ═════
两种形态,由 config.nativeCamera 决定:
① cameraEnabled=true → 真机取景:<camera> 铺满 + 椭圆镂空蒙版 + 快门直接 takePhoto(对齐 H5 #s-cam)
② cameraEnabled=false → 系统相机:静态版面 + 快门调 my.chooseImage
关键:<camera> 不能嵌 <cover-view>(微信专有组件,淘宝上会导致整页崩溃),
所以相机是兄弟节点,覆盖层用普通 view + box-shadow 镂空。 -->
<view class="cam">
<import src="../../components/brand-header.axml" />
<template is="brand-header" data="{{brandHeader: brandHeader}}" />
<!-- H5 三步取景。普通前置帧在本地识别人脸并自动抓拍,AR 为显式可选分支。
所有覆盖层为兄弟节点。 -->
<view class="cam" style="top:{{brandHeader.height}}px;">
<view class="cam-verifying" a:if="{{identityPending}}">
<view>{{identityError || '正在确认登录状态…'}}</view>
<view a:if="{{identityError}}" onTap="onRetryIdentity">重试</view>
</view>
<!-- ①真机取景:相机铺满,不加任何子节点 -->
<camera a:if="{{cameraEnabled}}" id="skin-camera" class="cam-device"
device-position="{{devicePosition}}" flash="off"
<ar-camera a:if="{{cameraEnabled && useAR}}" id="skin-ar-camera-{{cameraSession}}" class="cam-device" data-camera-session="{{cameraSession}}"
devicePosition="{{arDevicePosition}}" mode="faceDetection2D" useCapturedImage="{{true}}"
onInit="onARInit" onARFrame="onARFrame" onError="onCameraError" onStop="onCameraStop" />
<camera a:if="{{cameraEnabled && !useAR}}" id="{{nativeCameraId}}" class="cam-device" data-camera-session="{{cameraSession}}"
mode="normal" device-position="{{devicePosition}}" frame-size="{{nativeFrameSize}}" flash="off"
onError="onCameraError" onStop="onCameraStop" />
<!-- ②系统相机兜底:H5 相机静态态(白底 + 85% 黑蒙版 ≈ #262626) -->
<view class="cam-bg" a:if="{{!cameraEnabled}}" />
<!-- 取景蒙版:H5 用 SVG 镂空;这里用带巨大 box-shadow 的椭圆开窗,视觉等效 -->
<!-- PNGs are rasterized from the exact H5 SVG paths, including feature lines. -->
<view class="cam-mask">
<view class="cam-hole mask-{{maskStep}}" />
<view class="cam-mask-edge edge-top" style="height:{{maskInsetY}}px" />
<view class="cam-mask-edge edge-bottom" style="height:{{maskInsetY}}px" />
<view class="cam-mask-edge edge-left" style="width:{{maskInsetX}}px" />
<view class="cam-mask-edge edge-right" style="width:{{maskInsetX}}px" />
<image class="cam-mask-image {{cameraEnabled && devicePosition === 'back' && maskStep ? 'mirror' : ''}}" style="{{maskStageStyle}}" src="../../assets/camera/mask-{{maskName}}{{cameraEnabled ? '-live' : ''}}.png" mode="scaleToFill" />
<view a:if="{{cameraEnabled && autoCapture && !doneTip && !analyzing}}" class="cam-live-scan scan-{{maskName}} {{devicePosition === 'back' && maskStep ? 'mirror' : ''}}" style="{{maskStageStyle}}"><view class="cam-live-band" /></view>
</view>
<view class="cam-next" a:if="{{doneTip && !analyzing}}">
<view class="cam-next-ok">✓</view>
<view class="cam-next-done">{{doneTip}}</view>
<view class="cam-next-tip">{{nextTip}}</view>
</view>
<view class="cam-countdown" a:if="{{countdown}}">{{countdown}}</view>
<view class="cam-fill" a:if="{{fillLight}}" />
<view class="cam-step">
<view class="cam-step-no">{{stepText}}</view>
<view class="cam-step-tip">{{stepTip}}</view>
@@ -40,36 +58,57 @@
</view>
<!-- 分析中 -->
<view class="cam-analyzing" a:if="{{analyzing}}">
<view class="cam-analyzing-text">{{debugMode ? '正在验证本地图片压缩…' : '正在生成您的肌肤报告…'}}</view>
<view class="cam-cancel" onTap="onCancel">{{debugMode ? '退出验收' : '返回,稍后查看历史报告'}}</view>
<view class="cam-analyzing" a:if="{{analyzing || analysisError}}">
<view class="scan-stage" style="{{scanStageStyle}}" a:if="{{!debugMode && !analysisError}}">
<image class="scan-artwork" src="../../assets/camera/scan-base.png" mode="scaleToFill" onError="onScanError" />
<view class="scan-face"><view class="scan-beam" /></view>
<view class="scan-flip-icon"><image src="../../assets/camera/icon-switch-camera.png" mode="aspectFit" /></view>
</view>
<view class="cam-analyzing-text" a:if="{{debugMode || analysisError || scanError}}">{{analysisError || (debugMode ? '正在验证本地图片压缩…' : '检测中…')}}</view>
<view class="analysis-stage" a:if="{{!analysisError}}">{{analysisStage}}</view>
<view class="analysis-retry" a:if="{{analysisError}}" onTap="onRetryAnalysis">重试查看本次检测</view>
<view class="analysis-retake" a:if="{{analysisError}}" onTap="onRestart">重新拍摄</view>
<view class="cam-cancel" onTap="onCancel">{{debugMode ? '退出验收' : '取消'}}</view>
</view>
<!-- 底部控制条:相册 / 快门 / 翻转 -->
<view class="cam-controls" a:if="{{!previewUrl && !analyzing}}">
<view class="cam-side" onTap="onAlbum">相册</view>
<view class="cam-shutter" onTap="onShutter">
<view class="cam-shutter-dot" />
<view class="cam-controls" a:if="{{!previewUrl && !analyzing && !analysisError && !doneTip}}">
<view class="cam-side" onTap="onAlbum"><image src="../../assets/camera/icon-album.png" mode="aspectFit" /></view>
<view class="cam-shutter {{autoCapture && cameraEnabled ? 'cam-shutter-auto' : ''}}" onTap="onShutter">
<image src="../../assets/camera/icon-shutter.png" mode="aspectFit" />
</view>
<view class="cam-side" onTap="{{cameraEnabled ? 'onFlip' : 'onOpenSettings'}}">{{cameraEnabled ? '翻转' : '授权设置'}}</view>
<view class="cam-side cam-side-switch" onTap="onFlip"><image src="../../assets/camera/icon-switch-camera.png" mode="aspectFit" /><text class="cam-switch-label">切换镜头</text></view>
</view>
<!-- 提示/错误文案 -->
<view class="cam-hint" a:if="{{permissionMessage && !previewUrl && !analyzing}}">{{permissionMessage}}</view>
<view class="cam-live-hint {{liveGood ? 'good' : ''}}" a:if="{{cameraEnabled && autoCapture && !doneTip && !analyzing}}">{{liveHint}}</view>
<view class="cam-enable" a:if="{{cameraSupported && !cameraEnabled && !identityPending && !previewUrl && !doneTip && !debugComplete && !analyzing && !analysisError && (camError || permissionMessage)}}" onTap="onEnableCamera">重新开启相机</view>
<view class="cam-settings" a:if="{{permissionMessage && !analyzing}}" onTap="onOpenSettings">授权设置</view>
<!-- Must remain mounted and laid out; display:none/hidden causes empty exports on phones. -->
<canvas id="compress-canvas" canvas-id="compress-canvas" width="{{compressWidth}}" height="{{compressHeight}}" class="compress-canvas" style="width:{{compressWidth}}px;height:{{compressHeight}}px" />
<!-- 开发版:权限诊断 -->
<view class="cam-diag-entry" a:if="{{showDiagnose}}" onTap="onDiagnose">权限诊断</view>
<view class="cam-diag" a:if="{{diagText}}" catchTap="noop">
<view class="cam-probe-toolbar" a:if="{{localFaceProbe}}" style="top:{{probeToolbarTop}}px;">
<view class="cam-probe-version">自动三连拍验收 · {{captureProbeVersion}}</view>
<view class="cam-probe-actions">
<button size="mini" onTap="onCopyCaptureDiagnostics">复制识别诊断</button>
<button size="mini" onTap="onCancel">退出验收</button>
</view>
</view>
<view class="cam-diag-entry" a:if="{{showDiagnose && !localFaceProbe}}" onTap="onDiagnose">权限诊断</view>
<view class="cam-diag" a:if="{{diagText}}" style="{{localFaceProbe ? 'top:' + (probeToolbarTop + 96) + 'px;' : ''}}" catchTap="noop">
<scroll-view class="cam-diag-scroll" scroll-y>
<text class="cam-diag-text">{{diagText}}</text>
<text class="cam-diag-text" selectable="{{true}}">{{diagText}}</text>
</scroll-view>
<view class="cam-diag-close" onTap="onCloseDiagnose">关闭</view>
</view>
<!-- 调试模式结果页 -->
<view class="cam-debug" a:if="{{debugComplete}}">
<view class="cam-debug" a:if="{{debugComplete}}" style="{{localFaceProbe ? 'padding-top:' + (probeToolbarTop + 96) + 'px;' : ''}}">
<view class="cam-debug-title">三步拍摄与 JPEG 压缩已完成</view>
<view class="cam-debug-note">请核对实际照片方向是否为正脸、右脸、左脸;本页不判断姿态是否合格。</view>
<view class="cam-debug-note">{{localFaceProbe ? '三张照片已通过实时识别自动拍摄;请核对正脸、右脸、左脸顺序和实际方向。照片只在本页临时预览,不上传、不生成报告。' : '请核对实际照片方向是否为正脸、右脸、左脸;本页不判断姿态是否合格。'}}</view>
<view class="cam-debug-item" a:for="{{debugPhotos}}" a:key="key">
<image class="cam-debug-img" src="{{item.photo}}" mode="aspectFit" />
<view class="cam-debug-meta">{{item.title}} · JPEG {{item.width}}×{{item.height}} · 约{{item.kilobytes}}KB</view>