learningos / index.html
YVES28's picture
Upload folder using huggingface_hub
e665390 verified
Raw History Blame Contribute Delete
36.9 kB
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>LearningOS V3.0 · 儿童学习能力 AI 操作系统</title>
<script src="https://cdn.plot.ly/plotly-2.35.2.min.js" charset="utf-8"></script>
<style>
:root{
--blue:#2E86DE; --blue-d:#1f5fa8; --bg:#f5f8fc; --card:#fff;
--line:#e2e8f0; --text:#1f2d3d; --muted:#6b7a8d; --red:#E74C3C; --green:#27ae60;
}
*{box-sizing:border-box}
body{margin:0;font-family:-apple-system,"PingFang SC","Microsoft YaHei",Segoe UI,Roboto,sans-serif;
background:var(--bg);color:var(--text);line-height:1.6}
header{background:linear-gradient(135deg,var(--blue),var(--blue-d));color:#fff;padding:18px 24px}
header h1{margin:0;font-size:20px}
header p{margin:4px 0 0;font-size:13px;opacity:.9}
.tabs{display:flex;flex-wrap:wrap;background:#fff;border-bottom:1px solid var(--line)}
.tab{padding:12px 16px;cursor:pointer;font-size:14px;color:var(--muted);border-bottom:3px solid transparent}
.tab.active{color:var(--blue);border-bottom-color:var(--blue);font-weight:600}
.page{display:none;padding:20px 24px;max-width:980px;margin:0 auto}
.page.active{display:block}
.card{background:var(--card);border:1px solid var(--line);border-radius:10px;padding:16px 18px;margin-bottom:16px;
box-shadow:0 1px 3px rgba(0,0,0,.04)}
h2{font-size:18px;margin:0 0 10px}
h3{font-size:15px;margin:14px 0 6px;color:var(--blue-d)}
label{display:block;font-size:13px;margin:10px 0 4px;color:var(--text)}
.row{display:flex;gap:14px;flex-wrap:wrap}
.row > *{flex:1;min-width:200px}
button{background:var(--blue);color:#fff;border:none;padding:10px 18px;border-radius:8px;
font-size:14px;cursor:pointer;margin-top:10px}
button:hover{background:var(--blue-d)}
button.ghost{background:#fff;color:var(--blue);border:1px solid var(--blue)}
.opt{display:flex;gap:8px;flex-wrap:wrap;margin:6px 0}
.opt label{margin:0;padding:6px 12px;border:1px solid var(--line);border-radius:20px;cursor:pointer;font-size:13px}
.opt input{display:none}
.opt input:checked + span{font-weight:600}
.opt label:has(input:checked){background:var(--blue);color:#fff;border-color:var(--blue)}
input[type=number],textarea,select{width:100%;padding:8px 10px;border:1px solid var(--line);border-radius:8px;font-size:14px}
.pill{display:inline-block;padding:2px 10px;border-radius:12px;font-size:12px;background:#eef4fb;color:var(--blue)}
.warn{color:var(--red);font-weight:600}
.ok{color:var(--green);font-weight:600}
.muted{color:var(--muted);font-size:13px}
.plot{width:100%;height:440px}
details{border:1px solid var(--line);border-radius:8px;padding:8px 12px;margin:10px 0;background:#fff}
summary{cursor:pointer;font-weight:600;font-size:14px}
.banner{background:#fff7e6;border:1px solid #ffe1a8;color:#8a5a00;padding:10px 14px;border-radius:8px;font-size:13px;margin-bottom:14px}
.qcard{border:1px solid var(--line);border-radius:8px;padding:10px 12px;margin:8px 0}
pre{white-space:pre-wrap;word-break:break-word;background:#f8fafc;border:1px solid var(--line);padding:12px;border-radius:8px;font-size:13px}
table{width:100%;border-collapse:collapse;font-size:13px;margin-top:6px}
th,td{border:1px solid var(--line);padding:6px 8px;text-align:left}
th{background:#f1f6fc}
</style>
</head>
<body>
<header>
<h1>🧠 LearningOS V3.0 — 儿童学习能力 AI 操作系统(原型演示)</h1>
<p>AI筛查 · 能力评估 · 学习数字孪生 · 智能解释(LearningGPT) · 个性化干预 · 报告导出</p>
</header>
<div class="tabs" id="tabs">
<div class="tab active" data-t="home">🏠 概览</div>
<div class="tab" data-t="screen">🔍 AI 筛查</div>
<div class="tab" data-t="assess">📝 能力评估</div>
<div class="tab" data-t="twin">👤 学习数字孪生</div>
<div class="tab" data-t="explain">🤖 智能解释</div>
<div class="tab" data-t="intervene">🎯 个性化干预</div>
<div class="tab" data-t="report">📤 报告导出</div>
</div>
<!-- 概览 -->
<div class="page active" id="home">
<div class="banner">⚠️ 本应用为<b>演示原型</b>:题目、常模、算法均为平台自研原创演示内容,<b>不构成任何临床或教育诊断结论</b>。WIAT-III/WISC-V 仅作为维度设计的学术参考框架。</div>
<div class="card">
<h2>平台定位</h2>
<p>基于儿童神经发育科学 + AI 主动智能体 + 多模态行为分析 + 标准化学习能力评估体系 + 数字化干预,
打造覆盖 <b>AI筛查—能力评估—智能解释—个性化干预—家庭管理—医疗协同—科研数据库</b> 的儿童学习脑健康数字生态平台。</p>
<h3>可体验的完整闭环</h3>
<ol>
<li><b>AI 筛查</b>:家长/教师 8 项行为问卷 → 风险预警</li>
<li><b>能力评估</b>:自研分测验(阅读/数学/语言/书写/执行功能)→ 组合分标准分</li>
<li><b>学习数字孪生</b>:10 维能力雷达 + 成长时间轴 + 6 个月趋势投影</li>
<li><b>智能解释 LearningGPT</b>:可解释地追溯底层认知因素,支持问答</li>
<li><b>个性化干预</b>:自适应干预引擎(ZPD 动态调参)</li>
<li><b>报告导出</b>:面向医/教/家三端的报告</li>
</ol>
<button id="demoBtn">🚀 一键加载演示档案(快速体验)</button>
<button class="ghost" id="resetBtn">🧹 清空并重新开始</button>
<p class="muted" id="homeStatus">尚未生成画像,请先完成筛查与评估,或点击一键演示。</p>
</div>
</div>
<!-- AI 筛查 -->
<div class="page" id="screen">
<div class="card">
<h2>AI 筛查(家长/教师版)</h2>
<p class="muted">请按孩子近一个月的真实表现评分:1=从不,5=总是</p>
<div id="screenItems"></div>
<button id="saveScreen">保存筛查结果</button>
<div id="screenOut" class="muted"></div>
</div>
</div>
<!-- 能力评估 -->
<div class="page" id="assess">
<div class="card">
<h2>能力评估(自研分测验)</h2>
<p class="muted">完成以下任务,系统将计算分测验 → 组合分标准分(均值100 / 标准差15)。</p>
<details open><summary>📖 阅读理解</summary>
<p id="rcPassage" class="muted"></p>
<div id="rcQuestions"></div>
</details>
<details open><summary>🔢 数学计算</summary>
<div id="mcQuestions"></div>
</details>
<details open><summary>🧩 数学应用</summary>
<div id="maQuestions"></div>
</details>
<details open><summary>🔤 词汇</summary>
<div id="vocQuestions"></div>
</details>
<details open><summary>✏️ 句子结构</summary>
<div id="sentQuestions"></div>
</details>
<details><summary>🔡 字词识读(自评)</summary>
<label>能流利识读以下 16 个字的数量:<span id="wrVal">12</span></label>
<input type="range" id="wordReading" min="0" max="16" value="12" />
<p class="muted" id="wrChars"></p>
</details>
<details><summary>✍️ 书写流畅(自评)</summary>
<label>抄写参考句耗时(秒)</label>
<input type="number" id="writtenSec" value="45" />
<p class="muted" id="wfPrompt"></p>
</details>
<details><summary>🟥 Stroop 抑制控制(自评)</summary>
<p class="muted" id="stroopDemo"></p>
<label>正确点击数 (0-10):<span id="scVal">8</span></label>
<input type="range" id="stroopCorrect" min="0" max="10" value="8" />
<label>平均反应时 (ms)</label>
<input type="number" id="stroopRt" value="900" />
</details>
<details><summary>🎯 CPT 持续注意(自评)</summary>
<p class="muted" id="cptDemo"></p>
<label>漏点 X 的次数 (0-4):<span id="coVal">1</span></label>
<input type="range" id="cptOmis" min="0" max="4" value="1" />
<label>误点非 X 的次数 (0-10):<span id="ccVal">1</span></label>
<input type="range" id="cptComm" min="0" max="10" value="1" />
</details>
<button id="submitAssess">📊 提交并生成能力画像</button>
<div id="assessOut"></div>
</div>
</div>
<!-- 数字孪生 -->
<div class="page" id="twin">
<div class="card">
<h2>学习数字孪生 (Learning Digital Twin)</h2>
<label><input type="checkbox" id="intervene" checked /> 已启动自适应干预(影响未来斜率)</label>
<div class="row">
<div><div id="radar" class="plot"></div></div>
<div><div id="timeline" class="plot"></div></div>
</div>
<button id="refreshTwin">🔄 刷新数字孪生</button>
<p class="muted" id="twinHint"></p>
</div>
</div>
<!-- 智能解释 -->
<div class="page" id="explain">
<div class="card">
<h2>智能解释 · LearningGPT(可解释 AI)</h2>
<div id="exSummary"></div>
<hr/>
<label>向 LearningGPT 提问(如:为什么孩子阅读理解下降?)</label>
<textarea id="exQuestion" rows="2" placeholder="输入您关心的问题…"></textarea>
<button id="askBtn">💡 获取解释</button>
<div id="exAnswer" style="margin-top:10px"></div>
</div>
</div>
<!-- 个性化干预 -->
<div class="page" id="intervene">
<div class="card">
<h2>个性化干预(自适应干预引擎)</h2>
<button id="ivBtn">🔄 生成/刷新干预方案</button>
<div id="ivPlan" style="margin-top:10px"></div>
</div>
</div>
<!-- 报告导出 -->
<div class="page" id="report">
<div class="card">
<h2>报告导出(医/教/家三端)</h2>
<button id="rpBtn">📄 生成报告</button>
<button class="ghost" id="rpDownload">⬇️ 下载报告 (.md)</button>
<button class="ghost" id="rpPrint">🖨️ 打印 / 另存 PDF</button>
<div id="rpMD" style="margin-top:12px"></div>
</div>
</div>
<script>
/* ===================== 数据与常模(自研原创演示) ===================== */
const SS_MEAN=100, SS_SD=15, SCALED_MEAN=10, SCALED_SD=3;
const AGE_BANDS=["4-6岁(幼小衔接)","7-9岁(小学低段)","10-12岁(小学高段)","13-15岁(初中)"];
const DIMENSIONS=[
["info","基础信息",false],["neuro","神经发育",true],["cognitive","认知能力",true],
["language","语言沟通",true],["reading","阅读素养",true],["math","数学计算",true],
["executive","执行功能",true],["family","家庭环境",false],["school","学校表现",false],
["ai_history","AI训练历史",false]
];
const COMPOSITES={
reading:{name:"阅读素养 (Reading)",subtests:["word_reading","reading_comp"]},
math:{name:"数学能力 (Math)",subtests:["math_calc","math_applied"]},
written:{name:"书写表达 (Written)",subtests:["written_fluency"]},
oral:{name:"口头语言 (Oral Language)",subtests:["vocabulary","sentence"]},
executive:{name:"执行功能/注意力 (Executive)",subtests:["stroop","cpt"]}
};
const ITEMS={
reading_comp:{
passage:"小猫和小狗是好朋友。一天,它们一起去公园玩球。小狗把球抛得很高,小猫跳起来接住了。回家的路上,下起了小雨,它们躲进树叶下,开心地笑了。",
questions:[
{q:"谁把球抛得很高?",options:["小猫","小狗","小鸟"],answer:1},
{q:"它们为什么躲起来?",options:["累了","下雨了","天黑了"],answer:1},
{q:"这个故事主要讲什么?",options:["两个朋友玩耍","下雨天真好","接球比赛"],answer:0}
]},
math_calc:{problems:[
{q:"12 + 7 = ?",answer:19},{q:"35 - 18 = ?",answer:17},{q:"6 × 8 = ?",answer:48},
{q:"72 ÷ 9 = ?",answer:8},{q:"45 + 29 = ?",answer:74}]},
math_applied:{questions:[
{q:"小明有8颗糖,妈妈又给了5颗,他现在有几颗?",options:["12","13","14"],answer:1},
{q:"一盒铅笔有12支,平均分给3个同学,每人几支?",options:["3","4","6"],answer:1}]},
vocabulary:{questions:[
{q:"「迅速」的意思最接近?",options:["快速","缓慢","安静"],answer:0},
{q:"「美丽」的意思最接近?",options:["好看","难看","高大"],answer:0},
{q:"「寒冷」的意思最接近?",options:["冷","热","甜"],answer:0},
{q:"「巨大」的意思最接近?",options:["大","小","轻"],answer:0}]},
sentence:{questions:[
{q:"下列哪个句子语序正确?",options:["我吃饭了","饭吃了我","吃了饭我"],answer:0},
{q:"「因为…所以…」使用正确的是?",options:["因为下雨,所以比赛取消","因为比赛取消,所以下雨","下雨因为,所以取消"],answer:0},
{q:"量词使用正确的是?",options:["一只猫","一条猫","一个猫"],answer:0}]},
word_reading:{chars:["蝴","蝶","螃","蟹","蘑","菇","蜻","蜓","鸬","鹚","鼹","鼠","蜈","蚣","蝙","蝠"]},
written_fluency:{prompt:"今天天气真好,我们去公园放风筝。",ref:16},
stroop:{stimuli:[["红","绿"],["蓝","红"],["绿","蓝"],["黄","红"],["红","蓝"],["绿","黄"],["蓝","绿"],["黄","绿"],["红","黄"],["绿","红"]],colors:["红","绿","蓝","黄"]},
cpt:{sequence:["K","J","F","X","L","S","D","X","P","A","X","M","R","T","X","B","N","X","C","V"],target:"X"}
};
const SCREENING=[
{q:"写作业时容易分心、走神",domain:"attention"},
{q:"阅读时经常跳行、漏字或重复读",domain:"reading"},
{q:"记不住多步口头指令",domain:"executive"},
{q:"完成功课极慢,明显超出同龄人",domain:"speed"},
{q:"数学计算常因粗心出错",domain:"math"},
{q:"字迹潦草、握笔姿势别扭",domain:"written"},
{q:"遇到挫折容易情绪波动",domain:"emotion"},
{q:"与同伴交往存在困难",domain:"social"}
];
const SCREEN_DOMAINS=["attention","reading","executive","speed","math","written","emotion","social"];
const DOMAIN_CN={attention:"注意力",reading:"阅读",executive:"执行功能",speed:"加工速度",math:"数学",written:"书写",emotion:"情绪",social:"社交"};
const FACTOR_MAP={
reading:{low_word_high_comp:["工作记忆负载 (Working Memory Load)","字词识读尚可但阅读理解偏弱,提示信息保持与整合环节负载阶段性超载,而非识字能力本身倒退。"],
general:["阅读流畅性与解码效率","阅读相关分测验整体处于临界区间,建议优先排查视觉-语音转换与眼动回视模式。"]},
math:["计算策略表型与程序性知识","数学分测验偏低,常见瓶颈为计算策略固化与工作记忆在多位运算中的负载。"],
written:["精细动作与加工速度","书写流畅性偏弱,通常与手部精细动作协调及视觉-动作整合速度相关。"],
oral:["词汇提取与句法工作记忆","口头语言分测验反映词汇量与句法工作记忆,偏低时影响课堂理解与表达。"],
executive:["抑制控制与持续注意","执行功能/注意力分测验提示抑制控制或持续注意存在波动,易表现为分心与冲动。"]
};
const MODULE_CATALOG={
"工作记忆负载 (Working Memory Load)":{module:"工作记忆双任务训练",modality:"Child APP · 游戏化(数字广度+视觉矩阵)",freq:"每周 4 次",dur:"每次 12 分钟",goal:"提升信息保持与整合容量,缓解阅读理解加工瓶颈"},
"阅读流畅性与解码效率":{module:"眼动-语音整合训练",modality:"Child APP · 眼动追踪+跟读",freq:"每周 5 次",dur:"每次 10 分钟",goal:"降低回视概率、提升阅读流畅性"},
"计算策略表型与程序性知识":{module:"计算策略多样化训练",modality:"Child APP · 分步解题+策略提示",freq:"每周 4 次",dur:"每次 15 分钟",goal:"丰富计算策略、降低程序性错误"},
"精细动作与加工速度":{module:"书写自动化训练",modality:"Child APP · 压感笔迹+抄写节奏",freq:"每周 3 次",dur:"每次 10 分钟",goal:"提升书写速率与视觉-动作整合"},
"词汇提取与句法工作记忆":{module:"语义网络拓展训练",modality:"Child APP · 词汇联想+造句",freq:"每周 3 次",dur:"每次 12 分钟",goal:"扩充词汇量与句法工作记忆"},
"抑制控制与持续注意":{module:"Go/No-Go 与持续注意训练",modality:"Child APP · 反应抑制+信号检测",freq:"每周 5 次",dur:"每次 8 分钟",goal:"提升抑制控制与持续注意力时长"}
};
/* ===================== 工具函数 ===================== */
const clamp=(v,lo=1,hi=19)=>Math.max(lo,Math.min(hi,v));
function classifySS(ss){if(ss>=115)return"高于平均";if(ss>=85)return"平均水平";if(ss>=70)return"临界偏低";return"显著偏低";}
function scaledFromCorrect(correct,total){if(total<=0)return 10;const center=total/2;return clamp(Math.round(SCALED_MEAN+(correct-center)/center*SCALED_SD));}
function compositeSS(list){if(!list.length)return 100;const avg=list.reduce((a,b)=>a+b,0)/list.length;return Math.round(SS_MEAN+(avg-SCALED_MEAN)*(SS_SD/SCALED_SD));}
function readingFactor(profile){
const sub=profile.sub_scaled||{};const wr=sub.word_reading,rc=sub.reading_comp;const rd=FACTOR_MAP.reading;
if(wr!=null&&rc!=null&&wr-rc>=2)return rd.low_word_high_comp;return rd.general;
}
function factorOf(key,profile){
const f=FACTOR_MAP[key];
if(Array.isArray(f))return f;
if(f&&typeof f==="object")return readingFactor(profile);
return ["待评估因素",""];
}
/* ===================== 状态 ===================== */
let state={profile:null,screening:{},meta:{name:"待测儿童",age_band:AGE_BANDS[1]}};
/* ===================== 页面切换 ===================== */
document.querySelectorAll('.tab').forEach(t=>t.onclick=()=>{
document.querySelectorAll('.tab').forEach(x=>x.classList.remove('active'));
document.querySelectorAll('.page').forEach(x=>x.classList.remove('active'));
t.classList.add('active');
document.getElementById(t.dataset.t).classList.add('active');
if(t.dataset.t==="twin")refreshTwin();
});
/* ===================== 构建评估 UI ===================== */
function buildAssessUI(){
document.getElementById('rcPassage').textContent="短文:"+ITEMS.reading_comp.passage;
const rc=document.getElementById('rcQuestions');
ITEMS.reading_comp.questions.forEach((q,i)=>{
rc.appendChild(qCard(`阅读 ${i+1}. ${q.q}`,q.options,`rc${i}`));
});
const mc=document.getElementById('mcQuestions');
ITEMS.math_calc.problems.forEach((p,i)=>{
const d=document.createElement('div');d.className='qcard';
d.innerHTML=`<label>计算 ${i+1}. ${p.q}</label><input type="number" id="mc${i}" />`;
mc.appendChild(d);
});
const ma=document.getElementById('maQuestions');
ITEMS.math_applied.questions.forEach((q,i)=>ma.appendChild(qCard(`应用 ${i+1}. ${q.q}`,q.options,`ma${i}`)));
const voc=document.getElementById('vocQuestions');
ITEMS.vocabulary.questions.forEach((q,i)=>voc.appendChild(qCard(`词汇 ${i+1}. ${q.q}`,q.options,`voc${i}`)));
const sent=document.getElementById('sentQuestions');
ITEMS.sentence.questions.forEach((q,i)=>sent.appendChild(qCard(`句子 ${i+1}. ${q.q}`,q.options,`sent${i}`)));
document.getElementById('wrChars').textContent="演示字表:"+ITEMS.word_reading.chars.join("、");
document.getElementById('wfPrompt').textContent="参考句:"+ITEMS.written_fluency.prompt;
document.getElementById('stroopDemo').textContent="演示刺激(字≠墨色),需点击墨色:"+
ITEMS.stroop.stimuli.map(s=>`${s[0]}(墨:${s[1]})`).join("、");
document.getElementById('cptDemo').textContent="刺激序列(出现 X 需点击):"+ITEMS.cpt.sequence.join(" ");
// 滑块实时数值
bindRange('wordReading','wrVal');bindRange('stroopCorrect','scVal');
bindRange('cptOmis','coVal');bindRange('cptComm','ccVal');
}
function qCard(title,options,name){
const d=document.createElement('div');d.className='qcard';
let html=`<label>${title}</label><div class="opt">`;
options.forEach((o,i)=>{html+=`<label><input type="radio" name="${name}" value="${i}"><span>${o}</span></label>`;});
html+='</div>';d.innerHTML=html;return d;
}
function bindRange(id,lab){const el=document.getElementById(id);el.oninput=()=>document.getElementById(lab).textContent=el.value;}
/* ===================== 筛查 UI ===================== */
function buildScreenUI(){
const box=document.getElementById('screenItems');
SCREENING.forEach((it,i)=>{
const d=document.createElement('div');d.className='qcard';
let opts='';for(let v=1;v<=5;v++)opts+=`<label><input type="radio" name="scr${i}" value="${v}" ${v===3?'checked':''}><span>${v}</span></label>`;
d.innerHTML=`<label>${i+1}. ${it.q}</label><div class="opt">${opts}</div>`;
box.appendChild(d);
});
}
/* ===================== 评分 ===================== */
function getRadio(name){const el=document.querySelector(`input[name="${name}"]:checked`);return el?parseInt(el.value):null;}
function scoreScreening(){
const ratings={};
SCREENING.forEach((it,i)=>{const v=getRadio(`scr${i}`);if(v)ratings[it.domain]=ratings[it.domain]||[];if(v)ratings[it.domain].push(v);});
const out={};
SCREEN_DOMAINS.forEach(dom=>{const vals=ratings[dom]||[];const avg=vals.length?vals.reduce((a,b)=>a+b,0)/vals.length:0;out[dom]={avg:Math.round(avg*100)/100,flag:avg>=4};});
return out;
}
function buildProfile(responses){
const sub={};
// 阅读
const rcA=ITEMS.reading_comp.questions.map(q=>q.answer);
sub.reading_comp=scaledFromCorrect(rcA.filter((a,i)=>a===responses.rc[i]).length,rcA.length);
sub.word_reading=scaledFromCorrect(responses.wordReading,16);
// 数学
const mcA=ITEMS.math_calc.problems.map(p=>String(p.answer));
const mcCorrect=mcA.filter((a,i)=>String(responses.mc[i])===a).length;
let sCalc=scaledFromCorrect(mcCorrect,5);
const per=responses.mcTime/5;if(per<4)sCalc=clamp(sCalc+1);else if(per>9)sCalc=clamp(sCalc-1);
sub.math_calc=sCalc;
const maA=ITEMS.math_applied.questions.map(q=>q.answer);
sub.math_applied=scaledFromCorrect(maA.filter((a,i)=>a===responses.ma[i]).length,maA.length);
// 词汇/句子
const vocA=ITEMS.vocabulary.questions.map(q=>q.answer);
sub.vocabulary=scaledFromCorrect(vocA.filter((a,i)=>a===responses.voc[i]).length,vocA.length);
const sentA=ITEMS.sentence.questions.map(q=>q.answer);
sub.sentence=scaledFromCorrect(sentA.filter((a,i)=>a===responses.sent[i]).length,sentA.length);
// 书写
const elapsed=responses.writtenSec||45;const cpm=16/(elapsed/60);
sub.written_fluency=clamp(Math.round(SCALED_MEAN+(cpm-22)/22*SCALED_SD*3));
// Stroop / CPT
sub.stroop=clamp(13-responses.stroopErrors*2-(responses.stroopRt>1500?1:0));
sub.cpt=clamp(13-(responses.cptOmis+responses.cptComm)*2);
const composites={};
for(const k in COMPOSITES){const scales=COMPOSITES[k].subtests.map(s=>sub[s]);const ss=compositeSS(scales);
composites[k]={name:COMPOSITES[k].name,ss,level:classifySS(ss),subtests:Object.fromEntries(COMPOSITES[k].subtests.map(s=>[s,sub[s]]))};}
const dim={};DIMENSIONS.forEach(d=>dim[d[0]]=null);
dim.reading=composites.reading.ss;dim.math=composites.math.ss;dim.language=composites.oral.ss;
dim.executive=composites.executive.ss;dim.cognitive=Math.round((composites.written.ss+composites.executive.ss)/2);
dim.neuro=dim.cognitive;dim.family=72;dim.school=68;dim.ai_history=25;dim.info=100;
return {meta:state.meta,sub_scaled:sub,composites,dim_scores:dim,screening:state.screening};
}
function demoProfile(){
const base={reading:78,math:96,written:92,oral:104,executive:88};
const composites={};
for(const k in base){const ss=Math.max(60,Math.min(130,base[k]+(Math.random()*12-6)|0));composites[k]={name:COMPOSITES[k].name,ss,level:classifySS(ss)};}
const dim={};DIMENSIONS.forEach(d=>dim[d[0]]=null);
dim.reading=composites.reading.ss;dim.math=composites.math.ss;dim.language=composites.oral.ss;
dim.executive=composites.executive.ss;dim.cognitive=composites.written.ss;dim.neuro=composites.written.ss;
dim.family=72;dim.school=68;dim.ai_history=25;dim.info=100;
const scr={};SCREEN_DOMAINS.forEach(d=>{const avg=Math.round((2+Math.random()*2.6)*100)/100;scr[d]={avg,flag:avg>=4};});
scr.reading={avg:4.3,flag:true};scr.attention={avg:4.1,flag:true};
return {meta:{name:"演示儿童",age_band:AGE_BANDS[1],demo:true},sub_scaled:{},composites,dim_scores:dim,screening:scr};
}
/* ===================== 数字孪生 ===================== */
function ssToIndex(ss){return Math.max(0,Math.min(100,(ss-60)/(130-60)*100));}
function normalizedDims(p){const d=p.dim_scores||{};const o={};DIMENSIONS.forEach(([k,_,ab])=>{const v=d[k];if(v==null){o[k]=50;return;}o[k]=ab?ssToIndex(v):Math.max(0,Math.min(100,v));});return o;}
function refreshTwin(){
if(!state.profile||!state.profile.composites){document.getElementById('twinHint').textContent="请先生成能力画像(评估页或一键演示)。";return;}
const nd=normalizedDims(state.profile);
const labels=DIMENSIONS.map(d=>d[1]);const vals=DIMENSIONS.map(d=>nd[d[0]]);
Plotly.newPlot('radar',[{type:'scatterpolar',r:[...vals,vals[0]],theta:[...labels,labels[0]],fill:'toself',
name:'当前能力画像',line:{color:'#2E86DE'},fillcolor:'rgba(46,134,222,0.25)'},
{type:'scatterpolar',r:Array(labels.length+1).fill(65),theta:[...labels,labels[0]],name:'同龄参考',line:{color:'#888',dash:'dot'}}],
{polar:{radialaxis:{visible:true,range:[0,100]}},showlegend:true,height:430,
margin:{l:40,r:40,t:30,b:30},legend:{orientation:'h',y:-0.15}});
// 时间轴
const intervene=document.getElementById('intervene').checked;
const abilityKeys=DIMENSIONS.filter(d=>d[2]).map(d=>d[0]);
const base=abilityKeys.reduce((a,k)=>a+nd[k],0)/abilityKeys.length;
const scr=state.profile.screening||{};const readingFlag=scr.reading&&scr.reading.flag;
const aiHist=state.profile.dim_scores.ai_history||25;
let drift=0.15;if(aiHist>=40)drift+=0.25;if(readingFlag&&!intervene)drift-=0.35;if(intervene)drift+=0.45;
const past=[];let val=base;for(let i=12;i>0;i--){val+=0.2+(Math.random()*2-1)*1.2;past.push(Math.round(val*10)/10);}
const future=[];val=base;for(let i=1;i<=26;i++){val+=drift+(Math.random()*2-1)*0.6;future.push(Math.max(0,Math.min(100,val)));}
const weeks=[];for(let i=-12;i<0;i++)weeks.push(i);weeks.push(0);for(let i=1;i<=26;i++)weeks.push(i);
const series=[...past,base,...future];const upper=[],lower=[];
weeks.forEach(w=>{const band=w<=0?1.5:1.5+w*0.25;upper.push(Math.min(100,series[weeks.indexOf(w)]+band));lower.push(Math.max(0,series[weeks.indexOf(w)]-band));});
const traces=[
{x:weeks,y:upper,mode:'lines',line:{width:0},showlegend:false,hoverinfo:'skip'},
{x:weeks,y:lower,mode:'lines',line:{width:0},fill:'tonexty',fillcolor:'rgba(46,134,222,0.15)',name:'不确定区间',hoverinfo:'skip'}
];
weeks.forEach((w,i)=>{const phase=w<0?'历史':(w===0?'当前':'预测');if(!traces.find(t=>t.name===phase))traces.push({x:[weeks[i]],y:[series[i]],mode:'lines+markers',name:phase,line:{color:{历史:'#95A5A6',当前:'#E74C3C',预测:'#2E86DE'}[phase],width:3},marker:{size:5}});else{const t=traces.find(t=>t.name===phase);t.x.push(weeks[i]);t.y.push(series[i]);}});
Plotly.newPlot('timeline',traces,{title:`学习成长时间轴 · 6个月预测斜率≈${drift>=0?'+':''}${drift.toFixed(2)}/周${intervene?' · 已启动自适应干预':' · 未干预'}`,
xaxis:{title:'周(负数=过去,正数=未来)'},yaxis:{title:'综合能力指数',range:[0,100]},height:430,
legend:{orientation:'h',y:-0.25},margin:{l:40,r:40,t:50,b:40}});
document.getElementById('twinHint').textContent="数字孪生已更新。";
}
/* ===================== 解释 ===================== */
function analyze(p){
const comps=p.composites||{};const scr=p.screening||{};const findings=[];const risks=[];const strengths=[];
for(const k in comps){const c=comps[k];if(c.ss<85){const[fname,fdesc]=factorOf(k,p);findings.push({dimension:c.name,ss:c.ss,level:c.level,factor:fname,detail:fdesc});risks.push(c.name);}else if(c.ss>=110)strengths.push(c.name);}
const flags=SCREEN_DOMAINS.filter(d=>scr[d]&&scr[d].flag).map(d=>DOMAIN_CN[d]);
const n=findings.length;
const overall=n===0?"当前各项能力处于平均水平或更高,未见明显偏低组合分,建议保持规律随访与能力拓展。":`共发现 ${n} 项能力组合分处于临界/显著偏低区间,主要关注:${risks.join("、")}。`;
let summary=`【总体结论】${overall}\n\n【能力组合分】\n`;
for(const k in comps)summary+=`· ${comps[k].name}:标准分 ${comps[k].ss}(${comps[k].level})\n`;
summary+=`\n【筛查预警】${flags.length?'存在:'+flags.join("、"):'无明显预警信号'}\n`;
summary+=`【相对优势】${strengths.length?strengths.join("、"):'暂未显现明显优势项'}`;
return {overall,findings,risks,strengths,flags,summary};
}
function explainQuestion(p,q){
if(!q)return "请输入您关心的问题。";
const a=analyze(p);const comps=p.composites||{};let target=null;
if(/阅读|理解|识字|读书/.test(q))target="reading";
else if(/数学|计算|应用题/.test(q))target="math";
else if(/写字|书写|字迹|握笔/.test(q))target="written";
else if(/注意|分心|专注|走神|冲动/.test(q))target="executive";
else if(/语言|表达|说话|词汇/.test(q))target="oral";
if(!target)return "我结合孩子的多模态能力画像为您解读:\n\n"+a.overall+"\n\n您可以就具体维度继续追问,例如:「为什么孩子阅读理解下降?」「数学计算总粗心怎么办?」「注意力为什么不持久?」";
const c=comps[target]||{};const[fname,fdesc]=factorOf(target,p);
return `关于您提到的「${COMPOSITES[target].name}」问题:\n\n系统追踪到该维度标准分为 **${c.ss}(${c.level})**。\n底层认知因素指向 **${fname}**:${fdesc}\n\n💡 建议:基于上述机制,可优先安排针对性的认知训练模块(如工作记忆/抑制控制/加工速度训练),并在家庭端降低任务时长、提升即时反馈频率,使孩子始终处于最优学习发展区(ZPD)。`;
}
/* ===================== 干预 ===================== */
function recommend(p){
const a=analyze(p);const aiHist=(p.dim_scores||{}).ai_history||25;const mods=[];const seen=new Set();
a.findings.forEach(f=>{const factor=f.factor;if(MODULE_CATALOG[factor]&&!seen.has(factor)){seen.add(factor);const m={...MODULE_CATALOG[factor]};
if(aiHist>=40)m.adapt="既往完成度高,初始难度上调一档,步进更快";
else if(aiHist<20)m.adapt="训练史较短,从基础档起步,强化即时反馈与激励";
else m.adapt="维持标准难度曲线,按实时表现动态变频";
m.target=f.dimension;mods.push(m);}});
if(!mods.length)mods.push({module:"能力拓展与预防训练",modality:"Child APP · 综合游戏化挑战",freq:"每周 2 次",dur:"每次 10 分钟",goal:"巩固优势、预防能力滑坡",adapt:"无显著风险,维持拓展性训练",target:"综合"});
return mods;
}
function planHTML(p){
const mods=recommend(p);let h='<h3>个性化干预方案(自适应)</h3>';
mods.forEach((m,i)=>{h+=`<p><b>${i+1}. ${m.module}</b> → 目标维度:${m.target}</p>
<p class="muted">干预形态:${m.modality} | 频次/时长:${m.freq} · ${m.dur}</p>
<p class="muted">训练目标:${m.goal}</p><p class="muted">自适应策略:${m.adapt}</p>`;});
return h;
}
/* ===================== 报告 ===================== */
function genMarkdown(p){
const meta=p.meta||{};const a=analyze(p);const d=p.dim_scores||{};const scr=p.screening||{};
let md=`# 儿童学习能力评估与干预报告(LearningOS V3.0 原型)\n\n`;
md+=`## 一、基本信息\n- 姓名/代号:${meta.name||'—'}\n- 年龄段:${meta.age_band||'—'}\n- 报告性质:演示原型(非诊断)\n\n`;
md+=`## 二、能力组合分(Subtests → Composites)\n| 组合分 | 标准分 | 等级 |\n| --- | --- | --- |\n`;
for(const k in p.composites)md+=`| ${p.composites[k].name} | ${p.composites[k].ss} | ${p.composites[k].level} |\n`;
md+=`\n## 三、学习数字孪生 · 十维画像\n| 维度 | 指数/分值 |\n| --- | --- |\n`;
DIMENSIONS.forEach(dm=>md+=`| ${dm[1]} | ${d[dm[0]]??'—'} |\n`);
md+=`\n## 四、AI 筛查预警\n| 维度 | 平均分(1-5) | 状态 |\n| --- | --- | --- |\n`;
SCREEN_DOMAINS.forEach(dom=>{const v=scr[dom];md+=`| ${DOMAIN_CN[dom]} | ${v?v.avg:'—'} | ${v&&v.flag?'⚠️ 预警':'正常'} |\n`;});
md+=`\n## 五、智能解释(LearningGPT)\n${a.summary}\n\n## 六、个性化干预方案\n`;
recommend(p).forEach((m,i)=>{md+=`### ${i+1}. ${m.module} → ${m.target}\n- 形态:${m.modality}\n- 频次/时长:${m.freq} · ${m.dur}\n- 目标:${m.goal}\n- 自适应:${m.adapt}\n`;});
md+=`\n---\n> ⚠️ 本报告显示范性原型输出,所用题目、常模与算法均为平台自研演示内容,不构成任何临床诊断或教育鉴定结论。WIAT-III/WISC-V 仅作为维度设计的学术参考框架。`;
return md;
}
/* ===================== 事件绑定 ===================== */
function syncAll(p,statusText){
if(!p||!p.composites){document.getElementById('twinHint').textContent="请先生成能力画像。";
document.getElementById('exSummary').textContent="请先生成能力画像。";document.getElementById('ivPlan').textContent="请先生成能力画像。";return;}
document.getElementById('exSummary').textContent=analyze(p).summary;
document.getElementById('ivPlan').innerHTML=planHTML(p);refreshTwin();
}
document.getElementById('demoBtn').onclick=()=>{state.profile=demoProfile();document.getElementById('homeStatus').textContent="✅ 已加载演示档案,请前往『学习数字孪生 / 智能解释 / 个性化干预 / 报告导出』查看。";syncAll(state.profile);};
document.getElementById('resetBtn').onclick=()=>{state.profile=null;document.getElementById('homeStatus').textContent="已清空,请重新评估。";syncAll(null);};
document.getElementById('saveScreen').onclick=()=>{state.screening=scoreScreening();let h='<h3>筛查结果</h3>';SCREEN_DOMAINS.forEach(d=>{const v=state.screening[d];h+=`<p>${DOMAIN_CN[d]}:均分 ${v.avg} → ${v.flag?'<span class="warn">⚠️ 预警</span>':'<span class="ok">✅ 正常</span>'}</p>`;});document.getElementById('screenOut').innerHTML=h;};
document.getElementById('submitAssess').onclick=()=>{
const responses={rc:ITEMS.reading_comp.questions.map((_,i)=>getRadio(`rc${i}`)),
mc:ITEMS.math_calc.problems.map((_,i)=>document.getElementById(`mc${i}`).value),mcTime:30,
ma:ITEMS.math_applied.questions.map((_,i)=>getRadio(`ma${i}`)),
voc:ITEMS.vocabulary.questions.map((_,i)=>getRadio(`voc${i}`)),
sent:ITEMS.sentence.questions.map((_,i)=>getRadio(`sent${i}`)),
wordReading:parseInt(document.getElementById('wordReading').value),
writtenSec:parseFloat(document.getElementById('writtenSec').value)||45,
stroopErrors:10-parseInt(document.getElementById('stroopCorrect').value),
stroopRt:parseFloat(document.getElementById('stroopRt').value)||900,
cptOmis:parseInt(document.getElementById('cptOmis').value),
cptComm:parseInt(document.getElementById('cptComm').value)};
state.profile=buildProfile(responses);
let h='<h3>✅ 能力画像已生成(组合分标准分,均值100/标准差15)</h3><ul>';
for(const k in state.profile.composites)h+=`<li><b>${state.profile.composites[k].name}</b>:${state.profile.composites[k].ss}(${state.profile.composites[k].level})</li>`;
h+='</ul>';document.getElementById('assessOut').innerHTML=h;syncAll(state.profile);
};
document.getElementById('refreshTwin').onclick=refreshTwin;
document.getElementById('askBtn').onclick=()=>{if(!state.profile){document.getElementById('exAnswer').textContent="请先生成能力画像再提问。";return;}document.getElementById('exAnswer').textContent=explainQuestion(state.profile,document.getElementById('exQuestion').value);};
document.getElementById('ivBtn').onclick=()=>{if(!state.profile){document.getElementById('ivPlan').textContent="请先生成能力画像。";return;}document.getElementById('ivPlan').innerHTML=planHTML(state.profile);};
let lastMD="";
document.getElementById('rpBtn').onclick=()=>{if(!state.profile){document.getElementById('rpMD').textContent="请先生成能力画像。";return;}lastMD=genMarkdown(state.profile);document.getElementById('rpMD').textContent=lastMD;};
document.getElementById('rpDownload').onclick=()=>{if(!lastMD)lastMD=genMarkdown(state.profile);const blob=new Blob([lastMD],{type:'text/markdown'});const a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='LearningOS_报告.md';a.click();};
document.getElementById('rpPrint').onclick=()=>{const w=window.open();w.document.write('<pre>'+genMarkdown(state.profile).replace(/</g,'&lt;')+'</pre>');w.document.close();w.print();};
/* ===================== 初始化 ===================== */
buildAssessUI();buildScreenUI();
</script>
</body>
</html>