feat: 真机反馈 11 项(下拉层级/侧脸蒙版/报告改版/护理建议 V2.3/水分图)

1. 城市下拉浮层 z-index 提至 50,不再被肤质轮播圆点压盖
2. 倒计时音频已更新(用户重生成,解码验证 2.62s)
3. 侧脸步蒙版鼻向修正:2/3 右脸鼻朝右、3/3 左脸鼻朝左(原与设计稿 06/07 相反)
4. 无进展提示上移至 bottom:24%(引导 chips 上方,不再压快门)
5. 相册选择器「拍照」项为 iOS/安卓系统行为,web 无法移除(详见回复)
6. 报告页顶栏移除,返回/历史改悬浮
7. 肌龄小字按产品要求不再展示(钳制留痕仍随数据返回)
8. 关注行对齐设计稿:前缀灰 + 维度名深色 500
9. 三维度排版对齐设计稿:去掉档位徽章,最低分标红
10. 肤色水润图改用 water_area(接口水分图),REPORT_MAPS 与 mock fixture 同步更新
11. 报告「综合分析」「生活方式建议」通栏移除,新增「护理建议」卡(V2.3 §8:肤质定制/最差2分类/精华/生活方式 五段,§8.5.1 无内部标注;skin-score 实现 8.6/8.7 全量文案库,回归新增 §8.8 两组样例逐字断言 86/86 绿)
e2e 全量绿(含真实 API:水分图/红区合成图挂载、护理建议五段)
This commit is contained in:
Ubuntu
2026-09-27 11:15:54 +08:00
parent ca76128ac0
commit 6c634e3a66
12 changed files with 164 additions and 53 deletions
+1 -1
View File
@@ -17,7 +17,7 @@ REF = os.path.join(ROOT, '..', '..', '..', 'reference', 'facepp-skinanalyze', 'e
TARGET_W = 1280
# 与服务端 REPORT_MAPS 白名单一致(h5/server.js)
MAP_KEYS = ['red_area', 'brown_area', 'texture_enhanced_lines', 'texture_enhanced_pores', 'texture_enhanced_blackheads']
MAP_KEYS = ['red_area', 'brown_area', 'water_area', 'texture_enhanced_lines', 'texture_enhanced_pores', 'texture_enhanced_blackheads']
def to_data_url(img, fmt):
File diff suppressed because one or more lines are too long
+28
View File
@@ -658,3 +658,31 @@ button { font-family: inherit; border: 0; background: none; cursor: pointer; }
#p-policy .policy-body { padding-top: 52px; }
/* P1-2 姿态提示气泡压住底部引导文字:改到步骤文案下方、取景框上方 */
.cam-hint { bottom: auto; top: 26%; }
/* ═══════════ 第8轮:真机反馈 11 项 ═══════════ */
/* #1 城市下拉浮层层级高于肤质轮播圆点 */
.rs { z-index: 50; }
.rs-list { z-index: 50; }
/* #4 无进展提示再上移(取景/拍摄区下方,引导 chips 上方) */
.cam-nudge { bottom: 24%; }
/* #6 报告页顶栏移除,返回/历史改悬浮 */
#s-report { position: relative; }
.report-float-back {
position: absolute; top: 12px; left: 12px; z-index: 21;
background: #fff; box-shadow: 0 1px 6px rgba(0,0,0,.10);
}
.report-float-history {
position: absolute; top: 12px; right: 12px; z-index: 21;
font-size: 12px; color: var(--grey-2); padding: 7px 10px;
background: #fff; border-radius: 15px; box-shadow: 0 1px 6px rgba(0,0,0,.10);
}
#s-report .report-body { padding-top: 44px; }
/* #8 关注行:前缀灰 + 维度名深色 500 */
.dims-note-l1 b { font-weight: 500; color: var(--ink); }
/* #9 维度分:最低分标红(替代原档位徽章) */
.dim-score.dim-bad { color: var(--bad); }
/* #11 护理建议(设计稿样式:标题 + 编号条目) */
#care-list .care-item { margin-bottom: 10px; }
#care-list .care-item b { font-weight: 600; color: var(--ink); }
/* 护理建议/精华推荐卡标题对齐设计稿(≈16px) */
.card-care .card-heading, .card-essence .card-heading { font-size: 16px; }
+13 -20
View File
@@ -101,16 +101,16 @@
<rect x="0" y="0" width="375" height="812" fill="#fff"/>
<g fill="#000">
<path data-shape="0" d="M187.5 240 C252 240 300 285 302 365 C313 367 318 381 315 397 C312 412 305 418 299 420 C294 488 246 578 187.5 586 C129 578 81 488 76 420 C70 418 63 412 60 397 C57 381 62 367 73 365 C75 285 123 240 187.5 240 Z"/>
<path data-shape="1" transform="translate(375 0) scale(-1 1)" d="M170 245 C230 240 258 270 262 320 C263 330 262 338 259 345 C270 360 282 380 284 398 C285 405 282 411 274 413 C267 415 262 417 261 421 C267 425 268 431 263 435 C267 439 267 445 262 448 C264 454 263 460 265 466 C266 476 260 483 248 486 C220 505 185 530 158 548 C140 560 122 558 112 538 C95 500 90 430 94 370 C98 305 120 250 170 245 Z"/>
<path data-shape="2" d="M170 245 C230 240 258 270 262 320 C263 330 262 338 259 345 C270 360 282 380 284 398 C285 405 282 411 274 413 C267 415 262 417 261 421 C267 425 268 431 263 435 C267 439 267 445 262 448 C264 454 263 460 265 466 C266 476 260 483 248 486 C220 505 185 530 158 548 C140 560 122 558 112 538 C95 500 90 430 94 370 C98 305 120 250 170 245 Z"/>
<path data-shape="1" d="M170 245 C230 240 258 270 262 320 C263 330 262 338 259 345 C270 360 282 380 284 398 C285 405 282 411 274 413 C267 415 262 417 261 421 C267 425 268 431 263 435 C267 439 267 445 262 448 C264 454 263 460 265 466 C266 476 260 483 248 486 C220 505 185 530 158 548 C140 560 122 558 112 538 C95 500 90 430 94 370 C98 305 120 250 170 245 Z"/>
<path data-shape="2" transform="translate(375 0) scale(-1 1)" d="M170 245 C230 240 258 270 262 320 C263 330 262 338 259 345 C270 360 282 380 284 398 C285 405 282 411 274 413 C267 415 262 417 261 421 C267 425 268 431 263 435 C267 439 267 445 262 448 C264 454 263 460 265 466 C266 476 260 483 248 486 C220 505 185 530 158 548 C140 560 122 558 112 538 C95 500 90 430 94 370 C98 305 120 250 170 245 Z"/>
</g>
</mask>
</defs>
<rect class="cam-dim-rect" x="0" y="0" width="375" height="812" mask="url(#cam-cut)"/>
<g class="cam-line">
<path data-shape="0" d="M187.5 240 C252 240 300 285 302 365 C313 367 318 381 315 397 C312 412 305 418 299 420 C294 488 246 578 187.5 586 C129 578 81 488 76 420 C70 418 63 412 60 397 C57 381 62 367 73 365 C75 285 123 240 187.5 240 Z"/>
<path data-shape="1" transform="translate(375 0) scale(-1 1)" d="M170 245 C230 240 258 270 262 320 C263 330 262 338 259 345 C270 360 282 380 284 398 C285 405 282 411 274 413 C267 415 262 417 261 421 C267 425 268 431 263 435 C267 439 267 445 262 448 C264 454 263 460 265 466 C266 476 260 483 248 486 C220 505 185 530 158 548 C140 560 122 558 112 538 C95 500 90 430 94 370 C98 305 120 250 170 245 Z"/>
<path data-shape="2" d="M170 245 C230 240 258 270 262 320 C263 330 262 338 259 345 C270 360 282 380 284 398 C285 405 282 411 274 413 C267 415 262 417 261 421 C267 425 268 431 263 435 C267 439 267 445 262 448 C264 454 263 460 265 466 C266 476 260 483 248 486 C220 505 185 530 158 548 C140 560 122 558 112 538 C95 500 90 430 94 370 C98 305 120 250 170 245 Z"/>
<path data-shape="1" d="M170 245 C230 240 258 270 262 320 C263 330 262 338 259 345 C270 360 282 380 284 398 C285 405 282 411 274 413 C267 415 262 417 261 421 C267 425 268 431 263 435 C267 439 267 445 262 448 C264 454 263 460 265 466 C266 476 260 483 248 486 C220 505 185 530 158 548 C140 560 122 558 112 538 C95 500 90 430 94 370 C98 305 120 250 170 245 Z"/>
<path data-shape="2" transform="translate(375 0) scale(-1 1)" d="M170 245 C230 240 258 270 262 320 C263 330 262 338 259 345 C270 360 282 380 284 398 C285 405 282 411 274 413 C267 415 262 417 261 421 C267 425 268 431 263 435 C267 439 267 445 262 448 C264 454 263 460 265 466 C266 476 260 483 248 486 C220 505 185 530 158 548 C140 560 122 558 112 538 C95 500 90 430 94 370 C98 305 120 250 170 245 Z"/>
</g>
</svg>
<p class="cam-status" id="cam-status">检测引擎加载中…</p>
@@ -137,11 +137,8 @@
<!-- ═══════════ 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>
<button class="nav-history" data-action="history">历史</button>
</header>
<button class="nav-back report-float-back" data-action="back-profile" aria-label="返回"><i class="chev left"></i></button>
<button class="nav-history report-float-history" data-action="history">历史</button>
<div class="report-body">
<h1 class="report-title">您的肌肤状态表现</h1>
@@ -159,9 +156,9 @@
<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><span class="dim-lv" id="dim-firm-lv"></span></div>
<div class="dim"><span class="dim-name">活力感</span><span class="dim-score" id="dim-vita">-.-</span><span class="dim-lv" id="dim-vita-lv"></span></div>
<div class="dim"><span class="dim-name">稳定力</span><span class="dim-score" id="dim-stab">-.-</span><span class="dim-lv" id="dim-stab-lv"></span></div>
<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>
@@ -228,15 +225,11 @@
<p class="report-disclaimer">*您的肌肤状态会随年龄、环境、作息和生活节奏动态变化。<br>*本次检测仅代表当前肌肤状态参考。</p>
<div class="card card-summary">
<h2 class="card-heading">综合分析</h2>
<p class="care-item" id="vm-summary">检测完成后显示分析结果。</p>
</div>
<div class="card card-care">
<h2 class="card-heading">生活方式建议</h2>
<p class="care-item" id="vm-lifestyle">--</p>
<p class="care-summary">好状态,是内外同调的长期节奏。</p>
<h2 class="card-heading">护理建议</h2>
<div id="care-list">
<p class="care-item">检测完成后显示分析结果。</p>
</div>
</div>
<div class="card card-essence">
+29 -30
View File
@@ -701,17 +701,11 @@
.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
function setDim(scoreSel, lvSel, dim) {
var el = $(scoreSel), lv = $(lvSel);
if (dim.S == null) {
el.textContent = '-.-';
lv.textContent = '未检出';
lv.className = 'dim-lv';
return;
}
el.textContent = dim.S.toFixed(1);
lv.textContent = dim.level;
lv.className = 'dim-lv ' + (LV_CLASS[dim.level] || '');
function setDim(scoreSel, dim, isWorst) {
var el = $(scoreSel);
// 设计稿:最低分标红,其余深色;无档位徽章
el.textContent = dim.S == null ? '-.-' : dim.S.toFixed(1);
el.classList.toggle('dim-bad', !!isWorst && dim.S != null);
}
function setCat(key, cat) {
@@ -731,7 +725,7 @@
{ key: 'mole', color: '#282828' }, // 痣
{ key: 'acne', color: '#D30C0C' } // 痤疮
] },
tone: { img: '#viz-tone', blendMap: 'brown_area' }, // 肤色:正脸×色沉图正片叠底(直挂是悬浮面具感,合成后色沉落在脸上)
tone: { img: '#viz-tone', blendMap: 'water_area' }, // 肤色水润:正脸×水分图正片叠底(water_area,接口返回)
sens: { img: '#viz-sens', blendMap: 'red_area' }, // 敏感:正脸×红区图正片叠底(直挂白底过淡不可读)
acne: { img: '#viz-acne', photo: true, marks: [ // 痘痘:正脸+闭口粉刺/痤疮标记
{ key: 'closed_comedones', color: '#E8A13D' }, // 闭口粉刺
@@ -902,28 +896,27 @@
}
$('#stat-score').textContent = total != null ? total + '分' : '--分';
$('#stat-age').textContent = vm.skinAgeDisplay != null ? vm.skinAgeDisplay + '岁' : '--岁';
// 肌龄小字:常显「与实际年龄相差X岁」,触发钳制时追加留痕(契约格式「触发(原X→Y)」不变)
var ageNote = '';
if (vm.skinAgeDisplay != null && vm.realAge != null) {
var ageDiff = Math.abs(vm.skinAgeDisplay - vm.realAge);
ageNote = ageDiff === 0 ? '与实际年龄相符' : '与实际年龄相差' + ageDiff + '岁';
}
if (vm.ageClampNote) ageNote += (ageNote ? ' · ' : '') + vm.ageClampNote;
$('#stat-age-note').textContent = ageNote;
$('#stat-age-note').textContent = ''; // 肌龄小字按产品要求不展示(钳制留痕 vm.ageClampNote 仍随数据返回)
// 三维度:S 值(1 位小数) + 档位(良好绿/改善琥珀/预警红)
setDim('#dim-firm', '#dim-firm-lv', vm.dims.firm);
setDim('#dim-vita', '#dim-vita-lv', vm.dims.vita);
setDim('#dim-stab', '#dim-stab-lv', vm.dims.stab);
// 关注行(设计稿两行:灰小字「近期优先关注:X」+ 深色维度口号)
// 三维度:S 值(1 位小数),最低分标红(设计稿无档位徽章)
var dimPs = { firm: vm.dims.firm.P, vita: vm.dims.vita.P, stab: vm.dims.stab.P };
var worstDimKey = Object.keys(dimPs).reduce(function (a, b) {
if (dimPs[a] == null) return b;
if (dimPs[b] == null) return a;
return dimPs[b] < dimPs[a] ? b : a;
});
setDim('#dim-firm', vm.dims.firm, worstDimKey === 'firm');
setDim('#dim-vita', vm.dims.vita, worstDimKey === 'vita');
setDim('#dim-stab', vm.dims.stab, worstDimKey === 'stab');
// 关注行(设计稿两行:「近期优先关注:」灰 + 维度名深色,下行为深色口号)
var DIM_SLOGAN = {
'紧塑力': '紧塑提拉力,轮廓上扬不松垮',
'活力感': '活力透亮感,水润澎弹有光泽',
'稳定力': '强韧稳态力,锁水保湿抵御刺激' // 设计稿原文
};
$('#dims-note').innerHTML = vm.focus.name
? '<span class="dims-note-l1">近期优先关注:' + esc(vm.focus.name) + '</span><br><span class="dims-note-l2">' + esc(DIM_SLOGAN[vm.focus.name] || '') + '</span>'
: '<span class="dims-note-l1">近期优先关注:---</span>';
? '<span class="dims-note-l1">近期优先关注:<b>' + esc(vm.focus.name) + '</b></span><br><span class="dims-note-l2">' + esc(DIM_SLOGAN[vm.focus.name] || '') + '</span>'
: '<span class="dims-note-l1">近期优先关注:<b>---</b></span>';
// 三个 Tab 面板:各所辖两个分类(S + 档位徽章 + 话术正文)
var keys = ['contour', 'wrinkles', 'smooth', 'tone', 'sens', 'acne'];
@@ -943,9 +936,15 @@
notesEl.style.display = 'none';
}
// 综合文案 / 生活方式 / 精华推荐
$('#vm-summary').textContent = vm.summary;
$('#vm-lifestyle').textContent = vm.lifestyle;
// 护理建议(V2.3 §8 五段:肤质定制/最差2分类/精华/生活方式);综合分析与生活方式通栏已按需求移除
var careBox = $('#care-list');
if (careBox) {
careBox.innerHTML = (vm.careAdvice || []).map(function (s, i) {
return '<p class="care-item"><b>' + (i + 1) + '、【' + esc(s.tag) + '】</b>' + esc(s.text) + '</p>';
}).join('');
}
// 精华推荐卡
$('#essence-name').textContent = vm.essence.name;
$('#essence-text').textContent = vm.essence.text;
$('#essence-triggers').textContent = vm.essence.triggers.length ? '触发:' + vm.essence.triggers.join('、') : '';
+68
View File
@@ -589,6 +589,57 @@
3: { name: '50+重塑精华', text: '建议搭配使用50+重塑精华:针对熟龄肌松弛与轮廓流失问题,深层重塑支撑结构,改善明显松弛与纹路,重建面部紧实与弹性。' }
};
/* ─── V2.3 §8 护理建议 ─── */
var SKIN_TYPE_TEXT = { // §8.6 五类映射【肤质定制】段全文 + 联动句
'干性肌肤': { base: '你的日常肤质为干性肌肤:全脸皮脂分泌偏少,角质层保水能力弱,易紧绷起屑。护理以高效保湿与封闭锁水为核心,洁面选用温和低泡产品,避免频繁去角质,面霜可选择含神经酰胺、角鲨烷等封闭性成分的配方。',
link: function (c) { return c.tone && c.tone.level === '预警' ? '当前已处于明显缺水状态,建议暂缓一切控油类产品' : ''; } },
'油性肌肤': { base: '你的日常肤质为油性肌肤:皮脂分泌旺盛,毛孔易被氧化油脂堵塞。护理以温和控油与毛孔疏通为核心,可选择含烟酰胺、水杨酸的清爽配方,但清洁仍需适度,避免过度去脂反而刺激代偿性出油。',
link: function (c) { return c.tone && c.tone.level === '预警' ? '需警惕外油内干:控油同时必须叠加保湿,避免屏障受损' : ''; } },
'中性肌肤': { base: '你的日常肤质为中性肌肤:水油分泌平衡,角质状态稳定,是理想的肌肤基础态。护理以维持现状为核心,精简护肤流程,做好基础清洁、保湿与防晒即可,无需叠加过多功效产品。',
link: function () { return ''; } },
'混合偏干肌肤': { base: '你的日常肤质为混合偏干肌肤:T区状态尚可,但两颊及面部外侧偏干,易出现紧绷与细纹。建议分区护理:两颊侧重保湿滋养,选用滋润型乳液/面霜,T区轻量保湿即可,避免全脸统一用厚重面霜。',
link: function (c) { return c.smooth && c.smooth.level === '预警' ? '干燥会放大纹理粗糙感,建议先将两颊水合度提上来再做角质调理' : ''; } },
'混合偏油肌肤': { base: '你的日常肤质为混合偏油肌肤:T区出油旺盛而两颊偏干,呈典型外油内干倾向。建议分区护理:T区使用控油清爽产品,两颊加强保湿;全脸避免高滋润面霜,可选用质地轻薄的保湿乳分区涂抹。',
link: function (c) { return c.tone && c.tone.level === '预警' ? '外油内干状态下切勿加大清洁力度,补水优先于控油' : ''; } }
};
function skinTypeKey(name) { // 归一:用户自选五类名;未知/缺失按中性
var keys = ['混合偏干肌肤', '混合偏油肌肤', '干性肌肤', '油性肌肤', '中性肌肤'];
for (var i = 0; i < keys.length; i++) if (name && name.indexOf(keys[i].replace('肌肤', '')) >= 0) return keys[i];
return '中性肌肤';
}
var CARE_POINTS = { // §8.7 护理要点库(6分类×3档,逐字;肤色水润=色沉+水分并列,先色沉后水分)
contour: {
'预警': '强化轮廓紧致管理,重点针对面中、苹果肌与下颌线支持带区域,配合向上提升按摩手法,促进真皮层胶原再生与微循环。',
'改善': '加强弹韧护理补充胶原支架营养,关注易显疲态区域的支撑力,日常可增加紧致精华步骤并配合向上按摩。',
'良好': '维持现有抗老护理节奏,做好光损伤防护与状态管理,巩固真皮胶原网络密度。'
},
wrinkles: {
'预警': '加强纹路分级管理,重点针对眼周、法令纹等动态纹高发区域,使用视黄醇/胜肽类淡纹精华并配合点按手法,遏制静态纹转化。',
'改善': '加强日常淡纹与弹润护理,维持真皮基质含水量,保持肌肤饱满平滑。',
'良好': '以抗初老预防为核心,提前建立抗氧化/紧致护理习惯,延缓第一道静态纹出现。'
},
smooth: {
'预警': '加强细腻度管理,避免过度清洁破坏角质屏障,重点关注毛孔显著区域,配合低浓度酸类(如水杨酸)周期护理与柔润精华。',
'改善': '加强基础清洁与角质调理,关注鼻翼、下颌等易粗糙部位,提升毛孔通畅度与柔滑度。',
'良好': '维持当前温和护理节奏,保护角质层排列与微循环稳态。'
},
tone: { // 每档 = [色沉段, 水分段](并列输出,先色沉后水分)
'预警': ['强化透亮与色素代谢管理,严格广谱防晒,配合温和抗氧化成分(如维C衍生物)抑制黑色素转运。', '强化屏障锁水修复,停用控油类产品,改用含神经酰胺的封闭性面霜,每周2-3次补水面膜快速纠正缺水状态。'],
'改善': ['加强日常光泽管理与局部色素防控,做好基础防晒与抗氧化打底。', '注重水油平衡调理,选用清爽保湿乳液,避免过度清洁带走皮脂膜。'],
'良好': ['维持现有防护与护理习惯,巩固肤色均匀度与透亮感。', '维持现有补水习惯,巩固水合状态与水油平衡。']
},
sens: {
'预警': '优先屏障修复与舒缓管理,精简护肤流程,避免频繁更换方案与叠加功效成分,修复受损角质层。',
'改善': '保持温和护理节奏,注意防晒与环境防护,逐步提升皮肤耐受度。',
'良好': '维持规律护理并按季节阶段性调整,巩固皮肤耐受稳态。'
},
acne: { // 痘痘:V1.2 无原文,V2.3 本版新撰
'预警': '优先抗炎与痘肌修护,避免挤压与厚重型封闭产品,选用含水杨酸或壬二酸的清爽配方,局部点涂抗痘精华,必要时寻求皮肤科处理。',
'改善': '维持温和清洁与控油节奏,注意枕巾与手部卫生,避免叠加过多功效产品刺激皮损。',
'良好': '维持现有清洁控油习惯,保持作息与饮食规律,防止毛孔堵塞复发。'
}
};
/* ─── 主入口 ─── */
function buildViewModel(apiResult, sideResults, profile) {
var r = apiResult || {};
@@ -717,6 +768,22 @@
+ (tail ? tail + '。' : '');
}
/* 护理建议(V2.3 §8.5 五段固定顺序:【肤质】【最差分类1】【最差分类2】【精华】【生活方式】;
§8.5.1 输出纪律:段内不得出现 P/S 数值、档位名、判据、字段名等内部标注) */
var careAdvice = [];
var stDef = SKIN_TYPE_TEXT[skinTypeKey(profile.skinType)];
var linkSeg = stDef.link(cats);
careAdvice.push({ tag: '肤质', text: stDef.base + (linkSeg ? linkSeg + '。' : '') });
if (sorted && sorted.length >= 2) {
for (i = 0; i < 2; i++) {
var ck = CAT_DEFS.filter(function (d) { return d.name === sorted[i].name; })[0].key;
var lv2 = cats[ck].level || '良好', pts = CARE_POINTS[ck][lv2];
careAdvice.push({ tag: sorted[i].name, text: Array.isArray(pts) ? pts.join('') : pts });
}
}
careAdvice.push({ tag: '精华', text: essence.text });
careAdvice.push({ tag: '生活方式', text: worst ? LIFESTYLE[worst.catKey] : '' });
return {
total: pick(r, 'total_score'),
skinAgeRaw: skinAge,
@@ -732,6 +799,7 @@
focus: focus,
summary: summary,
lifestyle: worst ? LIFESTYLE[worst.catKey] : '',
careAdvice: careAdvice,
notes: notes
};
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 KiB

