feat(report): unify display grades and add contour side photos
This commit is contained in:
+35
-8
@@ -21,6 +21,19 @@
|
||||
function dimensionScore(value) {
|
||||
return numeric(value) ? (Math.round((value + 1e-9) * 10) / 10).toFixed(1) : '-';
|
||||
}
|
||||
var gradeRule = 'display-score-8-9-v1';
|
||||
var copyRule = 'wrinkles-excellent-acne-detected-v1';
|
||||
function scoreOfP(P) {
|
||||
return numeric(P) ? Math.round((Math.max(7, Math.min(10, 7 + 3 * P / 100)) + 1e-9) * 100) / 100 : null;
|
||||
}
|
||||
function levelForScore(S) {
|
||||
if (!numeric(S)) return null;
|
||||
var displayed = Number(dimensionScore(S));
|
||||
return displayed < 8 ? '改善' : displayed < 9 ? '良好' : '优秀';
|
||||
}
|
||||
function internalLevel(S) {
|
||||
return { '改善': '预警', '良好': '改善', '优秀': '良好' }[levelForScore(S)] || null;
|
||||
}
|
||||
// Read saved raw dimension values, never re-score historical reports or use
|
||||
// the legacy focus.name (which contains the old dimension terminology).
|
||||
function focusOf(vm) {
|
||||
@@ -84,12 +97,11 @@
|
||||
result = result || {};
|
||||
var views = defs.map(function(d) {
|
||||
var cat = vm.cats[d[3]], vars = Object.assign({}, cat.vars || {});
|
||||
var level = levelMap[cat.level], valid = cat.P != null;
|
||||
var level, valid = numeric(cat.P);
|
||||
var viewP = cat.P;
|
||||
if (d[0] === 'color') {
|
||||
viewP = numeric(vars.color_score) ? vars.color_score : vars.tone_scoring && vars.tone_scoring.color_score;
|
||||
valid = vars.melanin != null && numeric(viewP);
|
||||
level = valid ? (viewP < 80 ? '改善' : viewP < 90 ? '良好' : '优秀') : null;
|
||||
}
|
||||
if (d[0] === 'water') {
|
||||
// Water copy/advice is independent of pigment/dark circles. Reuse
|
||||
@@ -99,8 +111,9 @@
|
||||
viewP = waterValid ? waterScore : null;
|
||||
if (waterValid && numeric(vars.water_sev) && vars.water_sev >= 60 && vars.water_sev <= 100 && waterScore >= 80) viewP = 100 - vars.water_sev;
|
||||
valid = waterValid;
|
||||
level = valid ? (viewP < 80 ? '改善' : viewP < 90 ? '良好' : '优秀') : null;
|
||||
}
|
||||
var viewS = valid ? scoreOfP(viewP) : null;
|
||||
level = levelForScore(viewS);
|
||||
var template = valid && level ? Copy.conclusion[d[0]][level] : '';
|
||||
if (d[0] === 'water' && valid) {
|
||||
vars.water_severity_note = numeric(vars.water_sev) && vars.water_sev >= 0 && vars.water_sev <= 100
|
||||
@@ -131,8 +144,9 @@
|
||||
var nodules = vars.acne_counts ? vars.acne_counts.acne_nodule : count(result, 'acne_nodule');
|
||||
var heavy = [pustules > 0 ? '脓包' : '', nodules > 0 ? '结节' : ''].filter(Boolean);
|
||||
vars.heavy_note = heavy.length ? ',含' + heavy.join('、') + '等中重度皮损,炎症反应明显' : '';
|
||||
if (heavy.length) { level = '改善'; template = Copy.conclusion.acne[level]; }
|
||||
else if (vars.acne_cnt > 0 && level === '优秀') { level = '良好'; template = Copy.conclusion.acne[level]; }
|
||||
// Never downgrade the grade independently of the displayed score,
|
||||
// but never claim absence when the API detected lesions either.
|
||||
if (vars.acne_cnt > 0) template = '检测到 {acne_cnt} 处皮损({acne_detail}){heavy_note},局部皮损仍需关注。';
|
||||
if (vars.acne_cnt == null) template = '本次未获取完整皮损计数,请结合检测图片查看。';
|
||||
else if (vars.acne_cnt === 0) template = '本次未检出明显皮损,请结合检测图片查看。';
|
||||
if (vars.acne_cnt != null && vars.acne_counts_complete === false) {
|
||||
@@ -156,7 +170,7 @@
|
||||
}
|
||||
var details = d[0] === 'wrinkles' ? wrinkleDetails(result) : null;
|
||||
var advice = level ? Copy.care[d[0]][level] : null;
|
||||
return { key: d[0], name: d[1], dim: d[2], source: d[3], P: viewP, level: level || null,
|
||||
return { key: d[0], name: d[1], dim: d[2], source: d[3], P: viewP, S: viewS, level: level || null,
|
||||
text: valid ? fill(template, vars) : '本次未检出有效数据,请重新拍摄后查看。',
|
||||
details: details, valid: valid, advice: valid ? advice : null };
|
||||
});
|
||||
@@ -170,7 +184,20 @@
|
||||
var care = chosen.map(function(v) { return { key: v.key, name: v.name, dim: v.dim, P: v.P, level: v.level,
|
||||
priority: priority(v) === 0, text: v.advice.care + v.advice.lifestyle }; });
|
||||
var product = products.filter(function(p) { return p.match === vm.essence.name; })[0] || null;
|
||||
return { version: Copy.version + '+feedback-2026-10-12+care-2026-10-15', careRule: 'seven-lowest-three-focus-first-v1', dims: dimNames, views: views, care: care, product: product, focus: focus };
|
||||
return { version: Copy.version + '+feedback-2026-10-12+care-2026-10-15+grade-8-9+two-copy-fixes', gradeRule: gradeRule, copyRule: copyRule, careRule: 'seven-lowest-three-focus-first-v1', dims: dimNames, views: views, care: care, product: product, focus: focus };
|
||||
}
|
||||
return { dimensionScore: dimensionScore, build: build, products: products, levelMap: levelMap, dimNames: dimNames, wrinkleDetails: wrinkleDetails, focusOf: focusOf, customerText: customerText };
|
||||
// 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 || (saved.gradeRule === gradeRule && saved.copyRule === copyRule)) return saved || build(vm, result);
|
||||
var current = build(vm, result);
|
||||
var care = (saved.care || []).map(function(item) {
|
||||
// Pre-seven-item snapshots contain name/text only, without a stable key.
|
||||
// Match exact known names; never infer from array position or insert items.
|
||||
var view = current.views.filter(function(v) { return item.key ? v.key === item.key : v.name === item.name; })[0];
|
||||
return view && view.advice ? Object.assign({}, item, { key: view.key, level: view.level, text: view.advice.care + view.advice.lifestyle }) : item;
|
||||
});
|
||||
return Object.assign({}, saved, { gradeRule: gradeRule, copyRule: copyRule, views: current.views, care: care });
|
||||
}
|
||||
return { dimensionScore: dimensionScore, scoreOfP: scoreOfP, levelForScore: levelForScore, internalLevel: internalLevel, gradeRule: gradeRule, copyRule: copyRule, build: build, forDisplay: forDisplay, products: products, levelMap: levelMap, dimNames: dimNames, wrinkleDetails: wrinkleDetails, focusOf: focusOf, customerText: customerText };
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user