fix(recommendation): use displayed skin age across reports and admin
This commit is contained in:
+4
-4
@@ -427,8 +427,8 @@ function renderDetail(data) {
|
||||
if (r.detect_status === '成功') {
|
||||
h += dSec('综合', '<div class="d-kv">' +
|
||||
'<span>综合得分 <b>' + fmtTotal(r.total_score) + '</b></span>' +
|
||||
'<span>原始肌龄(新推荐依据) <b>' + ageText(r.skin_age) + '</b></span>' +
|
||||
'<span>前端展示肌龄 <b>' + ageText(r.skin_age_display) + '</b></span>' +
|
||||
'<span>原始肌龄(接口返回) <b>' + ageText(r.skin_age) + '</b></span>' +
|
||||
'<span>报告展示肌龄(推荐依据) <b>' + ageText(r.skin_age_display) + '</b></span>' +
|
||||
'<span>六分类均分S <b>' + fmtScore(r.avg_s) + '</b></span>' +
|
||||
'<span>左下颌线角 <b>' + (r.jawline_angle_l != null ? r.jawline_angle_l + '°' : '-') + '</b></span>' +
|
||||
'<span>右下颌线角 <b>' + (r.jawline_angle_r != null ? r.jawline_angle_r + '°' : '-') + '</b></span>' +
|
||||
@@ -439,7 +439,7 @@ function renderDetail(data) {
|
||||
var tone = r.tone_scoring;
|
||||
h += '<p class="sub">肤色项=色素扣斑分×80%+黑眼圈评分×20%;' + (r.vita_score_rule === 'independent-color-water-smooth-min-v1' ? '该历史版本透亮感取独立肤色、水分、平滑度三项最低分。' : '肤色项与水分项各占50%合成肤色水润分,透亮感取肤色水润与平滑度的最低分。') + '色素扣斑分:' + esc(fmtToneScore(tone.pigment_adjusted_score)) + ',黑眼圈评分:' + esc(fmtToneScore(tone.dark_circle_score)) + ',独立肤色项:' + esc(fmtToneScore(tone.color_score)) + ',水分项:' + esc(fmtToneScore(tone.water_adjusted_score)) + '。肤色缺项按有效权重归一。</p>';
|
||||
}
|
||||
h += '<p class="sub">前端展示肌龄限制在实际年龄±5岁;推荐仍使用原始肌龄。历史报告保留当时的推荐。</p>';
|
||||
h += '<p class="sub">展示肌龄限制在实际年龄±5岁;当前推荐使用报告展示肌龄及边界规则。原始检测数据和历史快照保留。</p>';
|
||||
|
||||
/* 6 分类表格 */
|
||||
var catRows = '';
|
||||
@@ -532,7 +532,7 @@ function renderDetail(data) {
|
||||
var score = rec.scores[sk];
|
||||
scoreParts.push(DIM_NAMES[sk] + ':' + (score == null ? '未获取' : String(score)));
|
||||
}
|
||||
h += dSec('推荐依据', '<div class="d-kv"><span>使用原始肌龄 <b>' + ageText(rec.skinAge) + '</b></span>' +
|
||||
h += dSec('推荐依据', '<div class="d-kv"><span>' + (rec.ageBasis === 'display' ? '使用展示肌龄' : '使用原始肌龄') + ' <b>' + ageText(rec.skinAge) + '</b></span>' +
|
||||
'<span>基础档 <b>' + esc(tierText(rec.baseTier)) + '</b></span>' +
|
||||
'<span>最终档 <b>' + esc(tierText(rec.tier)) + '</b></span></div>' +
|
||||
'<div class="d-copy">' + esc(rec.reason) + '</div><div class="sub">判定分(未舍入S,不使用前端一位小数):' + esc(scoreParts.join(';')) + '</div>');
|
||||
|
||||
@@ -1669,6 +1669,7 @@
|
||||
refresh();
|
||||
}
|
||||
function renderReport(vm, frontPhoto, sidePhoto, payload, reportPhotos) {
|
||||
vm=SkinScore.withDisplayRecommendation(vm,payload && payload.result);
|
||||
activeWrinkleReport={payload:payload,photos:reportPhotos || [frontPhoto,sidePhoto,null],owner:AccountClient.user()&&AccountClient.user().id,started:false};
|
||||
renderContourSides(reportPhotos || [frontPhoto, sidePhoto, null]);
|
||||
reportOwner = AccountClient.user() && AccountClient.user().id;
|
||||
|
||||
@@ -181,6 +181,10 @@
|
||||
// Refresh only presentation for old snapshots: scores, selected care order,
|
||||
// product and original stored objects are never rewritten/recomputed.
|
||||
function forDisplay(vm, result, saved) {
|
||||
if (saved && vm.recommendation && vm.recommendation.ageBasis === 'display') {
|
||||
var product=products.filter(function(p){return p.tier === vm.recommendation.tier;})[0] || null;
|
||||
if(saved.product!==product)saved = Object.assign({}, saved, { product: product });
|
||||
}
|
||||
if (!saved || (saved.gradeRule === gradeRule && saved.copyRule === copyRule)) return saved || build(vm, result);
|
||||
var current = build(vm, result);
|
||||
var care = (saved.care || []).map(function(item) {
|
||||
|
||||
+22
-7
@@ -628,12 +628,12 @@
|
||||
var firm = isNum(scores.firm) ? scores.firm : null;
|
||||
var vita = isNum(scores.vita) ? scores.vita : null;
|
||||
var stab = isNum(scores.stab) ? scores.stab : null;
|
||||
var rec = { version: '2026-10-12-skin-age-v1', skinAge: skinAge,
|
||||
var rec = { version: '2026-10-16-display-skin-age-v2', ageBasis: 'display', skinAge: skinAge,
|
||||
baseTier: null, tier: null, boundary: null, adjustment: 'none',
|
||||
scores: { firm: firm, vita: vita, stab: stab }, reason: '', triggers: [] };
|
||||
if (!isNum(skinAge) || skinAge <= 0) {
|
||||
rec.adjustment = 'unavailable';
|
||||
rec.reason = '未获取有效原始肌龄,暂不推荐具体产品;不以实际年龄代替。';
|
||||
rec.reason = '未获取有效展示肌龄,暂不推荐具体产品;不以实际年龄代替。';
|
||||
return rec;
|
||||
}
|
||||
rec.baseTier = skinAge < 35 ? 1 : (skinAge < 50 ? 2 : 3);
|
||||
@@ -653,11 +653,11 @@
|
||||
rec.reason = '处于' + rec.boundary + '岁上侧边界,紧塑力≥9且透亮感或稳韧力≥9,降一档。';
|
||||
rec.triggers.push(rec.boundary + '岁边界高分降档');
|
||||
} else if (skinAge < 32) {
|
||||
rec.reason = '原始肌龄小于32岁,固定推荐25+,轮廓或皱纹低分不升档。';
|
||||
rec.reason = '展示肌龄小于32岁,固定推荐25+,轮廓或皱纹低分不升档。';
|
||||
} else if (rec.boundary != null) {
|
||||
rec.reason = '处于' + rec.boundary + '岁边界,未满足升降档条件,保持肤龄基础档。';
|
||||
} else {
|
||||
rec.reason = '不在35±3或50±3岁边界内,仅按原始肌龄推荐。';
|
||||
rec.reason = '不在35±3或50±3岁边界内,仅按展示肌龄推荐。';
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
@@ -777,7 +777,7 @@
|
||||
if (!worst || cP < worst.P) worst = { catKey: def.key, name: def.name, P: cP, S: sShow(cP) };
|
||||
}
|
||||
|
||||
var recommendation = recommendProduct(skinAge, {
|
||||
var recommendation = recommendProduct(skinAgeDisplay, {
|
||||
firm: dims.firm.P == null ? null : sRaw(dims.firm.P),
|
||||
vita: dims.vita.P == null ? null : sRaw(dims.vita.P),
|
||||
stab: dims.stab.P == null ? null : sRaw(dims.stab.P)
|
||||
@@ -934,7 +934,7 @@
|
||||
};
|
||||
|
||||
// Apply the current display rule to new and historical reports without
|
||||
// modifying their raw age, stored snapshot, copy or recommendation.
|
||||
// modifying their raw age or stored snapshot. Recommendation uses this age.
|
||||
function reportSkinAge(vm, result) {
|
||||
var raw = vm && Object.prototype.hasOwnProperty.call(vm, 'skinAgeRaw') ? val(vm.skinAgeRaw) : val(result && result.skin_age);
|
||||
if (!isNum(raw) || raw < 0) return null;
|
||||
@@ -942,7 +942,22 @@
|
||||
if (!isNum(actual) || actual < 0) return raw;
|
||||
return Math.max(actual - 5, Math.min(actual + 5, raw));
|
||||
}
|
||||
function withDisplayRecommendation(vm, result) {
|
||||
if (!vm) return vm;
|
||||
var age = reportSkinAge(vm, result), scores = {};
|
||||
['firm','vita','stab'].forEach(function(key) {
|
||||
var d = vm.dims && vm.dims[key];
|
||||
var saved = vm.recommendation && vm.recommendation.scores && vm.recommendation.scores[key];
|
||||
scores[key] = isNum(saved) ? saved : d && isNum(d.P) ? sRaw(d.P) : d && isNum(d.S) ? d.S : null;
|
||||
});
|
||||
var recommendation = recommendProduct(age, scores), tier = recommendation.tier;
|
||||
return Object.assign({}, vm, { skinAgeDisplay: age, recommendation: recommendation,
|
||||
group: tier == null ? null : ['25+组','35+组','50+组'][tier-1],
|
||||
essence: { name: tier == null ? '暂无法推荐' : ESSENCE[tier].name,
|
||||
text: tier == null ? recommendation.reason : ESSENCE[tier].text, tier: tier, triggers: recommendation.triggers } });
|
||||
}
|
||||
return {
|
||||
withDisplayRecommendation: withDisplayRecommendation,
|
||||
capDimensionScore: capDimensionScore,
|
||||
weightedTotal: weightedTotal,
|
||||
reportSkinAge: reportSkinAge,
|
||||
@@ -1020,7 +1035,7 @@ if (typeof require === 'function' && typeof module !== 'undefined' && require.ma
|
||||
ok(vm2.dims.firm.P === Math.min(vm2.cats.contour.P, vm2.cats.wrinkles.P)
|
||||
&& vm2.dims.vita.P === Math.min(vm2.cats.smooth.P, vm2.cats.tone.P)
|
||||
&& vm2.dims.stab.P === Math.min(vm2.cats.sens.P, vm2.cats.acne.P), '三维度 P = min(旗下两分类)');
|
||||
ok(vm2.group === '25+组', '实际年龄40不影响推荐,原始肌龄20仍为25+组');
|
||||
ok(vm2.group === '35+组', '实际年龄40、原始肌龄20、展示肌龄35,按展示肌龄推荐35+组');
|
||||
|
||||
console.log('== T3 原始肌龄展示 ==');
|
||||
var r3 = clone(SS.MOCK_RESULT);
|
||||
|
||||
Reference in New Issue
Block a user