+1 -1
View File
@@ -101,7 +101,7 @@ function readBody(req, limitBytes) {
const sleep = ms => new Promise(r => setTimeout(r, ms));
/* ─── 报告页图层白名单:face_maps 只透传这几层,一行增删 ─── */
const REPORT_MAPS = ['red_area', 'brown_area', 'texture_enhanced_lines', 'texture_enhanced_pores', 'texture_enhanced_blackheads'];
const REPORT_MAPS = ['red_area', 'brown_area', 'water_area', 'texture_enhanced_lines', 'texture_enhanced_pores', 'texture_enhanced_blackheads'];
/* 按 magic bytes 判断图片格式并补 data: URL 前缀(实测 red_area/brown_area 为 jpeg 头、其余 png,不硬编码) */
function toDataUrl(b64) {
+23
View File
@@ -21,6 +21,25 @@ var SkinScore = require(path.join(__dirname, '..', 'js', 'skin-score.js'));
引擎与两组真值全部一致;今后出现引擎/真值不一致时在此登记,未登记的新差异 → 退出码 1 ─── */
var KNOWN_DIFFS = {};
/* ─── V2.3 §8.8 护理建议成品真值(五段,逐字) ─── */
var V23_SKIN = { case1: '混合偏干肌肤', case2: '干性肌肤' };
var V23_EXPECT = {
case1: [
{ tag: '肤质', text: '你的日常肤质为混合偏干肌肤:T区状态尚可,但两颊及面部外侧偏干,易出现紧绷与细纹。建议分区护理:两颊侧重保湿滋养,选用滋润型乳液/面霜,T区轻量保湿即可,避免全脸统一用厚重面霜。干燥会放大纹理粗糙感,建议先将两颊水合度提上来再做角质调理。' },
{ tag: '皱纹', text: '加强纹路分级管理,重点针对眼周、法令纹等动态纹高发区域,使用视黄醇/胜肽类淡纹精华并配合点按手法,遏制静态纹转化。' },
{ tag: '光滑', text: '加强细腻度管理,避免过度清洁破坏角质屏障,重点关注毛孔显著区域,配合低浓度酸类(如水杨酸)周期护理与柔润精华。' },
{ tag: '精华', text: '建议搭配使用35+支撑精华:专为轻熟肌打造,提升弹韧表现、维持面部轮廓清晰度,改善疲态并延缓衰老速度。' },
{ tag: '生活方式', text: '保持侧卧改仰卧的睡姿习惯,减少枕巾摩擦;控制屏幕时间,缓解眼周疲劳' }
],
case2: [
{ tag: '肤质', text: '你的日常肤质为干性肌肤:全脸皮脂分泌偏少,角质层保水能力弱,易紧绷起屑。护理以高效保湿与封闭锁水为核心,洁面选用温和低泡产品,避免频繁去角质,面霜可选择含神经酰胺、角鲨烷等封闭性成分的配方。' },
{ tag: '皱纹', text: '加强纹路分级管理,重点针对眼周、法令纹等动态纹高发区域,使用视黄醇/胜肽类淡纹精华并配合点按手法,遏制静态纹转化。' },
{ tag: '轮廓', text: '强化轮廓紧致管理,重点针对面中、苹果肌与下颌线支持带区域,配合向上提升按摩手法,促进真皮层胶原再生与微循环。' },
{ tag: '精华', text: '建议搭配使用50+重塑精华:针对熟龄肌松弛与轮廓流失问题,深层重塑支撑结构,改善明显松弛与纹路,重建面部紧实与弹性。' },
{ tag: '生活方式', text: '保持侧卧改仰卧的睡姿习惯,减少枕巾摩擦;控制屏幕时间,缓解眼周疲劳' }
]
};
/* ─── 断言计数与输出 ─── */
var TOL = 0.05 + 1e-6; // 浮点容差 0.05(1e-6 仅抵二进制表示误差,如 98.65 vs 98.7)
var pass = 0, known = 0, fail = 0;
@@ -105,6 +124,10 @@ function main() {
okNum(tag + '.AV 六分类S均分', vm.avgS, tr.avgS);
okStr(tag + '.AW 综合文案', vm.summary, tr.summary, tag + '.AW');
okStr(tag + '.AX 生活方式', vm.lifestyle, tr.lifestyle);
// V2.3 §8 护理建议五段(真值:§8.8 样例;daily_skin_type 按样例取,与 summary 口径的肤质参数不同)
var vm23 = SkinScore.buildViewModel(fixture.result, fixture.side, { realAge: tr.profile.realAge, skinType: V23_SKIN[tag] });
okStr(tag + '.BA 护理建议·五段成品', JSON.stringify(vm23.careAdvice), JSON.stringify(V23_EXPECT[tag]));
}
// 登记项清理提示:已知差异键本轮全部命中为差异;若某键实际通过则提示移除登记