优化了副驾座椅控制
This commit is contained in:
+164
-56
@@ -80,8 +80,8 @@
|
||||
const isPassengerSeat = new Set(["passenger", "front-right"]).has(target);
|
||||
if (isPassengerSeat) {
|
||||
const passengerAxes = {
|
||||
"seat.set_longitudinal_position": ["副驾座椅前后调节", "longitudinal", 0],
|
||||
"seat.set_cushion_tilt": ["副驾座椅高度调节", "height", 1],
|
||||
"seat.set_longitudinal_position": ["副驾座椅前后调节", "horizontal", 0],
|
||||
"seat.set_cushion_tilt": ["副驾座椅高度调节", "basin", 1],
|
||||
"seat.set_backrest_recline": ["副驾座椅靠背调节", "backrest", 2],
|
||||
"seat.set_legrest_height": ["副驾座椅腿托调节", "legrest", 3],
|
||||
};
|
||||
@@ -89,13 +89,38 @@
|
||||
const position = boundedInteger(parameters.position_pct, 0, 100);
|
||||
if (axis && position !== null) {
|
||||
const targetPermille = position * 10;
|
||||
const motion = operation.motion || {};
|
||||
const delta = boundedInteger(motion.delta_position_pct, 1, 100);
|
||||
const relativeDirections = {
|
||||
horizontal: { increase: "backward", decrease: "forward" },
|
||||
basin: { increase: "down", decrease: "up" },
|
||||
backrest: { increase: "backward", decrease: "forward" },
|
||||
legrest: { increase: "up", decrease: "down" },
|
||||
};
|
||||
const relativeDirection = relativeDirections[axis[1]]?.[motion.direction];
|
||||
return command(
|
||||
axis[0],
|
||||
`seat passenger ${axis[1]} position ${position}`,
|
||||
motion.mode === "relative" && relativeDirection && delta !== null
|
||||
? `seat passenger ${axis[1]} relative ${relativeDirection} ${delta}`
|
||||
: `seat passenger ${axis[1]} position ${position}`,
|
||||
"CAN0",
|
||||
otaCan0Frame(0x64, axis[2], targetPermille),
|
||||
);
|
||||
}
|
||||
if (new Set(["seat.set_ventilation", "seat.set_heating"]).has(capability)) {
|
||||
const feature = capability === "seat.set_heating" ? "heat" : "vent";
|
||||
const level = boundedInteger(parameters.level, 1, 3);
|
||||
const setting = onOff === "off"
|
||||
? "off"
|
||||
: ({ 1: "low", 2: "medium", 3: "high" })[level];
|
||||
if (setting) {
|
||||
return command(
|
||||
"副驾座椅通风/加热",
|
||||
`seat passenger ${feature} ${setting}`,
|
||||
"CAN0",
|
||||
);
|
||||
}
|
||||
}
|
||||
if (capability === "seat.start_dynamic_mode") {
|
||||
const mode = boundedInteger(parameters.mode_id, 1, 2);
|
||||
if (mode !== null) {
|
||||
@@ -104,7 +129,7 @@
|
||||
: { name: "cradle", selector: 1 };
|
||||
return command(
|
||||
"副驾座椅动态模式",
|
||||
`seat passenger dynamic start ${dynamic.name}`,
|
||||
`seat passenger dynamic ${dynamic.name}`,
|
||||
"CAN0",
|
||||
otaCan0Frame(0x66, dynamic.selector, 300),
|
||||
);
|
||||
@@ -301,7 +326,7 @@
|
||||
<li data-can-channel="${escapeHtml(item.channel)}">
|
||||
<span>
|
||||
<b class="v2-can-command-channel">${escapeHtml(item.channel)}</b>
|
||||
${item.parseSource ? `<b class="v2-can-command-source" data-parse-source="${escapeHtml(item.parseSource)}">${item.parseSource === "local_rule" ? "本地规则" : "云端模型"}</b>` : ""}
|
||||
${item.parseSource ? `<b class="v2-can-command-source" data-parse-source="${escapeHtml(item.parseSource)}">${item.parseSource === "direct_control" ? "设备控件" : item.parseSource === "local_rule" ? "本地规则" : "云端模型"}</b>` : ""}
|
||||
${escapeHtml(item.category)}
|
||||
</span>
|
||||
<code>${escapeHtml(item.command)}</code>
|
||||
@@ -313,6 +338,30 @@
|
||||
requestAnimationFrame(syncSidebarLogBaseline);
|
||||
}
|
||||
|
||||
function renderDirectCanCommands(commands, deviceName) {
|
||||
const panel = $("#v2CanCommandPanel");
|
||||
const list = $("#v2CanCommandList");
|
||||
const count = $("#v2CanCommandCount");
|
||||
if (!panel || !list || !count) return;
|
||||
const items = commands.map((command) => ({
|
||||
channel: command.startsWith("seat passenger ") ? "CAN0" : "CAN1",
|
||||
command,
|
||||
}));
|
||||
count.textContent = String(items.length);
|
||||
panel.dataset.state = "ready";
|
||||
list.innerHTML = `<ol>${items.map((item) => `
|
||||
<li data-can-channel="${item.channel}">
|
||||
<span>
|
||||
<b class="v2-can-command-channel">${item.channel}</b>
|
||||
<b class="v2-can-command-source" data-parse-source="direct_control">设备控件</b>
|
||||
${escapeHtml(deviceName)}
|
||||
</span>
|
||||
<code>${escapeHtml(item.command)}</code>
|
||||
</li>`).join("")}</ol>`;
|
||||
validatedCommandsVisible = true;
|
||||
requestAnimationFrame(syncSidebarLogBaseline);
|
||||
}
|
||||
|
||||
function closeReasoningPicker() {
|
||||
reasoningPickerControl?.close();
|
||||
}
|
||||
@@ -620,7 +669,7 @@
|
||||
function seatLevelControlValue(seat, feature) {
|
||||
const text = seatFunctionValue(seat, feature);
|
||||
const level = text.match(/L(\d+)/i)?.[1];
|
||||
return /OFF|关闭|--/.test(text) ? "off" : level || "1";
|
||||
return /OFF|关闭|--/.test(text) ? "off" : level === "2" ? "low" : "high";
|
||||
}
|
||||
|
||||
function massageReadout() {
|
||||
@@ -632,34 +681,31 @@
|
||||
}
|
||||
|
||||
const levelOptions = [
|
||||
["off", "关闭"], ["1", "1 档"], ["2", "2 档"], ["3", "3 档"],
|
||||
["off", "关闭"], ["high", "1 档(高)"], ["low", "2 档(低)"],
|
||||
];
|
||||
const toggleOptions = [["off", "关闭"], ["on", "开启"]];
|
||||
const massageModeOptions = [
|
||||
["off", "关闭"], ["relax", "舒缓"], ["stretch", "伸展"], ["waist", "腰部"], ["wave", "波浪"],
|
||||
["off", "关闭"], ["relax", "放松"], ["stretch", "伸展"], ["slack", "松弛"], ["wave", "波浪"], ["pulse", "脉冲"],
|
||||
];
|
||||
const massageStrengthOptions = [
|
||||
["off", "关闭"], ["low", "低"], ["medium", "中"], ["high", "高"],
|
||||
["off", "关闭"], ["weak", "低"], ["medium", "中"], ["strong", "高"],
|
||||
];
|
||||
const colorIndexNames = ["皓月白", "冰川蓝", "松石绿", "星云紫", "琥珀橙", "玫瑰红"];
|
||||
const colorIndexOptions = Array.from({ length: 16 }, (_item, index) => [
|
||||
String(index), colorIndexNames[index] ? `${index} · ${colorIndexNames[index]}` : `色号 ${index}`,
|
||||
const colorIndexOptions = Array.from({ length: 127 }, (_item, index) => [
|
||||
String(index + 1), colorIndexNames[index] ? `${index + 1} · ${colorIndexNames[index]}` : `色号 ${index + 1}`,
|
||||
]);
|
||||
|
||||
const rangeControl = (key, label, value, min = 0, max = 100, step = 1, unit = "%", hint = "") => ({
|
||||
key, label, type: "range", value: clampControlNumber(value, min, max), min, max, step, unit, hint,
|
||||
});
|
||||
const selectControl = (key, label, value, options) => ({ key, label, type: "select", value, options });
|
||||
const hasControlValue = (values, key) => Object.hasOwn(values, key);
|
||||
|
||||
function deviceControlValue(deviceId, control) {
|
||||
const draft = displaySync.deviceDrafts[deviceId];
|
||||
return draft && Object.hasOwn(draft, control.key) ? draft[control.key] : control.value;
|
||||
}
|
||||
|
||||
function optionLabel(options, value) {
|
||||
return options.find(([optionValue]) => String(optionValue) === String(value))?.[1] || String(value);
|
||||
}
|
||||
|
||||
const syncedDevices = [
|
||||
{
|
||||
id: "passenger", name: "副驾座椅", icon: "armchair",
|
||||
@@ -670,7 +716,13 @@
|
||||
rangeControl("backrest_recline", "靠背", seatAxisValue("passenger", "backrest_recline")),
|
||||
rangeControl("legrest_height", "腿托", seatAxisValue("passenger", "legrest_height")),
|
||||
],
|
||||
command: (values) => `调节副驾座椅:前后${values.longitudinal}%,座椅高度${values.cushion_tilt}%,靠背${values.backrest_recline}%,腿托${values.legrest_height}%`,
|
||||
commands: (values) => [
|
||||
["longitudinal", "horizontal"],
|
||||
["cushion_tilt", "basin"],
|
||||
["backrest_recline", "backrest"],
|
||||
["legrest_height", "legrest"],
|
||||
].filter(([key]) => hasControlValue(values, key))
|
||||
.map(([key, axis]) => `seat passenger ${axis} position ${Math.round(Number(values[key]))}`),
|
||||
},
|
||||
{
|
||||
id: "driver", name: "主驾座椅", icon: "armchair",
|
||||
@@ -687,7 +739,22 @@
|
||||
selectControl("massage_strength", "按摩强度", /关闭|--/.test(massageStrength) ? "off" : massageStrength.toLowerCase(), massageStrengthOptions),
|
||||
];
|
||||
},
|
||||
command: (values) => `调节主驾座椅:通风${optionLabel(levelOptions, values.ventilation)},加热${optionLabel(levelOptions, values.heating)},按摩模式${optionLabel(massageModeOptions, values.massage_mode)},按摩强度${optionLabel(massageStrengthOptions, values.massage_strength)}`,
|
||||
commands: (values) => {
|
||||
const commands = [];
|
||||
if (hasControlValue(values, "ventilation")) commands.push(`seat driver vent ${values.ventilation}`);
|
||||
if (hasControlValue(values, "heating")) commands.push(`seat driver heat ${values.heating}`);
|
||||
if (hasControlValue(values, "massage_mode")) {
|
||||
commands.push(values.massage_mode === "off"
|
||||
? "seat driver massage off"
|
||||
: `seat driver massage mode ${values.massage_mode}`);
|
||||
}
|
||||
if (hasControlValue(values, "massage_strength")) {
|
||||
commands.push(values.massage_strength === "off"
|
||||
? "seat driver massage off"
|
||||
: `seat driver massage strength ${values.massage_strength}`);
|
||||
}
|
||||
return [...new Set(commands)];
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "windows", name: "车窗", icon: "gallery-vertical-end",
|
||||
@@ -698,19 +765,24 @@
|
||||
rangeControl("rear_left", "左后窗", readText("#rearLeftWindow")),
|
||||
rangeControl("rear_right", "右后窗", readText("#rearRightWindow")),
|
||||
],
|
||||
command: (values) => `调节车窗开合比例:左前窗${values.front_left}%,右前窗${values.front_right}%,左后窗${values.rear_left}%,右后窗${values.rear_right}%`,
|
||||
commands: (values) => Object.entries({
|
||||
front_left: "front-left", front_right: "front-right", rear_left: "rear-left", rear_right: "rear-right",
|
||||
}).filter(([key]) => hasControlValue(values, key))
|
||||
.map(([key, target]) => `window ${target} position ${Math.round(Number(values[key]))}`),
|
||||
},
|
||||
{
|
||||
id: "shade", name: "遮阳帘", icon: "panels-top-left",
|
||||
rows: () => [["当前位置", readText("#shadePositionValue")]],
|
||||
controls: () => [rangeControl("position", "当前位置", readText("#shadePositionValue"), 0, 100, 1, "%", "0% 关闭 · 100% 打开")],
|
||||
command: (values) => `将遮阳帘开合位置调整为${values.position}%`,
|
||||
commands: (values) => hasControlValue(values, "position")
|
||||
? [`shade position ${Math.round(Number(values.position))}`]
|
||||
: [],
|
||||
},
|
||||
{
|
||||
id: "reading", name: "阅读灯", icon: "book-open",
|
||||
rows: () => [["开关状态", readText("#interiorLightPower", "等待反馈")]],
|
||||
controls: () => [selectControl("power", "开关状态", /开启|ON/.test(readText("#interiorLightPower")) ? "on" : "off", toggleOptions)],
|
||||
command: (values) => `${values.power === "on" ? "打开" : "关闭"}阅读灯`,
|
||||
commands: (values) => hasControlValue(values, "power") ? [`light reading all ${values.power}`] : [],
|
||||
},
|
||||
{
|
||||
id: "ambient", name: "氛围灯", icon: "sparkles",
|
||||
@@ -724,31 +796,39 @@
|
||||
const [frontColor, rearColor] = splitReadout("#ambientColorIndex");
|
||||
return [
|
||||
selectControl("power", "开关状态", /OFF|关闭/.test(readText("#ambientPower")) ? "off" : "on", toggleOptions),
|
||||
rangeControl("front_brightness", "前排亮度", frontBrightness, 0, 5, 1, " 级"),
|
||||
selectControl("front_color", "前排颜色", String(clampControlNumber(frontColor, 0, 15, 0)), colorIndexOptions),
|
||||
rangeControl("rear_brightness", "后排亮度", rearBrightness, 0, 5, 1, " 级"),
|
||||
selectControl("rear_color", "后排颜色", String(clampControlNumber(rearColor, 0, 15, 0)), colorIndexOptions),
|
||||
rangeControl("brightness", "全车亮度", frontBrightness === "-" ? rearBrightness : frontBrightness, 1, 5, 1, " 级"),
|
||||
selectControl("color", "全车颜色", String(clampControlNumber(frontColor === "-" ? rearColor : frontColor, 1, 127, 1)), colorIndexOptions),
|
||||
];
|
||||
},
|
||||
command: (values) => `调节氛围灯:${values.power === "on" ? "开启" : "关闭"},前排亮度${values.front_brightness}级、颜色${optionLabel(colorIndexOptions, values.front_color)},后排亮度${values.rear_brightness}级、颜色${optionLabel(colorIndexOptions, values.rear_color)}`,
|
||||
commands: (values) => [
|
||||
...(hasControlValue(values, "power") ? [`light ambient ${values.power}`] : []),
|
||||
...(hasControlValue(values, "brightness") ? [`light ambient brightness ${Math.round(Number(values.brightness))}`] : []),
|
||||
...(hasControlValue(values, "color") ? [`light ambient color ${Math.round(Number(values.color))}`] : []),
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "headlight", name: "前大灯", icon: "car-front",
|
||||
controllable: false,
|
||||
rows: () => [["近光灯", readText("#lowBeamState")], ["远光灯", readText("#highBeamState")], ["雾灯", readText("#fogLightState")], ["转向灯", readText("#turnSignalState")]],
|
||||
controls: () => [["low_beam", "近光灯", "#lowBeamState"], ["high_beam", "远光灯", "#highBeamState"], ["fog_light", "雾灯", "#fogLightState"], ["turn_signal", "转向灯", "#turnSignalState"]].map(([key, label, selector]) => selectControl(key, label, /开启|ON/.test(readText(selector)) ? "on" : "off", toggleOptions)),
|
||||
command: (values) => `调节前大灯:近光灯${optionLabel(toggleOptions, values.low_beam)},远光灯${optionLabel(toggleOptions, values.high_beam)},雾灯${optionLabel(toggleOptions, values.fog_light)},转向灯${optionLabel(toggleOptions, values.turn_signal)}`,
|
||||
},
|
||||
{
|
||||
id: "climate", name: "空调", icon: "fan",
|
||||
rows: () => [["开关状态", readText("#climatePower", "等待反馈")], ["主驾温度", readText("#driverTemperature")], ["副驾温度", readText("#passengerTemperature")], ["风量", readText("#fanLevel")], ["循环模式", readText("#cycleMode")]],
|
||||
controls: () => [
|
||||
selectControl("power", "开关状态", /ON|ACTIVE|开启/.test(readText("#climatePower")) ? "on" : "off", toggleOptions),
|
||||
rangeControl("driver_temperature", "主驾温度", readText("#driverTemperature"), 16, 32, 0.5, "℃"),
|
||||
rangeControl("passenger_temperature", "副驾温度", readText("#passengerTemperature"), 16, 32, 0.5, "℃"),
|
||||
rangeControl("fan_level", "风量", readText("#fanLevel"), 0, 7, 1, " 档"),
|
||||
rangeControl("driver_temperature", "主驾温度", Math.round(clampControlNumber(readText("#driverTemperature"), 18, 32, 24)), 18, 32, 1, "℃"),
|
||||
rangeControl("passenger_temperature", "副驾温度", Math.round(clampControlNumber(readText("#passengerTemperature"), 18, 32, 24)), 18, 32, 1, "℃"),
|
||||
rangeControl("fan_level", "风量", readText("#fanLevel"), 1, 7, 1, " 档"),
|
||||
selectControl("cycle_mode", "循环模式", readText("#cycleMode").includes("内") ? "internal" : "external", [["internal", "内循环"], ["external", "外循环"]]),
|
||||
],
|
||||
command: (values) => `调节空调:${values.power === "on" ? "开启" : "关闭"},主驾${values.driver_temperature}℃,副驾${values.passenger_temperature}℃,风量${values.fan_level}档,${values.cycle_mode === "internal" ? "内循环" : "外循环"}`,
|
||||
commands: (values) => [
|
||||
...(hasControlValue(values, "power") ? [`ac ${values.power}`] : []),
|
||||
...(hasControlValue(values, "driver_temperature") ? [`ac temp driver ${Math.round(Number(values.driver_temperature))}`] : []),
|
||||
...(hasControlValue(values, "passenger_temperature") ? [`ac temp passenger ${Math.round(Number(values.passenger_temperature))}`] : []),
|
||||
...(hasControlValue(values, "fan_level") ? [`ac fan ${Math.round(Number(values.fan_level))}`] : []),
|
||||
...(hasControlValue(values, "cycle_mode") ? [`ac cycle ${values.cycle_mode}`] : []),
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -771,7 +851,8 @@
|
||||
grid.innerHTML = syncedDevices.map((device) => {
|
||||
const rows = device.rows();
|
||||
const waiting = rows.some(([, value]) => /--|等待|同步中|未知/.test(value));
|
||||
const controlOpen = displaySync.controlDevice === device.id;
|
||||
const controllable = device.controllable !== false;
|
||||
const controlOpen = controllable && displaySync.controlDevice === device.id;
|
||||
const hasDraft = Boolean(displaySync.deviceDrafts[device.id]);
|
||||
const pending = Boolean(displaySync.pendingControls[device.id]);
|
||||
const stateLabel = pending ? "已发送 · 等待同步" : hasDraft ? "参数待发送" : `${rows.length} 项关键状态`;
|
||||
@@ -780,13 +861,13 @@
|
||||
<button class="v2-device-card-focus" type="button" data-device-focus="${device.id}" aria-label="在孪生界面查看${device.name}">
|
||||
<span><i data-lucide="${device.icon}"></i></span><span><strong>${device.name}</strong><small data-device-card-state>${stateLabel}</small></span><i class="v2-device-signal"></i>
|
||||
</button>
|
||||
<button class="v2-device-adjust-toggle" type="button" data-device-control-toggle="${device.id}" aria-expanded="${String(controlOpen)}"><i data-lucide="sliders-horizontal"></i><span>${controlOpen ? "收起" : "调节"}</span></button>
|
||||
<button class="v2-device-adjust-toggle" type="button" data-device-control-toggle="${device.id}" aria-expanded="${String(controlOpen)}"${controllable ? "" : " disabled"}><i data-lucide="${controllable ? "sliders-horizontal" : "eye"}"></i><span>${controllable ? (controlOpen ? "收起" : "调节") : "只读"}</span></button>
|
||||
</header>
|
||||
<dl>${rows.map(([label, value]) => `<div><dt>${escapeHtml(label)}</dt><dd>${escapeHtml(value)}</dd></div>`).join("")}</dl>
|
||||
<div class="v2-device-controls" data-device-controls="${device.id}"${controlOpen ? "" : " hidden"}>
|
||||
<div class="v2-device-controls-intro"><span>手动调节</span><small>参数确认后通过编排链路发送至车机</small></div>
|
||||
${device.controls().map((control) => renderDeviceControl(device, control)).join("")}
|
||||
<button class="v2-device-control-apply" type="button" data-device-control-apply="${device.id}"${pending ? " disabled" : ""}><i data-lucide="send"></i><span>${pending ? "等待车机同步" : "发送控制"}</span></button>
|
||||
<button class="v2-device-control-apply" type="button" data-device-control-apply="${device.id}"${pending || !hasDraft ? " disabled" : ""}><i data-lucide="send"></i><span>${pending ? "等待车机同步" : hasDraft ? "发送 CAN 控制" : "请先修改参数"}</span></button>
|
||||
</div>
|
||||
</article>`;
|
||||
}).join("");
|
||||
@@ -817,28 +898,68 @@
|
||||
}));
|
||||
}
|
||||
|
||||
function sendDeviceControl(deviceId) {
|
||||
async function sendDeviceControl(deviceId) {
|
||||
const device = syncedDevices.find((item) => item.id === deviceId);
|
||||
if (!device) return;
|
||||
const values = Object.fromEntries(device.controls().map((control) => [control.key, String(deviceControlValue(device.id, control))]));
|
||||
const utterance = device.command(values);
|
||||
if (device.controllable === false || typeof device.commands !== "function") {
|
||||
window.CognitiveAgentConsole?.notify?.(`${device.name}当前只有状态反馈,尚无已验证的 CAN 控制白名单`);
|
||||
return;
|
||||
}
|
||||
const draft = displaySync.deviceDrafts[device.id];
|
||||
if (!draft || !Object.keys(draft).length) {
|
||||
window.CognitiveAgentConsole?.notify?.("请先修改需要发送的参数");
|
||||
return;
|
||||
}
|
||||
if (displaySync.pendingControls[device.id]) {
|
||||
window.CognitiveAgentConsole?.notify?.("该设备的上一组 CAN 指令仍在执行");
|
||||
return;
|
||||
}
|
||||
const values = Object.fromEntries(Object.entries(draft).map(([key, value]) => [key, String(value)]));
|
||||
const commands = device.commands(values).filter(Boolean);
|
||||
if (!commands.length) {
|
||||
window.CognitiveAgentConsole?.notify?.("修改项没有对应的 CAN 白名单控制指令");
|
||||
return;
|
||||
}
|
||||
const commandSummary = commands.join(";");
|
||||
const detail = {
|
||||
device_id: device.id,
|
||||
device_name: device.name,
|
||||
controls: values,
|
||||
utterance,
|
||||
can_commands: commands,
|
||||
source: "web_console",
|
||||
requested_at: new Date().toISOString(),
|
||||
};
|
||||
window.dispatchEvent(new CustomEvent("cognitive-agent:vehicle-control-request", { detail }));
|
||||
const accepted = window.CognitiveAgentConsole?.executeUtterance?.(utterance, { autoSubmit: true }) || false;
|
||||
if (!accepted) {
|
||||
window.CognitiveAgentConsole?.notify?.("上一条指令仍在执行,请稍候");
|
||||
const execute = window.CognitiveAgentConsole?.executeCanCommands;
|
||||
if (typeof execute !== "function") {
|
||||
window.CognitiveAgentConsole?.notify?.("当前页面尚未加载 CAN 直控接口");
|
||||
return;
|
||||
}
|
||||
displaySync.pendingControls[device.id] = utterance;
|
||||
appendSyncLog({ category: "device", title: `网页端调节${device.name}`, detail: utterance, status: "info" });
|
||||
window.dispatchEvent(new CustomEvent("cognitive-agent:vehicle-can-control-request", { detail }));
|
||||
displaySync.pendingControls[device.id] = commandSummary;
|
||||
appendSyncLog({ category: "device", title: `网页端直控${device.name}`, detail: commandSummary, status: "info" });
|
||||
renderDirectCanCommands(commands, device.name);
|
||||
renderSyncedDevices();
|
||||
try {
|
||||
await execute(commands, { deviceName: device.name });
|
||||
delete displaySync.deviceDrafts[device.id];
|
||||
appendSyncLog({
|
||||
category: "device",
|
||||
title: `${device.name} CAN 控制已执行`,
|
||||
detail: commandSummary,
|
||||
status: "success",
|
||||
});
|
||||
} catch (error) {
|
||||
appendSyncLog({
|
||||
category: "device",
|
||||
title: `${device.name} CAN 控制发送失败`,
|
||||
detail: error?.message || "CAN 控制请求失败",
|
||||
status: "error",
|
||||
});
|
||||
window.CognitiveAgentConsole?.notify?.(error?.message || "CAN 控制请求失败");
|
||||
} finally {
|
||||
delete displaySync.pendingControls[device.id];
|
||||
renderSyncedDevices();
|
||||
}
|
||||
}
|
||||
|
||||
function scheduleSyncedDeviceRender() {
|
||||
@@ -1389,19 +1510,6 @@
|
||||
});
|
||||
});
|
||||
window.addEventListener("cognitive-agent:request-complete", (event) => {
|
||||
const pendingDevice = Object.entries(displaySync.pendingControls).find(([, utterance]) => utterance === event.detail?.utterance)?.[0];
|
||||
if (pendingDevice) {
|
||||
const device = syncedDevices.find((item) => item.id === pendingDevice);
|
||||
delete displaySync.pendingControls[pendingDevice];
|
||||
if (!event.detail?.error) delete displaySync.deviceDrafts[pendingDevice];
|
||||
appendSyncLog({
|
||||
category: "device",
|
||||
title: event.detail?.error ? `${device?.name || "设备"}控制发送失败` : `${device?.name || "设备"}控制已执行`,
|
||||
detail: event.detail?.error?.message || "控制结果已进入车机状态同步链路",
|
||||
status: event.detail?.error ? "error" : "success",
|
||||
});
|
||||
renderSyncedDevices();
|
||||
}
|
||||
if (event.detail?.error && !validatedCommandsVisible) {
|
||||
renderParsedCanCommands(null, { message: "本次请求未生成 CAN 控制指令" });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user