Files
juzi/h5/index.html
T
xsl 5957ef04fc feat: 接入 Face++ 真实测肤 + 三轮多角色迭代修复
Face++ 集成(高阶版 skinanalyze_advanced):
- h5/server.js:零依赖 Node 后端,静态托管 + /api/skin-analyze 中转,
  api_secret 只存服务端(从 apikey.bash/env 读取,.gitignore 已排除)
- 实时相机:getUserMedia 自拍取景,不可用时降级系统相机;
  相机令牌防授权回调泄漏摄像头;离开拍照页即释放
- 检测流:三连拍仅送检正面照(压至 1280px JPEG),错误码→友好提示
- 结果映射:肌肤年龄=skin_age 真实值;紧塑力/活力感/稳定力由真实
  维度合成;具体描述按检出项动态生成;检测图用用户实拍
- ?mock=1 内置样本供离线/自动化验证;README 补充部署与 HTTPS 说明

三轮迭代修复(QA+美术并行审计→开发统一修复,共 ~28 项):
- 功能:P1 鼠标拖拽轮播(Pointer Events+setPointerCapture)、
  快门/返回竞态(camSeq 令牌)、报告页状态重置、弹窗 ESC/遮罩关闭
- 视觉:还原度 80%→94%,档案页布局/弹窗比例/报告页产品卡等
  结构性偏差修正,字号/间距逐项实测核销
- 工程化:首屏 701KB→386KB(懒加载+preload+清理 212KB 无用资源)、
  favicon/SEO meta/隐私协议占位层/README

Review 修复:server.js 路径穿越前缀绕过(ROOT+sep 校验)、
getUserMedia 迟到回调释放相机(camSeqCam 令牌)
2026-09-22 21:06:33 +08:00

