feat(taobao): add native mini program with shared backend
Preserve H5 flows while adding Taobao identity, native capture, reports and isolated local development. Fix canceled province selection and expired-session logout. Record passing local regressions, two pre-existing H5 assertion failures and pending platform validation.
This commit is contained in:
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"skin-score.js": "1f3256fd8d5863de3407c2037df30b6a801ac49858a8a0acab7163f83f642abc",
|
||||
"report-ui.js": "2c6acaad7cf6e9c826f062f9e79d419470b37da71ab86a5399897d62fd695caf",
|
||||
"report-copy.js": "402aa543c3437f4e8043e2281b09d7e4d734c0dd2d103636c9f37fe8aa28d6c2"
|
||||
}
|
||||
Vendored
+141
@@ -0,0 +1,141 @@
|
||||
// Generated from reference/AI测肤报告页话术修改.md; run tools/build_report_copy.py.
|
||||
(function(root,factory){if(typeof module==="object"&&module.exports)module.exports=factory();else root.ReportCopy=factory();})(typeof window!=="undefined"?window:this,function(){return {
|
||||
"version": "2026-10-09",
|
||||
"conclusion": {
|
||||
"contour": {
|
||||
"改善": "面部轮廓紧致度有待提升,下颌线清晰度不足,左右下颌线角度分别为左 {la}°/ 右 {ra}°;中面部容积略欠饱满,肌肤支撑力偏弱。",
|
||||
"良好": "面部轮廓清晰,下颌线较为清晰,左右下颌线角度左 {la}°/ 右 {ra}°;中面部容积无明显流失;肌肤处于健康状态,支撑力表现良好。",
|
||||
"优秀": "面部轮廓紧致立体,下颌线清晰;中面部容积饱满,肌肤支撑力充足。"
|
||||
},
|
||||
"wrinkles": {
|
||||
"改善": "全脸共检测到皱纹 {wr_cnt} 条、细纹 {fl_cnt} 条,面中、口周、眼周等区域已出现静态纹倾向,纹路已呈现固化趋势,并非临时性干纹。",
|
||||
"良好": "全脸共检测到皱纹 {wr_cnt} 条、细纹 {fl_cnt} 条,面部整体平整,仅眼周或口周有细微的干纹,无明显静态深纹,纹路面积占比相对较低。",
|
||||
"优秀": "全脸共检测到皱纹 {wr_cnt} 条、细纹 {fl_cnt} 条;整体纹路状态较好,建议维持日常淡纹与保湿护理。"
|
||||
},
|
||||
"color": {
|
||||
"改善": "检测到当前肌肤色素分 {melanin},存在色素沉着较显著,{dark_circle_note},整体透亮感不足。",
|
||||
"良好": "检测到当前肌肤色素分 {melanin},局部有色素沉积;{dark_circle_note},整体状态稳定,局部透亮感稍弱。",
|
||||
"优秀": "检测到当前肌肤色素分 {melanin},无明显色素沉积,{dark_circle_note};肤色均匀透亮。"
|
||||
},
|
||||
"smooth": {
|
||||
"改善": "当前肌肤平滑度还有提升空间,检测到粗大毛孔 {pore_cnt} 颗、黑头 {blackhead_cnt} 颗,肤感整体细腻度有提升空间,纹理不均。",
|
||||
"良好": "肌肤整体较为平滑,局部区域细腻度不足;检测到粗大毛孔 {pore_cnt} 颗、黑头 {blackhead_cnt} 颗,有轻微角质粗糙感。",
|
||||
"优秀": "肌肤质感表现优异,表面细腻平滑,角质层排列整齐,无明显粗大毛孔与黑头。"
|
||||
},
|
||||
"water": {
|
||||
"改善": "角质层含水量较低,缺水面积 {water_area}%、肌肤缺水比较严重 {water_sev},肌肤含水量偏低,水润度不足,表面偏干燥,容易出现干纹。",
|
||||
"良好": "角质层含水量适中,缺水面积 {water_area}%、肌肤含水量处于健康水平,整体水润度良好。",
|
||||
"优秀": "角质层含水量充足,肌肤屏障锁水能力强,表面饱满水润,无干燥紧绷表现。"
|
||||
},
|
||||
"sens": {
|
||||
"改善": "泛红面积达 {sens_area}%,肌肤泛红明显,敏感区域可见泛红;对外界刺激耐受度不足,容易受外界因素影响产生状态波动。",
|
||||
"良好": "泛红面积 {sens_area}%,肌肤存在局部轻微泛红;对外界环境有良好的耐受度,仅在接触强刺激物时偶有轻微反应。",
|
||||
"优秀": "泛红面积 {sens_area}%,无明显泛红、敏感迹象;对外界刺激耐受度佳,肌肤处于稳定的健康状态。"
|
||||
},
|
||||
"acne": {
|
||||
"改善": "检测到 {acne_cnt} 处皮损({acne_detail}){heavy_note},肌肤状态不稳定,毛孔易堵塞,皮脂分泌波动明显。",
|
||||
"良好": "检测到 {acne_cnt} 处皮损({acne_detail}),以闭口粉刺、丘疹为主,无明显红肿痘痘;皮脂分泌基本正常,毛孔偶有轻微堵塞。",
|
||||
"优秀": "未检出明显痘痘、粉刺或闭口,无明显红肿、脓包迹象。"
|
||||
}
|
||||
},
|
||||
"care": {
|
||||
"contour": {
|
||||
"改善": {
|
||||
"care": "重点进行轮廓紧致管理,关注面中、苹果肌与下颌线区域。日常增加紧致精华步骤,配合由下向上的轻柔提升按摩,帮助肌肤维持弹润和支撑感,让轮廓看起来更紧实。",
|
||||
"lifestyle": "保证充足、规律的睡眠,让肌肤在夜间充分修护;坚持防晒,减少紫外线带来的老化影响;减少熬夜。"
|
||||
},
|
||||
"良好": {
|
||||
"care": "关注面中、苹果肌、下颌线等容易显疲态区域的支撑感。日常可叠加紧致精华步骤,并配合向上提升按摩手法,预防疲态引起的松弛与垮塌累积,稳住面部支撑线。",
|
||||
"lifestyle": "日常注意防晒,保持规律作息;坚持适度运动,帮助肌肤维持活力。"
|
||||
},
|
||||
"优秀": {
|
||||
"care": "保持现有紧致抗衰护理节奏,日常叠加使用提亮精华,坚持防晒,加强光损伤防护与状态管理,持续关注面中疲态与轮廓支撑状态,让紧致状态更稳定、更持久。",
|
||||
"lifestyle": "坚持防晒与规律作息,均衡饮食,保证优质蛋白、新鲜蔬果和健康脂肪摄入,适度运动。"
|
||||
}
|
||||
},
|
||||
"wrinkles": {
|
||||
"改善": {
|
||||
"care": "重视纹路管理,日常可使用含有肽类、胶原类成分的淡纹精华,针对眼周、法令纹等动态纹高发区域配合点按手法,遏制静态纹转化,帮肌肤恢复平滑细腻的状态。",
|
||||
"lifestyle": "注意睡姿,减少面部长期受压;减少夸张表情,避免揉眼、托腮等表情性挤压习惯,减少纹路加深。"
|
||||
},
|
||||
"良好": {
|
||||
"care": "加强日常淡纹与肌肤弹润护理,叠加使用含肽类、胶原类成分的淡纹精华,提升肌肤水润度与饱满感,维持肤表平滑。",
|
||||
"lifestyle": "减少夸张表情反复牵拉,睡前加强保湿修护。"
|
||||
},
|
||||
"优秀": {
|
||||
"care": "以预防初纹为核心,搭配抗初老型精华,提前建立抗氧化/紧致护理习惯,延缓第一道静态纹出现。",
|
||||
"lifestyle": "保持良好作息与运动习惯,坚持防晒,减轻光老化与糖化负担,维持肌肤稳定状态。"
|
||||
}
|
||||
},
|
||||
"color": {
|
||||
"改善": {
|
||||
"care": "重点关照暗沉与色素易沉积区域,强化透亮与肤色均匀,严格防晒,配合温和焕亮或抗氧化精华帮助均匀肤色与透亮感。",
|
||||
"lifestyle": "日常加强防晒与抗氧化护理,减少熬夜与压力引发的暗沉,适当增加富含维C的蔬果摄入。"
|
||||
},
|
||||
"良好": {
|
||||
"care": "加强日常光泽管理与局部暗沉护理,做好防晒与抗氧化打底;叠加使用温和焕亮精华,稳住当前肤色状态并提升整体通透感。",
|
||||
"lifestyle": "持续做好防晒,保持作息规律,避免波动性色沉,守护均匀透亮感。"
|
||||
},
|
||||
"优秀": {
|
||||
"care": "维持现有防晒与抗氧化护肤习惯,叠加使用温和焕亮精华,巩固肤色均匀度与透亮感。",
|
||||
"lifestyle": "坚持日常防晒,保持均衡饮食支持皮肤稳态。"
|
||||
}
|
||||
},
|
||||
"smooth": {
|
||||
"改善": {
|
||||
"care": "关注毛孔可见度与肤表粗糙感改善,加强角质管理,提升肌肤平滑细腻度。",
|
||||
"lifestyle": "减少高糖高脂饮食,降低皮脂分泌刺激,定期温和调理角质,避免用手挤压黑头。"
|
||||
},
|
||||
"良好": {
|
||||
"care": "加强基础清洁与角质管理,关注鼻翼、下颌等易堵塞部位,提升毛孔通畅度与肌肤细腻度。",
|
||||
"lifestyle": "温水洁面避免烫洗,保持床品清洁减少局部刺激。"
|
||||
},
|
||||
"优秀": {
|
||||
"care": "维持当前温和护理节奏,维护角质层健康与肌肤屏障稳定状态。",
|
||||
"lifestyle": "保持规律清洁与保湿习惯,避免频繁更换功效类产品,减少肌肤适应负担。"
|
||||
}
|
||||
},
|
||||
"water": {
|
||||
"改善": {
|
||||
"care": "强化屏障锁水修复,注意水油平衡,每周2-3次深度补水,深度改善肌肤缺水状态。",
|
||||
"lifestyle": "每日足量饮水,补充身体水分,改善干燥环境湿度,避免长时间空调直吹。"
|
||||
},
|
||||
"良好": {
|
||||
"care": "日常需注重水油平衡调理,避免过度清洁损伤皮肤屏障,注意为肌肤持续补水。",
|
||||
"lifestyle": "每日足量饮水,环境干燥时及时增加肌肤水分补充。"
|
||||
},
|
||||
"优秀": {
|
||||
"care": "持续为皮肤补水与保湿,避免过度清洁与频繁去角质,巩固肌肤水润度与水油平衡。",
|
||||
"lifestyle": "坚持多喝水与规律作息,季节交替时提前调整保湿方案。"
|
||||
}
|
||||
},
|
||||
"sens": {
|
||||
"改善": {
|
||||
"care": "关注屏障修复与舒缓,精简护肤流程,选择温和洁面方式,修复受损角质层。若状态持续无明显好转,可寻求专业护肤建议。",
|
||||
"lifestyle": "减少外界刺激,如酒精、香精、高浓度酸类精华等成分,避免冷热骤变刺激。"
|
||||
},
|
||||
"良好": {
|
||||
"care": "保持温和护理节奏,注意防晒与环境防护,逐步提升皮肤耐受度。",
|
||||
"lifestyle": "避免冷热骤变刺激肌肤屏障,运动后及时清洁降温。"
|
||||
},
|
||||
"优秀": {
|
||||
"care": "持续规律护理并按季节阶段性调整,巩固皮肤耐受稳态。",
|
||||
"lifestyle": "保持健康作息与均衡饮食,维持皮肤屏障稳态。"
|
||||
}
|
||||
},
|
||||
"acne": {
|
||||
"改善": {
|
||||
"care": "优先针对性调理痘区肌肤状态,精简护肤流程,避免频繁更换护肤方案与叠加功效成分;严重时及时就医。",
|
||||
"lifestyle": "减少高糖高脂饮食与熬夜,避免手挤痘痘;保持床品、毛巾清洁,运动后及时清洁,减少汗液与皮脂堆积。"
|
||||
},
|
||||
"良好": {
|
||||
"care": "保持温和清洁与肌肤炎症调理,关注T区、下颌等易出油区域,提升毛孔通畅度,同时注意防晒与保湿。",
|
||||
"lifestyle": "保持规律作息与清淡饮食,运动后及时清洁,减少汗液与皮脂堆积。"
|
||||
},
|
||||
"优秀": {
|
||||
"care": "坚持定期清洁,维持水油平衡与毛孔通畅,巩固皮肤耐受稳态。",
|
||||
"lifestyle": "保持健康作息与均衡饮食,维持皮肤屏障健康稳定。"
|
||||
}
|
||||
}
|
||||
}
|
||||
};});
|
||||
Vendored
+199
@@ -0,0 +1,199 @@
|
||||
/* Presentation only: original scores and recommendation rules remain in SkinScore. */
|
||||
(function(root, factory) {
|
||||
if (typeof module === 'object' && module.exports) module.exports = factory(require('./report-copy.js'));
|
||||
else root.ReportUI = factory(root.ReportCopy);
|
||||
})(typeof window !== 'undefined' ? window : this, function(Copy) {
|
||||
'use strict';
|
||||
var defs = [
|
||||
['contour', '轮廓', 'firm', 'contour'], ['wrinkles', '皱纹', 'firm', 'wrinkles'],
|
||||
['color', '肤色', 'vita', 'tone'], ['smooth', '平滑度', 'vita', 'smooth'], ['water', '水分', 'vita', 'tone'],
|
||||
['sens', '泛红', 'stab', 'sens'], ['acne', '痘痘', 'stab', 'acne']
|
||||
];
|
||||
var products = [
|
||||
{ tier: 1, match: '25+束紧精华', title: "1'me 主场精华 I", name: '焕活光泽 透亮紧致', image: 'assets/img/ui-20261015/product-25.png' },
|
||||
{ tier: 2, match: '35+支撑精华', title: "1'me 主场精华 II", name: '恢复弹性 紧实利落', image: 'assets/img/ui-20261015/product-35.png' },
|
||||
{ tier: 3, match: '50+重塑精华', title: "1'me 主场精华 III", name: '强韧屏障 轮廓向上', image: 'assets/img/ui-20261015/product-50.png' }
|
||||
];
|
||||
var levelMap = { '预警': '改善', '改善': '良好', '良好': '优秀' };
|
||||
var dimNames = { firm: '紧塑力', vita: '透亮感', stab: '稳韧力' };
|
||||
var focusTips = { firm: '强化紧塑力,提拉轮廓抚平细纹。', vita: '提升透亮感,补水提亮加强防晒。', stab: '增强稳韧力,舒缓泛红强韧屏障。' };
|
||||
function numeric(value) { return typeof value === 'number' && isFinite(value); }
|
||||
function dimensionScore(value) {
|
||||
return numeric(value) ? Math.min(9.9, Math.round((value + 1e-9) * 10) / 10).toFixed(1) : '-';
|
||||
}
|
||||
var gradeRule = 'display-score-8-9-v1';
|
||||
var copyRule = 'wrinkles-excellent-acne-detected-water-contour-v4';
|
||||
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) {
|
||||
var selected = null;
|
||||
['firm', 'vita', 'stab'].forEach(function(key) {
|
||||
var dim = vm.dims && vm.dims[key];
|
||||
if (dim && numeric(dim.P) && (!selected || dim.P < selected.score)) selected = { key: key, score: dim.P, name: dimNames[key], tip: focusTips[key] };
|
||||
});
|
||||
return selected;
|
||||
}
|
||||
function customerText(view) {
|
||||
// Keep missing-data diagnostics in the saved/admin record, not on the
|
||||
// customer report. Also suppress equivalent text in older snapshots.
|
||||
if (view.valid === false || /本次未检出有效数据|本次未获取轮廓有效数据/.test(view.text || '')) return '';
|
||||
if (view.key === 'wrinkles') return view.text.split('\n分区明细')[0];
|
||||
if (view.key !== 'contour') return view.text;
|
||||
// Also cover immutable old presentations, without modifying stored copy.
|
||||
return view.text.replace(/侧脸角度数据未完整获取[;;]?/g, '');
|
||||
}
|
||||
function scalar(value) { return numeric(value) ? value : value && numeric(value.value) ? value.value : null; }
|
||||
var wrinkleDefs = [
|
||||
['forehead', '抬头纹(额头纹)', ['forehead_wrinkle_info'], 'forehead_count'],
|
||||
['left_nasolabial', '左法令纹', ['left_nasolabial_wrinkle_info', 'left_nasolabial_fold_info'], 'left_nasolabial_count'],
|
||||
['right_nasolabial', '右法令纹', ['right_nasolabial_wrinkle_info', 'right_nasolabial_fold_info'], 'right_nasolabial_count'],
|
||||
['left_crowsfeet', '左鱼尾纹', ['left_crowsfeet_wrinkle_info'], 'left_crowsfeet_count'],
|
||||
['right_crowsfeet', '右鱼尾纹', ['right_crowsfeet_wrinkle_info'], 'right_crowsfeet_count'],
|
||||
['left_eye', '左眼部细纹', ['left_eye_wrinkle_info'], 'left_undereye_count'],
|
||||
['right_eye', '右眼部细纹', ['right_eye_wrinkle_info'], 'right_undereye_count'],
|
||||
['left_mouth', '左嘴角纹', ['left_mouth_wrinkle_info'], 'left_mouth_count'],
|
||||
['right_mouth', '右嘴角纹', ['right_mouth_wrinkle_info'], 'right_mouth_count'],
|
||||
['glabella', '眉间纹', ['glabella_wrinkle_info'], 'glabella_count'],
|
||||
['left_cheek', '左脸颊纹', ['left_cheek_wrinkle_info'], 'left_cheek_count'],
|
||||
['right_cheek', '右脸颊纹', ['right_cheek_wrinkle_info'], 'right_cheek_count']
|
||||
];
|
||||
var wrinkleMetrics = [
|
||||
['wrinkle_score', '皱纹分'], ['wrinkle_severity_level', '严重等级'],
|
||||
['wrinkle_deep_num', '深纹条数'], ['wrinkle_shallow_num', '浅纹条数'],
|
||||
['wrinkle_norm_length', '标准化长度'], ['wrinkle_norm_depth', '标准化深度'],
|
||||
['wrinkle_pixel_density', '像素密度'], ['wrinkle_area_ratio', '面积比例'], ['wrinkle_deep_ratio', '深纹比例']
|
||||
];
|
||||
function wrinkleDetails(result) {
|
||||
result = result || {};
|
||||
return wrinkleDefs.map(function (def) {
|
||||
var node = null;
|
||||
def[2].some(function (key) { if (result[key] && typeof result[key] === 'object') { node = result[key]; return true; } return false; });
|
||||
var values = {};
|
||||
wrinkleMetrics.forEach(function (metric) { values[metric[0]] = scalar(node && node[metric[0]]); });
|
||||
// Region counts are a valid fallback; a missing count is never zero.
|
||||
if (values.wrinkle_deep_num == null) values.wrinkle_deep_num = scalar(result.wrinkle_count && result.wrinkle_count[def[3]]);
|
||||
var fine = result.fine_line || result.fine_line_count;
|
||||
if (values.wrinkle_shallow_num == null) values.wrinkle_shallow_num = scalar(fine && fine[def[3]]);
|
||||
return { key: def[0], name: def[1], metrics: values };
|
||||
});
|
||||
}
|
||||
function fill(template, vars) {
|
||||
return template.replace(/\{([a-z_]+)\}/g, function(_, key) {
|
||||
var v = vars[key];
|
||||
return v == null ? '未获取' : numeric(v) ? String(Math.round(v * 100) / 100) : String(v);
|
||||
}).replace(/\s+/g, ' ').trim();
|
||||
}
|
||||
function count(result, key) { var v = result[key]; return v && numeric(v.count) ? v.count : null; }
|
||||
function build(vm, result) {
|
||||
result = result || {};
|
||||
var views = defs.map(function(d) {
|
||||
var cat = vm.cats[d[3]], vars = Object.assign({}, cat.vars || {});
|
||||
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);
|
||||
}
|
||||
if (d[0] === 'water') {
|
||||
// Water copy/advice is independent of pigment/dark circles. Reuse
|
||||
// the existing water cross-check; never change dimension scoring.
|
||||
var waterScore = vars.water_score;
|
||||
var waterValid = numeric(waterScore) && waterScore >= 0 && waterScore <= 100;
|
||||
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;
|
||||
}
|
||||
var viewS = valid ? scoreOfP(viewP) : null;
|
||||
level = levelForScore(viewS);
|
||||
var template = valid && level ? Copy.conclusion[d[0]][level] : '';
|
||||
if (d[0] === 'contour') {
|
||||
if (vars.la == null || vars.ra == null) template = template.replace(/左右下颌线角度(?:分别为左|左) \{la\}°\/ 右 \{ra\}°[;;]/g, '');
|
||||
}
|
||||
if (d[0] === 'color') {
|
||||
// Severity is an independent detection, not inferred from tone level
|
||||
// or dark_circle_score. Missing/invalid severity must not imply mild.
|
||||
var colorSeverity = scalar(result.dark_circle_severity);
|
||||
var colorDescriptions = ['无明显黑眼圈', '仅存在轻度黑眼圈', '存在中度黑眼圈', '可见明显黑眼圈'];
|
||||
if (numeric(colorSeverity) && colorSeverity % 1 === 0 && colorSeverity >= 0 && colorSeverity <= 3) {
|
||||
vars.dark_circle_note = colorDescriptions[colorSeverity];
|
||||
} else {
|
||||
template = template.replace(/\{dark_circle_note\}[,;]/g, '');
|
||||
}
|
||||
}
|
||||
if (d[0] === 'acne') {
|
||||
var pustules = vars.acne_counts ? vars.acne_counts.acne_pustule : count(result, 'acne_pustule');
|
||||
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('、') + '等中重度皮损,炎症反应明显' : '';
|
||||
// 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) {
|
||||
template = vars.acne_cnt > 0
|
||||
? '本次已获取数据中检测到 {acne_cnt} 处皮损({acne_detail}){heavy_note},部分类型计数未获取,请结合检测图片查看。'
|
||||
: '本次已获取的皮损计数为0,部分类型数据缺失,请结合检测图片查看。';
|
||||
}
|
||||
}
|
||||
// Missing counts are unknown, not zero: remove only the unavailable metric.
|
||||
if (vars.fl_cnt == null) template = template.replace(/、细纹 \{fl_cnt\} 条/g, '(细纹计数未获取)');
|
||||
if (vars.wr_cnt == null) template = template.replace(/皱纹 \{wr_cnt\} 条/g, '皱纹计数未获取');
|
||||
if (vars.water_area == null) template = template.replace(/缺水面积 \{water_area\}%[、,]/g, '缺水面积未获取;');
|
||||
if (vars.water_sev == null) template = template.replace(/肌肤缺水比较严重 \{water_sev\},/g, '');
|
||||
if (vars.sens_area == null) template = template.replace(/泛红面积(?:达 | )\{sens_area\}%[,;]/g, '泛红面积未获取;');
|
||||
if (vars.pore_cnt == null) template = template.replace(/粗大毛孔 \{pore_cnt\} 颗/g, '毛孔计数未获取');
|
||||
if (vars.blackhead_cnt == null) template = template.replace(/黑头 \{blackhead_cnt\} 颗/g, '黑头计数未获取');
|
||||
if (d[0] === 'smooth' && valid && level === '优秀') {
|
||||
// A high aggregate score does not mean every localized pore is absent.
|
||||
if (vars.pore_cnt == null || vars.blackhead_cnt == null) template = '肌肤质感整体较好,但毛孔或黑头计数未完整获取,请结合检测图查看。';
|
||||
else if (vars.pore_cnt > 0 || vars.blackhead_cnt > 0) template = '肌肤质感整体较好;本次检测到粗大毛孔 {pore_cnt} 颗、黑头 {blackhead_cnt} 颗,局部仍有可改善之处。';
|
||||
}
|
||||
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, S: viewS, level: level || null,
|
||||
text: valid ? fill(template, vars) : '本次未检出有效数据,请重新拍摄后查看。',
|
||||
details: details, valid: valid, advice: valid ? advice : null };
|
||||
});
|
||||
var focus = focusOf(vm);
|
||||
function priority(view) { return focus && view.dim === focus.key ? 0 : 1; }
|
||||
function order(a, b) { return a.P - b.P || priority(a) - priority(b) || views.indexOf(a) - views.indexOf(b); }
|
||||
// Select globally weakest three FIRST, then move selected focus members
|
||||
// to the front. Never insert an unselected stronger focus-category view.
|
||||
var chosen = views.filter(function(v) { return v.valid && numeric(v.P) && v.advice; }).sort(order).slice(0,3);
|
||||
chosen.sort(function(a,b) { return priority(a) - priority(b) || order(a,b); });
|
||||
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+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 };
|
||||
}
|
||||
// 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) {
|
||||
// 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 };
|
||||
});
|
||||
Vendored
+1265
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user