From 652c977cec36e422ebf7a2bff71a249ca8375ff6 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 10 Oct 2026 09:46:17 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E4=BA=8C=E7=89=88=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../1meAI测肤旷视UI问题反馈/第二轮2反馈.md | 2 + h5/README.md | 3 +- h5/css/style.css | 70 +++++++----- h5/index.html | 102 ++++++++++-------- h5/js/app.js | 31 ++++-- 5 files changed, 130 insertions(+), 78 deletions(-) create mode 100644 feedback/1meAI测肤旷视UI问题反馈/第二轮2反馈.md diff --git a/feedback/1meAI测肤旷视UI问题反馈/第二轮2反馈.md b/feedback/1meAI测肤旷视UI问题反馈/第二轮2反馈.md new file mode 100644 index 0000000..112aba3 --- /dev/null +++ b/feedback/1meAI测肤旷视UI问题反馈/第二轮2反馈.md @@ -0,0 +1,2 @@ +1 拍摄的时候,拍摄完前一张图片的时候,需要有一停顿提示用户 拍摄下一张。 这样用户有心理预期。 +2 报告页面的 "紧塑力 活力感 稳定力" 这个部分还是改回原来的布局,保留点击照片放大的功能就行。 \ No newline at end of file diff --git a/h5/README.md b/h5/README.md index 727a6f0..58e6b55 100644 --- a/h5/README.md +++ b/h5/README.md @@ -65,6 +65,7 @@ node server.js # 默认 8080,可用 PORT=xxx 修改 - **预览缩小 15%**:`#cam-video` 按 `scale(.85)` 显示,手机离脸近一些也能把脸装进轮廓;距离阈值随之按 1/0.85 换算(人脸框高/视频高 <0.30 提示「请靠近一点」、>0.68 提示「请远一点」)。 - **动态提示**(一次一条,优先级:无人脸 > 距离 > 居中 > 角度 > 光线):「未检测到人脸」「请靠近一点 / 请远一点」「请将脸部移入取景框」(人脸中心偏离中线 >18% 屏宽)、角度类「请向左转头 / 请向右转头 / 请略微抬头 / 请略微低头」(正脸阈值 |yaw|≤15°、|pitch|≤18°,超出时按超出比例更大的一项给方向;侧脸 yaw 28°–75°、|pitch|≤20°)、光线类「请到光线充足处 / 光线过强,请避开强光」(脸部平均亮度 <65 或 >235)。 - **合格即拍**:上述条件全部合格并连续维持 450ms(滤掉一闪而过的合格帧,防运动模糊)立即白屏补光抓拍,**无倒计时、无手动快门**。 +- **两张之间停顿**:正脸、右脸拍完后中央弹出停顿卡约 2s(「正脸拍摄完成 / 下一张:右脸出镜,请向左转头」),停顿期间不检测,结束后再切到下一步并播下一步引导,让用户对下一张有心理预期。 - **实时检测**:face-api 从本地 `vendor/faceapi/` 加载(`tinyFaceDetector` + `faceLandmark68Net`),进入拍照页开始加载(状态提示「检测引擎加载中…」)。检测循环 ~150ms 一帧,特征点取自原始帧(预览 CSS 镜像不影响),个别前置帧已镜像的机型由侧脸自校准翻转 `sideYawFlip`;连续漏检 ≥3 帧才报「未检测到人脸」。 - **镜像策略**:前置镜头预览镜像(照镜子习惯);后置预览不镜像,侧脸轮廓随之翻转(`.cam-mask.flip`)。**抓帧一律不镜像**,三张照片都是摄像头原始视角。 - **白屏补光**:全屏纯白覆盖层瞬间点亮,~300ms 后抓全分辨率帧(原始视角 + 最长边 1280 JPEG),保持 ~300ms 再淡出,同步 `navigator.vibrate(30)`。 @@ -77,7 +78,7 @@ node server.js # 默认 8080,可用 PORT=xxx 修改 ## 档案页与报告页 - **档案页**:出生年月 / 性别 / 所在地区三个滚轮选择器同一风格(`vendor/mobile-select`,MIT),出生年月自动换算年龄;地区为省–市两级联动,数据为 `js/region-data.js`(由 china-division 2.7.0 `pc.json` 生成,另含港澳台与「海外」)。 -- **报告页**:无返回按钮与页头标题;总分环形图 + 肌肤年龄与「比实际年龄年轻/大 N 岁」;三维度分数 + 进度条(最低分标红并挂「优先关注」);紧塑力/活力感/稳定力各一张卡,卡内子 Tab 切换;点检测图全屏放大,再点或按返回键回到报告。 +- **报告页**:无返回按钮与页头标题;总分环形图 + 肌肤年龄与「比实际年龄年轻/大 N 岁」;三维度分数 + 进度条(最低分标红并挂「优先关注」);维度详情为原布局——一张卡内紧塑力/活力感/稳定力三个 Tab,每个 Tab 两条「竖排标题 + 左图右文」;点检测图全屏放大,再点或按返回键回到报告。 ## 检测流程与评分渲染 diff --git a/h5/css/style.css b/h5/css/style.css index 68e2975..a02bf1d 100644 --- a/h5/css/style.css +++ b/h5/css/style.css @@ -314,6 +314,31 @@ button { font-family: inherit; border: 0; background: none; cursor: pointer; col } .cam-nudge.show { opacity: 1; transform: translateX(-50%); } +/* 两张之间的停顿卡:本张完成 + 下一张预告,停顿期间不检测 */ +.cam-next { + position: absolute; left: 50%; top: 50%; + transform: translate(-50%, -50%) scale(.94); + width: calc(230 * var(--u)); padding: calc(22 * var(--u)) calc(16 * var(--u)) calc(20 * var(--u)); + display: flex; flex-direction: column; align-items: center; + background: rgba(0,0,0,.72); border-radius: calc(12 * var(--u)); + color: #fff; text-align: center; + z-index: 3; opacity: 0; pointer-events: none; + transition: opacity .2s ease, transform .2s ease; +} +.cam-next.show { opacity: 1; transform: translate(-50%, -50%); } +.cam-next-ok { + width: calc(40 * var(--u)); height: calc(40 * var(--u)); border-radius: 50%; + background: #34C759; position: relative; margin-bottom: calc(12 * var(--u)); +} +.cam-next-ok::after { + content: ""; position: absolute; left: 50%; top: 45%; + width: calc(16 * var(--u)); height: calc(8 * var(--u)); + border: solid #fff; border-width: 0 0 calc(3 * var(--u)) calc(3 * var(--u)); + transform: translate(-50%, -50%) rotate(-45deg); +} +.cam-next b { font-size: calc(17 * var(--u)); font-weight: 500; } +.cam-next span { margin-top: calc(8 * var(--u)); font-size: calc(14 * var(--u)); color: rgba(255,255,255,.85); line-height: 1.5; } + /* ═══════════ 08 报告页 ═══════════ */ #s-report { background: var(--bg); } .report-body { padding: 0 calc(18 * var(--u)) calc(28 * var(--u)); } @@ -408,40 +433,35 @@ button { font-family: inherit; border: 0; background: none; cursor: pointer; col .dims-note-l1 b { font-weight: 500; color: var(--ink); text-decoration: underline; text-underline-offset: 3px; } .dims-note-l2 { margin-top: calc(4 * var(--u)); font-size: calc(12 * var(--u)); color: var(--grey); } -/* 维度区块:大标题 + 卡内子 Tab + 大图 + 说明 */ -.sec-title { - font-size: calc(22 * var(--u)); font-weight: 700; color: var(--ink); - text-align: center; letter-spacing: calc(1 * var(--u)); - margin: calc(26 * var(--u)) 0 calc(16 * var(--u)); -} -.card-detail { padding: calc(14 * var(--u)) calc(30 * var(--u)) calc(22 * var(--u)); } -.detail-tabs { display: flex; justify-content: space-between; border-bottom: 1px solid #EFEFEF; } -.dtab { - position: relative; - min-width: calc(80 * var(--u)); - padding: calc(6 * var(--u)) calc(4 * var(--u)) calc(11 * var(--u)); - font-size: calc(14.5 * var(--u)); font-weight: 500; color: var(--ink); -} +/* 维度详情卡(原布局):紧塑力/活力感/稳定力三个 Tab,每个 Tab 两条「竖排标题 + 左图右文」;检测图点击放大 */ +.card-detail { padding: 0 calc(19 * var(--u)) calc(19 * var(--u)); } +.detail-tabs { display: flex; border-bottom: 1px solid #F0F0F0; } +.dtab { flex: 1; padding: calc(13 * var(--u)) 0 0; font-weight: 500; color: var(--ink); } +.dtab-tx { position: relative; display: inline-block; font-size: calc(10.1 * var(--u)); padding: 0 calc(5 * var(--u)) calc(7 * var(--u)); } .dtab.active { font-weight: 700; } -.dtab.active::after { - content: ""; position: absolute; left: 0; right: 0; bottom: calc(-3 * var(--u)); - height: calc(6 * var(--u)); border-radius: calc(3 * var(--u)); background: var(--yellow); +.dtab.active .dtab-tx::after { + content: ""; position: absolute; left: 50%; transform: translateX(-50%); bottom: -1px; + width: calc(78 * var(--u)); height: calc(7 * var(--u)); border-radius: calc(3.5 * var(--u)); background: var(--yellow); } .dpanel { display: none; } -.dpanel.active { display: block; animation: fade .25s ease; padding-top: calc(14 * var(--u)); } +.dpanel.active { display: block; animation: fade .25s ease; padding-top: calc(19 * var(--u)); } @keyframes fade { from { opacity: 0; } to { opacity: 1; } } +.ditem { display: flex; gap: calc(9 * var(--u)); align-items: center; } +.ditem + .ditem { margin-top: calc(18 * var(--u)); padding-top: calc(18 * var(--u)); border-top: 1px solid #F0F0F0; } .ditem-img { - width: calc(213 * var(--u)); height: calc(277 * var(--u)); - margin: 0 auto calc(14 * var(--u)); - object-fit: cover; border-radius: calc(6 * var(--u)); + width: calc(92 * var(--u)); height: calc(96 * var(--u)); + object-fit: cover; border-radius: calc(6 * var(--u)); flex-shrink: 0; background: #F5F5F5; cursor: zoom-in; } .ditem-img[hidden] { display: none; } -.ditem-para { - padding-top: calc(12 * var(--u)); border-top: 1px solid #EFEFEF; - font-size: calc(13 * var(--u)); color: var(--para); line-height: 1.72; - text-align: justify; overflow-wrap: anywhere; +.ditem-text { flex: 1; min-width: 0; } +.ditem-title { + writing-mode: vertical-rl; + letter-spacing: calc(4 * var(--u)); + font-size: calc(11.5 * var(--u)); font-weight: 500; color: var(--ink); + margin-right: calc(3.5 * var(--u)); flex-shrink: 0; } +.ditem-para { font-size: calc(10.1 * var(--u)); font-weight: 400; color: var(--para); line-height: 1.41; overflow-wrap: anywhere; } .vm-notes { font-size: calc(10 * var(--u)); color: var(--grey-3); line-height: 1.7; margin: calc(14 * var(--u)) calc(6 * var(--u)) 0; } .report-disclaimer { diff --git a/h5/index.html b/h5/index.html index 9314227..4e06f27 100644 --- a/h5/index.html +++ b/h5/index.html @@ -118,6 +118,11 @@