256 lines
11 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, user-scalable=no">
<meta name="format-detection" content="telephone=no">
<meta name="description" content="1'me 在线肌肤测试:拍摄正面与侧面照片,即时获取六维肌肤状态分析与个性化护理建议。">
<meta name="theme-color" content="#101823">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta property="og:title" content="1'me 在线肌肤测试">
<meta property="og:description" content="拍摄正面与侧面照片,即时获取六维肌肤状态分析与个性化护理建议。">
<title>1'me 在线肌肤测试</title>
<link rel="icon" type="image/svg+xml" href="assets/favicon.svg">
<link rel="preload" as="image" href="assets/img/bg-splash.jpg">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<!-- ═══════════ 01 启动页 ═══════════ -->
<section class="screen active" id="s-splash">
<div class="splash-bg"></div>
<p class="splash-slogan">Life in Full<br>为更好的生命表现</p>
<div class="splash-bottom">
<div class="brand-row">
<img src="assets/svg/品牌-1me.svg" alt="1'me" class="brand-logo">
<span class="brand-text">肌肤状态检测</span>
</div>
<button class="btn btn-primary" data-action="open-privacy">开始检测</button>
</div>
</section>
<!-- ═══════════ 03 档案填写 ═══════════ -->
<section class="screen" id="s-profile">
<div class="profile-bg"></div>
<header class="nav">
<button class="nav-back" data-action="back-splash" aria-label="返回"><i class="chev left"></i></button>
<span class="nav-title">1'me在线肌肤测试</span>
</header>
<div class="profile-body">
<h1 class="page-title">您的肌肤状态</h1>
<div class="form-row two">
<div class="field">
<label class="field-label">您的年龄</label>
<input id="f-age" class="field-input" type="text" inputmode="numeric" maxlength="2" placeholder="请输入">
</div>
<div class="field">
<label class="field-label">您的性别</label>
<div class="field-select-wrap">
<select id="f-gender" class="field-input field-select">
<option value="" selected disabled>请选择</option>
<option>女</option><option>男</option>
</select>
<i class="chev down"></i>
</div>
</div>
</div>
<div class="field">
<label class="field-label">您的所在地区</label>
<div class="field-select-wrap">
<select id="f-region" class="field-input field-select">
<option value="" selected disabled>请选择</option>
</select>
<i class="chev down"></i>
</div>
</div>
<div class="field">
<label class="field-label">您的日常肤质</label>
<div class="skin-card">
<div class="skin-axis">
<span class="axis-item"><i class="chip" style="background:#EAE6E1"></i>偏干</span>
<span class="axis-item"><i class="chip" style="background:#DBF6D6"></i>水油平衡</span>
<span class="axis-item"><i class="chip" style="background:#F5F078"></i>偏油</span>
</div>
<div class="skin-carousel" id="skin-carousel">
<div class="skin-track" id="skin-track"></div>
</div>
<div class="skin-dots" id="skin-dots"></div>
</div>
</div>
<button class="btn btn-primary btn-submit" data-action="submit-profile">提交</button>
</div>
</section>
<!-- ═══════════ 05-07 拍照页 ═══════════ -->
<section class="screen" id="s-cam" data-step="0">
<div class="cam-bg" id="cam-bg"></div>
<header class="nav nav-dark">
<button class="nav-back" data-action="cam-back" aria-label="返回"><i class="chev left"></i></button>
<span class="nav-title">1'me在线肌肤测试</span>
</header>
<p class="cam-step" id="cam-step">1/3<br>请单人正脸出镜</p>
<div class="cam-guide" id="cam-guide"></div>
<video id="cam-video" autoplay playsinline muted></video>
<input type="file" id="cam-file" accept="image/*" capture="user" hidden>
<div class="cam-controls">
<button class="cam-side" data-action="album" aria-label="相册">
<img src="assets/svg/图标-相册.svg" alt="相册">
</button>
<button class="cam-shutter" data-action="shutter" aria-label="拍照">
<img src="assets/svg/拍照-快门.svg" alt="快门">
</button>
<button class="cam-side cam-flip" data-action="flip" aria-label="切换">
<img src="assets/svg/图标-重拍.svg" alt="切换">
</button>
</div>
<div class="cam-flash" id="cam-flash"></div>
</section>
<!-- ═══════════ 08 报告页 ═══════════ -->
<section class="screen" id="s-report">
<header class="nav">
<button class="nav-back" data-action="back-profile" aria-label="返回"><i class="chev left"></i></button>
<span class="nav-title">1'me在线肌肤测试</span>
</header>
<div class="report-body">
<h1 class="report-title">您的肌肤状态表现</h1>
<div class="card card-stats">
<div class="stat">
<span class="stat-label">综合评分</span>
<span class="stat-value" id="stat-score">--分</span>
</div>
<div class="stat">
<span class="stat-label">肌肤年龄</span>
<span class="stat-value" id="stat-age">--岁</span>
</div>
</div>
<p class="dims-intro">我们从6个维度观察了你的肌肤,当下优先关注:紧致、光泽、纹路、耐受、细腻、水润</p>
<p class="dims-disclaimer">*状态是动态流动的,和作息、压力、季节都有关系,仅代表此刻的状态参考。</p>
<div class="card card-dims">
<div class="dims-row">
<div class="dim"><span class="dim-name">紧塑力</span><span class="dim-score" id="dim-firm">-.-</span></div>
<div class="dim"><span class="dim-name">活力感</span><span class="dim-score" id="dim-vita">-.-</span></div>
<div class="dim"><span class="dim-name">稳定力</span><span class="dim-score" id="dim-stab">-.-</span></div>
</div>
<p class="dims-note" id="dims-note">近期优先关注:<br>---</p>
</div>
<div class="card card-detail">
<div class="detail-tabs" id="detail-tabs">
<button class="dtab active" data-tab="0">紧塑力</button>
<button class="dtab" data-tab="1">活力感</button>
<button class="dtab" data-tab="2">稳定力</button>
</div>
<div class="detail-panels">
<div class="dpanel active" data-panel="0">
<div class="ditem">
<h3 class="ditem-title">紧致</h3>
<img id="ditem-img1" src="assets/img/det-1.jpg" loading="lazy" class="ditem-img" alt="紧致检测图">
<div class="ditem-text">
<p class="ditem-para" id="ditem-para1">检测完成后显示分析结果。</p>
</div>
</div>
<div class="ditem">
<h3 class="ditem-title">纹路</h3>
<img id="ditem-img2" src="assets/img/det-2.jpg" loading="lazy" class="ditem-img" alt="纹路检测图">
<div class="ditem-text">
<p class="ditem-para" id="ditem-para2">检测完成后显示分析结果。</p>
</div>
</div>
</div>
<div class="dpanel" data-panel="1">
<div class="dempty">活力感维度内容以实际检测报告为准</div>
</div>
<div class="dpanel" data-panel="2">
<div class="dempty">稳定力维度内容以实际检测报告为准</div>
</div>
</div>
</div>
<p class="report-disclaimer">*您的肌肤状态会随年龄、环境、作息和生活节奏动态变化。<br>*本次检测仅代表当前肌肤状态参考。</p>
<div class="card card-care">
<h2 class="card-heading">护理建议</h2>
<p class="care-item">1、面部支撑力明显下降,软组织有下移趋势。护肤时请避免用力向下拉扯皮肤,涂抹护肤品时配合由下向上的提拉手法,重点照顾下颌线与苹果肌位置。</p>
<p class="care-item">2、肤色不均,局部有色素沉积。建议严格防晒,避免紫外线加重色沉;护肤上可尝试温和的美白精华,加速代谢。</p>
<p class="care-summary">好状态,是内外同调的长期节奏。</p>
</div>
<div class="card card-product">
<h2 class="prod-title">感受高光时刻<br>从日常的好状态开始</h2>
<div class="prod-card">
<div class="prod-info">
<span class="prod-badge">CORE Ⅱ</span>
<h3 class="prod-name">以我自在有势挺括双仓精华液</h3>
<p class="prod-sub">参透皮下根源 28天校准皮肤状态</p>
</div>
<div class="prod-scroll" id="prod-scroll">
<img src="assets/img/prod-1.jpg" loading="lazy" alt="以我自在有势挺括双仓精华液">
</div>
</div>
</div>
<button class="btn btn-primary btn-more" data-action="more">了解更多</button>
</div>
</section>
<!-- ═══════════ 弹窗:隐私授权 ═══════════ -->
<div class="overlay" id="p-privacy">
<div class="popup">
<button class="popup-close" data-action="close-privacy" aria-label="关闭">
<img src="assets/svg/图标-关闭.svg" alt="关闭">
</button>
<h2 class="popup-title">欢迎体验1'me<br>肌肤状态评估服务!</h2>
<p class="popup-body">我们将采集您的面部影像,为您生成专属肌肤分析与状态管理方案。所有数据严格保密,仅用于本次检测分析。</p>
<label class="privacy-row" id="privacy-row">
<span class="checkbox" id="privacy-check"></span>
<span class="privacy-text">我已阅读并同意<a class="privacy-link" id="privacy-policy-link">相关隐私协议</a></span>
</label>
<button class="btn btn-primary popup-btn" data-action="agree-continue">继续</button>
</div>
</div>
<!-- ═══════════ 弹窗:拍照引导 ═══════════ -->
<div class="overlay" id="p-photoguide">
<div class="popup">
<button class="popup-close" data-action="close-photoguide" aria-label="关闭">
<img src="assets/svg/图标-关闭.svg" alt="关闭">
</button>
<h2 class="popup-title popup-title-center">请拍摄正面及<br>左右侧面照片</h2>
<button class="btn btn-primary popup-btn" data-action="start-camera">开始</button>
</div>
</div>
<!-- ═══════════ 弹窗:隐私协议(占位) ═══════════ -->
<div class="overlay" id="p-policy">
<div class="popup popup-policy">
<button class="popup-close" data-action="close-policy" aria-label="关闭">
<img src="assets/svg/图标-关闭.svg" alt="关闭">
</button>
<h2 class="popup-title popup-title-policy">1'me 肌肤状态评估隐私协议</h2>
<p class="popup-body">(协议全文待法务提供后接入,当前为占位)</p>
</div>
</div>
<!-- ═══════════ 分析中过渡 ═══════════ -->
<div class="overlay overlay-dark" id="p-analyzing">
<div class="analyzing">
<div class="spinner"></div>
<p>正在生成您的肌肤报告…</p>
</div>
</div>
<!-- ═══════════ Toast ═══════════ -->
<div class="toast" id="toast"></div>
<script src="js/app.js"></script>
</body>
</html>