(function () {
"use strict";
const $ = (selector, root = document) => root.querySelector(selector);
const $$ = (selector, root = document) => [...root.querySelectorAll(selector)];
const familyModels = [
{
id: "user-a",
name: "用户 A",
code: "USER-A",
version: "v1.7",
state: "enabled",
stateLabel: "已启用",
statusNote: "专属模型已启用",
error: 0.18,
samples: 8,
sampleTarget: 11,
sync: "2026.08.14 · 08:29",
errors: [0.50, 0.44, 0.38, 0.32, 0.27, 0.23, 0.20, 0.18],
parameters: [
{ name: "零点偏移补偿", user: "已优化", before: "+0.38", after: "+0.11", progress: 88 },
{ name: "坐姿角度补偿", user: "稳定", before: "0.64", after: "0.91", progress: 91 },
{ name: "压力分布权重", user: "已优化", before: "0.72", after: "0.93", progress: 93 },
{ name: "温度漂移补偿", user: "学习中", before: "42%", after: "76%", progress: 76 },
],
events: [
{ time: "08.14 08:29", title: "模型 v1.7 验证通过并启用", meta: "有效样本 8", result: "±0.22 → ±0.18 kg", state: "已发布" },
{ time: "08.14 08:27", title: "家庭称重与座椅采样配对", meta: "身份匹配成功", result: "采样质量 96%", state: "已进入学习" },
{ time: "08.12 19:06", title: "模型 v1.6 参数更新", meta: "有效样本 7", result: "±0.24 → ±0.22 kg", state: "已验证" },
],
adminReference: "家庭体脂秤 62.40 kg · 座椅估计 62.58 kg",
},
{
id: "user-b",
name: "用户 B",
code: "USER-B",
version: "v1.3",
state: "learning",
stateLabel: "学习中",
statusNote: "4 / 6 个有效样本",
error: 0.31,
samples: 4,
sampleTarget: 6,
sync: "2026.08.13 · 20:18",
errors: [0.50, 0.43, 0.37, 0.31],
parameters: [
{ name: "零点偏移补偿", user: "学习中", before: "+0.41", after: "+0.24", progress: 62 },
{ name: "坐姿角度补偿", user: "学习中", before: "0.61", after: "0.76", progress: 58 },
{ name: "压力分布权重", user: "已优化", before: "0.69", after: "0.82", progress: 70 },
{ name: "温度漂移补偿", user: "等待样本", before: "18%", after: "34%", progress: 34 },
],
events: [
{ time: "08.13 20:22", title: "新参数验证未优于 v1.3,保持旧模型", meta: "本次未参与发布", result: "±0.31 → ±0.34 kg", state: "已回滚", tone: "warning" },
{ time: "08.13 20:19", title: "检测到坐姿不稳定", meta: "异常样本已隔离", result: "采样质量 61%", state: "未参与更新", tone: "warning" },
{ time: "08.10 07:51", title: "第 4 组有效样本完成配对", meta: "身份匹配成功", result: "±0.37 → ±0.31 kg", state: "学习中" },
],
adminReference: "家庭体脂秤 71.25 kg · 异常座椅估计 71.59 kg",
},
{
id: "user-c",
name: "用户 C",
code: "USER-C",
version: "—",
state: "cold",
stateLabel: "冷启动",
statusNote: "等待首次家庭称重",
error: 0.50,
samples: 0,
sampleTarget: 6,
sync: "尚未同步",
errors: [],
parameters: [
{ name: "零点偏移补偿", user: "等待数据", before: "—", after: "—", progress: 0 },
{ name: "坐姿角度补偿", user: "等待数据", before: "—", after: "—", progress: 0 },
{ name: "压力分布权重", user: "等待数据", before: "—", after: "—", progress: 0 },
{ name: "温度漂移补偿", user: "等待数据", before: "—", after: "—", progress: 0 },
],
events: [
{ time: "等待中", title: "尚无可用的车家配对样本", meta: "需要先在家庭体脂秤完成称重", result: "使用通用模型", state: "±0.50 kg" },
],
adminReference: "尚无家庭体脂秤参考值",
},
{
id: "guest",
name: "访客",
code: "GENERIC",
version: "通用",
state: "generic",
stateLabel: "通用模型",
statusNote: "未识别用户使用通用模型",
error: 0.50,
samples: 0,
sampleTarget: 0,
sync: "无需同步",
errors: [0.50],
parameters: [
{ name: "零点偏移补偿", user: "通用参数", before: "0.00", after: "0.00", progress: 50 },
{ name: "坐姿角度补偿", user: "通用参数", before: "0.50", after: "0.50", progress: 50 },
{ name: "压力分布权重", user: "通用参数", before: "0.68", after: "0.68", progress: 50 },
{ name: "温度漂移补偿", user: "通用参数", before: "50%", after: "50%", progress: 50 },
],
events: [
{ time: "当前策略", title: "未识别用户不创建专属模型", meta: "不保存个人参考体重", result: "通用模型基线", state: "±0.50 kg" },
],
adminReference: "访客模式不记录精确体重",
},
];
const systemEntries = [
{
version: "v0.5", date: "2026.08.12", status: "当前版本", title: "统一主题与权限体验",
summary: "把权限、主题与核心交互收束到同一套体验规则,让不同模块看起来、用起来都属于同一个系统。",
changes: [["主题统一", "自扩展固定使用 user 绿色主题,避免权限语义混用。"], ["孪生同步", "3D 模型渲染、玩具动作和车端动作统一跟随当前主题。"], ["能力扩充", "新增自进化入口,让 user 与 admin 共同查看演进过程。"]],
modules: ["自扩展", "数字孪生", "权限体系"], metrics: [["主题一致性", "72%", "100%", 100], ["可见能力模块", "4 个", "5 个", 92], ["待修正视觉项", "4 项", "0 项", 100]],
userValidation: "核心板块已完成主题复核,权限色与交互反馈保持一致。", adminValidation: "前端契约 11/11 · 自标定/自修复检查 8/8",
},
{
version: "v0.4", date: "2026.08.11", status: "稳定版本", title: "自修复闭环增强",
summary: "从发现异常走向诊断、修复与验证闭环,同时补齐离线场景的默认内容,确保功能状态始终可见。",
changes: [["故障覆盖", "补充六类量产故障用例,覆盖更真实的车端异常。"], ["修复闭环", "形成发现、定位、决策、执行、验证五阶段流程。"], ["离线韧性", "服务暂时离线时仍保留默认案例和演示路径。"]],
modules: ["自修复", "故障诊断", "离线体验"], metrics: [["故障用例", "2 类", "6 类", 86], ["修复阶段", "3 阶段", "5 阶段", 92], ["离线可用性", "空白", "可演示", 100]],
userValidation: "断开服务后仍可理解自修复能力,并可继续浏览默认案例。", adminValidation: "默认数据回退、流程状态与接口异常路径均已验证。",
},
{
version: "v0.3", date: "2026.08.10", status: "能力升级", title: "外设与车端统一编排",
summary: "将玩具动作、车端设备动作与数字孪生放进同一个控制流程,减少跨区域理解和操作成本。",
changes: [["动作融合", "玩具动作与车端设备动作进入统一动作界面。"], ["布局优化", "孪生界面位于左侧,动作界面固定在右侧。"], ["映射精简", "移除重复外框,让实时映射关系更直接。"]],
modules: ["自扩展", "外设学习", "整车控制"], metrics: [["动作入口", "2 处", "1 处", 100], ["映射层级", "3 层", "2 层", 88], ["协同对象", "玩具", "玩具 + 车端", 94]],
userValidation: "动作与孪生左右分区清晰,学习结果可以直接用于统一控制。", adminValidation: "外设连接状态、动作映射与车端执行链路保持独立可追踪。",
},
{
version: "v0.2", date: "2026.08.09", status: "体系建立", title: "多权限主题体系",
summary: "建立 user 与 admin 的视觉身份,使权限差异不只体现在可用功能,也能被用户直观感知。",
changes: [["角色主题", "user 使用绿色,admin 使用蓝色,形成稳定的权限认知。"], ["能力边界", "按角色控制模块入口,同时保留清晰的切换反馈。"], ["模型联动", "数字孪生模型与界面主题保持同色语义。"]],
modules: ["权限体系", "主题系统", "数字孪生"], metrics: [["角色主题", "1 套", "2 套", 100], ["权限反馈", "文字", "视觉 + 文字", 90], ["主题联动", "界面", "界面 + 模型", 96]],
userValidation: "绿色主题贯穿 user 可用能力,角色身份更加明确。", adminValidation: "角色切换事件可同步驱动界面变量与模型渲染参数。",
},
{
version: "v0.1", date: "2026.08.08", status: "起点版本", title: "整车认知控制台诞生",
summary: "完成从自然语言意图到整车状态回读的第一条闭环,建立后续能力持续进化的共同底座。",
changes: [["自然语言控制", "用贴近日常表达的指令控制座舱功能。"], ["整车孪生", "把座椅、空调、车窗等状态集中映射到一个界面。"], ["执行回读", "串联 CAN 计划、设备执行与状态反馈。"]],
modules: ["自编排", "数字孪生", "CAN 执行"], metrics: [["能力模块", "0 个", "1 个", 100], ["控制链路", "分散", "闭环", 92], ["状态视图", "单设备", "整车", 96]],
userValidation: "自然语言、执行过程与结果反馈首次形成连续体验。", adminValidation: "意图解析、CAN 编译计划与硬件回读具备完整追踪链路。",
},
];
let playbackTimer = null;
let activeModelId = "user-a";
let visibleSamples = null;
function make(tag, className, html) {
const node = document.createElement(tag);
if (className) node.className = className;
if (html != null) node.innerHTML = html;
return node;
}
function formatError(value) {
return `±${Number(value).toFixed(2)}`;
}
function memberButtons() {
return familyModels.map((model, index) => `
`).join("");
}
function systemVersionButtons() {
return systemEntries.map((entry, index) => `
`).join("");
}
function shellTemplate() {
return `
模型参数持续进化
展示可解释参数状态管理员可见参数前后值与发布保障
`;
}
function summaryTemplate(model, view) {
if (view === "system") {
return `当前版本v0.5能力融合期累计迭代5个版本能力改进12项记录最近更新08.122026`;
}
return `当前用户${model.name}${model.state === "generic" ? "隐私访客模式" : model.statusNote}当前验证误差${formatError(model.error)}kg · 演示数据目标误差±0.10kg有效样本${model.samples}${model.sampleTarget ? `组车家配对` : "无需配对"}`;
}
function chartTemplate(model, count = model.errors.length) {
const values = model.errors.slice(0, count);
const width = 720;
const left = 48;
const right = 698;
const top = 18;
const bottom = 184;
const y = (error) => top + ((0.52 - error) / 0.44) * (bottom - top);
const x = (index) => values.length <= 1 ? left : left + (index / (Math.max(model.errors.length, 2) - 1)) * (right - left);
const grid = [0.5, 0.4, 0.3, 0.2, 0.1].map((error) => `
±${error.toFixed(2)}`).join("");
const points = values.map((error, index) => `${x(index)},${y(error)}`).join(" ");
const circles = values.map((error, index) => `
`).join("");
const labels = model.errors.map((_, index) => `样本${index + 1}`).join("");
const area = values.length > 1 ? `` : "";
const line = values.length > 1 ? `` : "";
const current = values.length ? values[values.length - 1] : null;
return `${values.length ? "" : `等待首组车家配对样本当前继续使用通用模型 ±0.50 kg
`}`;
}
function linkageTemplate(model) {
const baseSteps = [
["家庭体脂秤", "收到用户参考体重"], ["用户 ID 匹配", "家庭账号与车端身份一致"], ["座椅稳定采样", "坐姿、温度、座椅位置质量合格"], ["专属参数更新", "生成候选参数并离线验证"], ["验证并发布", "优于旧模型后正式生效"],
];
let done = model.state === "enabled" ? 5 : model.state === "learning" ? 3 : 0;
if (model.state === "generic") done = 0;
const list = baseSteps.map(([title, copy], index) => {
const state = index < done ? "done" : index === done && model.state === "learning" ? "active" : "pending";
const label = state === "done" ? "已完成" : state === "active" ? "进行中" : "等待";
return `${index + 1}${title}${copy}
${label}`;
}).join("");
const guard = model.id === "user-b"
? `退化保护已触发候选模型误差上升至 ±0.34 kg,已自动回滚并保留 v1.3。
`
: model.state === "enabled"
? `发布保护正常只有验证结果优于当前模型时才会发布新参数。
`
: `专属模型尚未发布样本不足时保持通用模型,不以未验证参数影响称重。
`;
return { list, guard, done };
}
function parameterTemplate(model) {
return model.parameters.map((item) => `
${item.name}${item.user}${item.before}${item.after}
${item.user === "等待数据" ? "等待有效车家样本" : "根据近期有效样本持续校准"}参数窗口 8 组 · 可回滚 · MODEL ${model.version}
`).join("");
}
function eventTemplate(model) {
return model.events.map((event) => `
${event.title}${event.meta}${event.result}${event.state}`).join("");
}
function renderModel(root, modelId, { keepPlayback = false } = {}) {
const model = familyModels.find((item) => item.id === modelId) || familyModels[0];
activeModelId = model.id;
if (!keepPlayback) {
clearInterval(playbackTimer);
playbackTimer = null;
visibleSamples = null;
$("#v2PlayEvolution", root)?.classList.remove("playing");
const playLabel = $("#v2PlayEvolution span", root);
if (playLabel) playLabel.textContent = "演示进化过程";
}
$("#v2EvolutionSummary", root).innerHTML = summaryTemplate(model, "weighing");
$$("[data-family-model]", root).forEach((button) => {
const active = button.dataset.familyModel === model.id;
button.classList.toggle("active", active);
button.setAttribute("aria-pressed", String(active));
});
const badge = $("#v2ModelStateBadge", root);
badge.textContent = model.state === "enabled" ? "专属模型已启用" : model.stateLabel;
badge.dataset.modelState = model.state;
$("#v2ModelCode", root).textContent = `MODEL ${model.version} · ${model.code}`;
$("#v2HomeSyncState", root).textContent = model.state === "generic" ? "访客隐私模式" : model.sync === "尚未同步" ? "等待车家同步" : "车家同步正常";
$("#v2HomeSyncTime", root).textContent = model.sync;
$("#v2ModelTitle", root).textContent = `${model.name} · ${model.state === "generic" ? "通用称重模型" : "个性化称重模型"}`;
$("#v2ModelLead", root).textContent = model.state === "enabled" ? "最近一次家庭参考值与车端座椅采样已完成配对,新参数通过验证并正式生效。" : model.state === "learning" ? "专属参数仍在学习;样本不足或验证退化时,车端继续使用已验证模型。" : model.state === "cold" ? "尚未收到家庭体脂秤参考值,当前安全使用通用模型。" : "未识别用户不会创建个人参数或保存精确体重。";
const play = $("#v2PlayEvolution", root);
play.disabled = model.errors.length < 2;
play.title = play.disabled ? "当前没有可回放的专属模型样本" : "按有效样本顺序回放误差收敛过程";
$("#v2EvolutionChart", root).innerHTML = chartTemplate(model, visibleSamples ?? model.errors.length);
$("#v2SampleInsight", root).textContent = model.errors.length > 1 ? `已从通用模型基线 ±0.50 kg 收敛至 ${formatError(model.error)} kg;点击曲线节点可查看该次样本。` : "个性化模型仅使用身份匹配、时间有效且座椅采样稳定的数据。";
const linkage = linkageTemplate(model);
$("#v2LinkageSteps", root).innerHTML = linkage.list;
$("#v2LinkageGuard", root).innerHTML = linkage.guard;
$("#v2LinkageProgress", root).textContent = `${linkage.done} / 5 已完成`;
$("#v2ParameterGrid", root).innerHTML = parameterTemplate(model);
$("#v2EventList", root).innerHTML = eventTemplate(model);
$("#v2AdminReference", root).textContent = model.adminReference;
const remaining = Math.max(0, model.sampleTarget - model.samples);
const percent = model.sampleTarget ? Math.min(100, Math.round((model.samples / model.sampleTarget) * 100)) : 100;
$("#v2MilestoneCopy", root).textContent = model.state === "generic" ? "访客称重不会进入任何家庭成员的参数空间。" : model.state === "cold" ? "完成家庭体脂秤绑定后,首次有效配对将启动专属模型学习。" : remaining ? `预计再完成 ${remaining} 组有效样本后进入目标精度验证阶段。` : "样本数量已满足要求,正在持续验证 ±0.10 kg 目标。";
$("#v2MilestoneCount", root).textContent = model.sampleTarget ? `${model.samples} / ${model.sampleTarget} 组` : "隐私模式";
$("#v2MilestonePercent", root).textContent = model.sampleTarget ? `当前学习进度 ${percent}%` : "不留存个人数据";
$("#v2MilestoneBar", root).style.width = `${percent}%`;
window.lucide?.createIcons({ attrs: { "aria-hidden": "true" } });
}
function renderSystemEntry(root, index) {
const entry = systemEntries[index];
if (!entry) return;
$("#v2SystemStatus", root).textContent = entry.status;
$("#v2SystemVersion", root).textContent = entry.version;
const date = $("#v2SystemDate", root);
date.textContent = entry.date;
date.dateTime = entry.date.replaceAll(".", "-");
$("#v2SystemTitle", root).textContent = entry.title;
$("#v2SystemLead", root).textContent = entry.summary;
$("#v2SystemChangeList", root).innerHTML = entry.changes.map(([label, copy]) => ``).join("");
$("#v2SystemMetrics", root).innerHTML = entry.metrics.map(([label, before, after, progress]) => `${label}${before}${after}
`).join("");
$("#v2SystemModules", root).innerHTML = entry.modules.map((module) => `${module}`).join("");
$("#v2SystemUserValidation", root).textContent = entry.userValidation;
$("#v2SystemAdminValidation", root).textContent = entry.adminValidation;
$$("[data-system-evolution-index]", root).forEach((button, buttonIndex) => {
const active = buttonIndex === index;
button.classList.toggle("active", active);
button.setAttribute("aria-pressed", String(active));
});
window.lucide?.createIcons({ attrs: { "aria-hidden": "true" } });
}
function setView(root, view) {
const system = view === "system";
clearInterval(playbackTimer);
playbackTimer = null;
$$("[data-evolution-page]", root).forEach((page) => {
const active = page.dataset.evolutionPage === view;
page.classList.toggle("active", active);
page.hidden = !active;
});
$("#v2EvolutionKicker", root).textContent = system ? "SELF-EVOLUTION · SYSTEM JOURNAL" : "SELF-EVOLUTION · SEAT WEIGHING";
$("#v2EvolutionPageTitle", root).textContent = system ? "系统能力日志" : "座椅称重模型进化";
$("#v2EvolutionPageIntro", root).textContent = system ? "保留每次问题发现、能力升级与验证结果,持续记录控制台系统能力演进。" : "通过车家联动持续校准家庭成员专属模型,让称重误差从 ±0.50 kg 逐步收敛至 ±0.10 kg。";
$("#v2EvolutionDataBadge", root).innerHTML = system
? '历史记录'
: '演示数据';
$("#v2EvolutionSummary", root).innerHTML = summaryTemplate(familyModels.find((item) => item.id === activeModelId), view);
const footer = $("#v2EvolutionFooter", root);
footer.hidden = system;
root.dataset.evolutionView = view;
window.dispatchEvent(new CustomEvent("cognitive-agent:evolution-view-change", {
detail: { view },
}));
window.lucide?.createIcons({ attrs: { "aria-hidden": "true" } });
}
function playEvolution(root) {
const model = familyModels.find((item) => item.id === activeModelId);
if (!model || model.errors.length < 2) return;
clearInterval(playbackTimer);
let count = 1;
visibleSamples = count;
const button = $("#v2PlayEvolution", root);
button.classList.add("playing");
$("#v2PlayEvolution span", root).textContent = "正在回放";
renderModel(root, model.id, { keepPlayback: true });
playbackTimer = window.setInterval(() => {
count += 1;
visibleSamples = count;
renderModel(root, model.id, { keepPlayback: true });
if (count >= model.errors.length) {
clearInterval(playbackTimer);
playbackTimer = null;
button.classList.remove("playing");
$("#v2PlayEvolution span", root).textContent = "再次回放";
}
}, 520);
}
function bind(root) {
$(".v2-family-list", root).addEventListener("click", (event) => {
const button = event.target.closest("[data-family-model]");
if (button) renderModel(root, button.dataset.familyModel);
});
$(".v2-evolution-version-list", root).addEventListener("click", (event) => {
const button = event.target.closest("[data-system-evolution-index]");
if (button) renderSystemEntry(root, Number(button.dataset.systemEvolutionIndex));
});
$("#v2PlayEvolution", root).addEventListener("click", () => playEvolution(root));
$("#v2EvolutionChart", root).addEventListener("click", (event) => {
const point = event.target.closest("[data-sample-index]");
const model = familyModels.find((item) => item.id === activeModelId);
if (!point || !model) return;
const index = Number(point.dataset.sampleIndex);
$("#v2SampleInsight", root).textContent = `样本 ${index + 1}:验证误差 ${formatError(model.errors[index])} kg。该节点来自固定演示数据,不代表实时算法结果。`;
});
$("#v2EvolutionChart", root).addEventListener("keydown", (event) => {
if (!["Enter", " "].includes(event.key)) return;
const point = event.target.closest("[data-sample-index]");
if (point) { event.preventDefault(); point.dispatchEvent(new MouseEvent("click", { bubbles: true })); }
});
}
function mount(mainPanel) {
const existing = $("#v2SelfEvolution", mainPanel);
if (existing) return existing;
const evolution = make("section", "v2-self-evolution", shellTemplate());
evolution.id = "v2SelfEvolution";
evolution.dataset.evolutionView = "weighing";
evolution.setAttribute("aria-label", "自进化 · 座椅称重个性化模型进化");
mainPanel.append(evolution);
bind(evolution);
renderModel(evolution, activeModelId);
renderSystemEntry(evolution, 0);
setView(evolution, "weighing");
return evolution;
}
window.CognitiveAgentSelfEvolution = {
mount,
getView: () => $("#v2SelfEvolution")?.dataset.evolutionView || "weighing",
setView: (view) => {
const root = $("#v2SelfEvolution");
if (root) setView(root, view === "system" ? "system" : "weighing");
},
};
}());