检测引擎加载中…

识别不到?请正对镜头,并到光线充足处

+
+ + 正脸拍摄完成 + 准备拍摄下一张 +
@@ -170,52 +175,61 @@

近期优先关注:---

- -

紧塑力

-
- - +
+ + +
-
- 轮廓检测图 -

检测完成后显示分析结果。

-
-
- 皱纹检测图 -

检测完成后显示分析结果。

-
-
- -

活力感

-
-
- - -
-
- -

检测完成后显示分析结果。

-
-
- -

检测完成后显示分析结果。

-
-
- -

稳定力

-
-
- - -
-
- -

检测完成后显示分析结果。

-
-
- -

检测完成后显示分析结果。

+
+
+
+

轮廓

+ 轮廓检测图 +
+

检测完成后显示分析结果。

+
+
+
+

皱纹

+ 皱纹检测图 +
+

检测完成后显示分析结果。

+
+
+
+
+
+

光滑

+ +
+

检测完成后显示分析结果。

+
+
+
+

肤色水润

+ +
+

检测完成后显示分析结果。

+
+
+
+
+
+

敏感

+ +
+

检测完成后显示分析结果。

+
+
+
+

痘痘

+ +
+

检测完成后显示分析结果。

+
+
+
diff --git a/h5/js/app.js b/h5/js/app.js index 2acdc6f..082a86a 100644 --- a/h5/js/app.js +++ b/h5/js/app.js @@ -711,10 +711,14 @@ // 左脸出镜=头向自己的右侧转(target 'left',产物作 left_image)。 // mask 为 index.html 取景轮廓编号(1=左脸出镜 耳在画面左,2=右脸出镜 耳在画面右,均按镜像预览绘制) var CAM_STEPS = [ - { step: '1/3
请正对屏幕', guides: ['正脸居中', '取下眼镜', '光线充足'], target: 'front', mask: 0 }, - { step: '2/3
请右脸出镜', guides: ['右脸居中', '取下眼镜', '光线充足'], target: 'right', mask: 2 }, - { step: '3/3
请左脸出镜', guides: ['左脸居中', '取下眼镜', '光线充足'], target: 'left', mask: 1 } + { step: '1/3
请正对屏幕', guides: ['正脸居中', '取下眼镜', '光线充足'], target: 'front', mask: 0, + done: '正脸拍摄完成' }, + { step: '2/3
请右脸出镜', guides: ['右脸居中', '取下眼镜', '光线充足'], target: 'right', mask: 2, + done: '右脸拍摄完成', preview: '下一张:右脸出镜
请向左转头' }, + { step: '3/3
请左脸出镜', guides: ['左脸居中', '取下眼镜', '光线充足'], target: 'left', mask: 1, + done: '左脸拍摄完成', preview: '下一张:左脸出镜
请向右转头' } ]; + var NEXT_PAUSE_MS = 2000; // 两张之间的停顿:给用户「下一张要拍什么」的心理预期 function photosByView(ph) { // 拍摄顺序 → 送检/报告/历史统一口径 [正脸, 左脸, 右脸] var at = {}; CAM_STEPS.forEach(function (s, i) { at[s.target] = ph[i]; }); @@ -729,6 +733,7 @@ .map(function (g) { return '' + g + ''; }) .join(''); $('#cam-mask').setAttribute('data-step', cfg.mask); // 蒙版按步骤切换轮廓 + $('#cam-next').classList.remove('show'); applyMirror(); resetDetectState(); voice.play(VOICE.step[camStep]); // 步骤引导语音 @@ -739,20 +744,30 @@ // 照片就绪(已通过校验)后推进流程:存图→「拍摄完成」→300ms 过渡→下一步;三步严格按顺序,本步合格才进下一步 function onPhotoCaptured(dataUrl) { - shutterLock = true; // 推进窗口上锁,直到下一步/送检 + shutterLock = true; // 推进窗口上锁(停顿期间不检测、不接受快门),直到下一步/送检 photos[camStep] = dataUrl; voice.play(VOICE.shot, { cut: true }); // 「拍摄完成」:已拍下,本步未播完的引导作废 - var seq = camSeq; + var seq = camSeq, hasNext = camStep < CAM_STEPS.length - 1; + if (hasNext) { + // 停顿卡:本张完成 + 下一张拍什么、往哪转;停顿结束再切到下一步(播下一步引导语音) + setHint(''); + hideNudge(); + clearTimeout(nudgeTimer); + setMask(''); + $('#cam-next-done').textContent = CAM_STEPS[camStep].done; + $('#cam-next-tip').innerHTML = CAM_STEPS[camStep + 1].preview; + $('#cam-next').classList.add('show'); + } setTimeout(function () { if (seq !== camSeq) return; // 期间已退出/重新开始:放弃本次推进 - if (camStep < CAM_STEPS.length - 1) { + if (hasNext) { camStep++; - renderCamStep(); // 内含检测状态机重置 + renderCamStep(); // 内含停顿卡收起与检测状态机重置 shutterLock = false; // 进入下一步即解锁 } else { submitPhotos(seq); // 三张拍完:送检 } - }, 300); + }, hasNext ? NEXT_PAUSE_MS : 300); } // 白屏补光抓拍:全屏纯白瞬间点亮→约300ms 后抓全分辨率帧→保持300ms 再淡出(总 600–900ms)