优化后端和前端

This commit is contained in:
minghanchen
2026-08-24 14:15:53 +08:00
parent 8d05815773
commit 33c92d1352
27 changed files with 2328 additions and 234 deletions
+153 -42
View File
@@ -7023,14 +7023,14 @@ function renderExecution(result) {
const operationResults = report.spec.results.filter((item) => item.ref !== "seat-controller-firmware");
const succeededOperations = operationResults.filter((item) => item.status === "succeeded");
const failedOperations = operationResults.filter((item) => item.status === "failed");
const mqttPublishedOperations = operationResults.filter(
(item) => item.telemetry?.delivery_status === "published",
const mqttSubmittedOperations = operationResults.filter(
(item) => ["queued", "published"].includes(item.telemetry?.delivery_status),
);
const physicallyConfirmedOperations = operationResults.filter(
(item) => item.telemetry?.physical_effect_confirmed === true,
);
const mqttPublishedUnconfirmed = result.control_transport === "wireless_mqtt"
&& mqttPublishedOperations.length > physicallyConfirmedOperations.length;
&& mqttSubmittedOperations.length > physicallyConfirmedOperations.length;
const succeededDomains = [...new Set(succeededOperations.map((item) => item.domain))];
const failedDomains = [...new Set(failedOperations.map((item) => item.domain))];
let executionDetail = modeSave
@@ -7041,7 +7041,7 @@ function renderExecution(result) {
? `${executedDomains.join(" / ")} 已完成隔离 HIL 仿真,未访问物理 CAN`
: physical
? result.control_transport === "wireless_mqtt"
? `${executedDomains.join(" / ")} 已通过 MQTT 发布 ${mqttPublishedOperations.length || succeededOperations.length} 个白名单控制步骤${mqttPublishedUnconfirmed ? ";车辆效果尚未确认,以状态话题回读为准" : `,并确认 ${physicallyConfirmedOperations.length || succeededOperations.length} 个车辆状态`}`
? `${executedDomains.join(" / ")} 已向 MQTT 提交 ${mqttSubmittedOperations.length || succeededOperations.length} 个白名单控制步骤${mqttPublishedUnconfirmed ? ";车辆效果尚未确认,以状态话题回读为准" : `,并确认 ${physicallyConfirmedOperations.length || succeededOperations.length} 个车辆状态`}`
: selectedVehicleTransport()?.target_policy === "ch1_body_can_driver_only"
? `${executedDomains.join(" / ")} 已通过 CH1 下发,并以车端状态字段确认 ${operationResults.filter((item) => item.status === "succeeded").length} 个步骤`
: `${executedDomains.join(" / ")} 已下发真实 CAN,并以 IAR 固件实际反馈确认 ${operationResults.filter((item) => item.status === "succeeded").length} 个步骤`
@@ -7081,7 +7081,7 @@ function renderExecution(result) {
: presetSave ? "姿态预设已保存"
: simulatedHil ? "模拟台架执行成功"
: physical
? mqttPublishedUnconfirmed ? "MQTT 指令已发布" : "真实台架执行成功"
? mqttPublishedUnconfirmed ? "MQTT 指令已提交" : "真实台架执行成功"
: "虚拟执行成功"
: partiallySucceeded ? (physical ? "真实台架部分执行成功" : "部分执行成功")
: simulatedHil ? "模拟故障已触发" : physical ? "真实台架执行失败" : "虚拟执行失败";
@@ -7091,7 +7091,7 @@ function renderExecution(result) {
summary.innerHTML = `<i data-lucide="${executionIcon}"></i><div><strong>${executionTitle}</strong><span>${executionDetail}</span></div>`;
$("#resultNavMeta").textContent = reportSucceeded
? mqttPublishedUnconfirmed
? `${mqttPublishedOperations.length} 项已发布 · MQTT`
? `${mqttSubmittedOperations.length} 项已提交 · MQTT`
: `${report.spec.results.length} 项完成 · ${simulatedHil ? "SIM-HIL" : physical ? "HIL" : "DRY-RUN"}`
: partiallySucceeded ? `${succeededOperations.length} 项成功 / ${failedOperations.length} 项失败 · 查看明细`
: "执行失败 · 查看回读";
@@ -7251,7 +7251,7 @@ function renderResult(result) {
const feedbackSource = result.execution_report?.metadata?.labels?.seat_feedback;
const mqttPublishedUnconfirmed = result.control_transport === "wireless_mqtt"
&& (result.execution_report?.spec?.results || []).some(
(item) => item.telemetry?.delivery_status === "published"
(item) => ["queued", "published"].includes(item.telemetry?.delivery_status)
&& item.telemetry?.physical_effect_confirmed !== true,
);
if (feedbackSource === "simulated_hardware") {
@@ -7291,7 +7291,7 @@ function renderResult(result) {
: result.scene_config
? `${domains.length} 域场景闭环完成`
: mqttPublishedUnconfirmed
? `${domainLabels[domains[0]] || "车舱"}控制指令已发布`
? `${domainLabels[domains[0]] || "车舱"}控制指令已提交`
: `${domainLabels[domains[0]] || "车舱"}单域闭环完成`
: "请求未执行";
const conversationLabel = result.conversation_id?.slice(-8) || "no-context";
@@ -7324,6 +7324,67 @@ function renderResult(result) {
window.dispatchEvent(new CustomEvent("cognitive-agent:result", { detail: result }));
}
async function postControlPhase(path, body, executionMode, onEvent = null) {
const streaming = typeof onEvent === "function";
const response = await apiRequest(path, {
method: "POST",
timeoutMs: requestTimeoutForExecutionMode(executionMode),
headers: {
"Content-Type": "application/json",
...(streaming ? { Accept: "application/x-ndjson" } : {}),
},
body: JSON.stringify(body),
});
if (response.status === 401) {
window.location.replace("/login");
return null;
}
if (streaming && response.ok && response.body?.getReader) {
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffered = "";
let resultPayload = null;
const handleLine = (line) => {
if (!line.trim()) return;
const phaseEvent = JSON.parse(line);
if (phaseEvent.type === "error") {
const requestError = new Error(
phaseEvent.message || phaseEvent.error || "流式控制请求失败",
);
requestError.code = phaseEvent.error;
requestError.retryAfter = Number(phaseEvent.retry_after_seconds || 0);
throw requestError;
}
if (phaseEvent.type === "result") {
resultPayload = phaseEvent.payload;
} else {
onEvent(phaseEvent);
}
};
while (true) {
const { value, done } = await reader.read();
buffered += decoder.decode(value || new Uint8Array(), { stream: !done });
const lines = buffered.split("\n");
buffered = lines.pop() || "";
lines.forEach(handleLine);
if (done) break;
}
if (buffered.trim()) handleLine(buffered);
if (!resultPayload) throw new Error("流式控制请求未返回完整结果");
return resultPayload;
}
const payload = await response.json();
if (!response.ok) {
const requestError = new Error(payload.message || payload.error || `HTTP ${response.status}`);
requestError.code = payload.error;
requestError.retryAfter = Number(
payload.retry_after_seconds || response.headers.get("Retry-After") || 0,
);
throw requestError;
}
return payload;
}
async function submitRequest(event) {
event.preventDefault();
const utterance = $("#utterance").value.trim();
@@ -7360,39 +7421,89 @@ async function submitRequest(event) {
setRunStatus("processing", "PROCESSING");
$("#resultTitle").textContent = "正在执行车舱编排";
try {
const response = await apiRequest("/api/requests", {
method: "POST",
timeoutMs: requestTimeoutForExecutionMode(state.executionMode),
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
utterance,
client_type: "web_console",
provider: state.provider,
conversation_id: state.conversationId,
vehicle_id: state.vehicleId || state.runtime?.default_vehicle_id,
execution_mode: state.executionMode,
control_transport: state.controlTransport,
...(state.provider === "openai" ? { reasoning_effort: state.reasoningEffort } : {}),
...(state.executionMode === "hardware" && !driverOnlyCh1
? { hardware_client_id: state.hardwareClientId }
: {}),
...(state.executionMode === "simulated_hardware"
? { simulation_fault: $("#simulationFault").value }
: {}),
}),
});
const payload = await response.json();
if (response.status === 401) {
window.location.replace("/login");
return;
}
if (!response.ok) {
const requestError = new Error(payload.message || payload.error || `HTTP ${response.status}`);
requestError.code = payload.error;
requestError.retryAfter = Number(
payload.retry_after_seconds || response.headers.get("Retry-After") || 0,
const requestBody = {
utterance,
client_type: "web_console",
provider: state.provider,
conversation_id: state.conversationId,
vehicle_id: state.vehicleId || state.runtime?.default_vehicle_id,
execution_mode: state.executionMode,
control_transport: state.controlTransport,
...(state.provider === "openai" ? { reasoning_effort: state.reasoningEffort } : {}),
...(state.executionMode === "hardware" && !driverOnlyCh1
? { hardware_client_id: state.hardwareClientId }
: {}),
...(state.executionMode === "simulated_hardware"
? { simulation_fault: $("#simulationFault").value }
: {}),
};
let payload;
let supplementWarning = "";
const onControlPhaseEvent = (phaseEvent) => {
if (phaseEvent.type !== "validated_commands" || !phaseEvent.payload) return;
window.dispatchEvent(new CustomEvent(
"cognitive-agent:validated-can-commands",
{ detail: phaseEvent.payload },
));
};
if (state.provider === "openai") {
const preview = await postControlPhase(
"/api/requests/preview",
requestBody,
state.executionMode,
onControlPhaseEvent,
);
throw requestError;
if (!preview) return;
renderResult(preview);
completedResult = preview;
if (preview.supplement_required) {
setRunStatus("processing", "CLOUD SUPPLEMENT");
$("#resultTitle").textContent = "本地指令已处理,正在补充云端解析";
try {
payload = await postControlPhase(
`/api/requests/${preview.request_id}/supplement`,
{
client_type: "web_console",
provider: state.provider,
reasoning_effort: state.reasoningEffort,
...(state.executionMode === "hardware" && !driverOnlyCh1
? { hardware_client_id: state.hardwareClientId }
: {}),
},
state.executionMode,
onControlPhaseEvent,
);
if (!payload) return;
} catch (error) {
const localCommandCount = Object.values(preview.function_configs || {})
.reduce((total, config) => total + (config?.spec?.operations?.length || 0), 0);
if (!localCommandCount) throw error;
payload = {
...preview,
status: "partially_succeeded",
supplement_required: false,
cloud_supplement_error: {
code: error.code || "cloud_supplement_failed",
message: error.message,
},
decision_summary: [
...(preview.decision_summary || []),
`云端补充失败:${error.message};本地规则命令已保留且不会撤销。`,
],
};
supplementWarning = "本地规则命令已执行;云端补充失败,已保留本地结果";
}
} else {
payload = preview;
}
} else {
payload = await postControlPhase(
"/api/requests",
requestBody,
state.executionMode,
onControlPhaseEvent,
);
if (!payload) return;
}
renderResult(payload);
completedResult = payload;
@@ -7405,7 +7516,7 @@ async function submitRequest(event) {
setModeExecutionState(submittedModeProfileId, completed ? "succeeded" : "failed");
}
const simulated = payload.execution_report?.metadata?.labels?.seat_feedback === "simulated_hardware";
showToast(completed
showToast(supplementWarning || (completed
? (payload.mode_profile
? `${payload.mode_profile.name}已创建并添加到功能模式`
: payload.status === "partially_succeeded"
@@ -7415,7 +7526,7 @@ async function submitRequest(event) {
: payload.execution_report?.spec?.mode === "hil"
? "真实台架执行与反馈确认已完成"
: "可执行动作的 dry-run 已完成")
: simulated ? "模拟故障已触发,详情见执行结果" : "请求未执行");
: simulated ? "模拟故障已触发,详情见执行结果" : "请求未执行"));
} catch (error) {
completedError = error;
if (submittedModeProfileId) setModeExecutionState(submittedModeProfileId, "failed");