fix(web): unify mode previews and label window positions
This commit is contained in:
@@ -1760,6 +1760,17 @@
|
||||
border-top: 1px solid color-mix(in oklch, var(--primary) 17%, var(--border));
|
||||
}
|
||||
|
||||
.assistant-dispatched-controls-list[hidden] { display: none; }
|
||||
.assistant-dispatched-controls-footer:empty { display: none; }
|
||||
.assistant-dispatched-controls .assistant-mode-draft-inline {
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.assistant-dispatched-controls-list > li {
|
||||
min-height: 55px;
|
||||
display: grid;
|
||||
|
||||
@@ -553,6 +553,17 @@
|
||||
|
||||
function assistantControlCategory(operation = {}, fallback = "控制指令") {
|
||||
const capability = String(operation.capability || "");
|
||||
if (capability.startsWith("window.")) {
|
||||
const target = String(operation.target?.zone || operation.target?.instance
|
||||
|| operation.target_scope || (typeof operation.target === "string" ? operation.target : ""))
|
||||
.replaceAll("-", "_");
|
||||
return {
|
||||
front_left: "左前车窗(主驾)", driver: "左前车窗(主驾)",
|
||||
front_right: "右前车窗(副驾)", passenger: "右前车窗(副驾)",
|
||||
rear_left: "左后车窗", rear_right: "右后车窗",
|
||||
all: "全部车窗", front: "前排车窗", rear: "后排车窗",
|
||||
}[target] || "车窗(位置待确认)";
|
||||
}
|
||||
if (capability === "infrared.emit") {
|
||||
const deviceName = String(
|
||||
operation.target?.name || operation.target?.device || "红外外设",
|
||||
@@ -673,8 +684,30 @@
|
||||
commands = [];
|
||||
}
|
||||
if (!commands.length) commands = fallbackAssistantControlCommands(result);
|
||||
if (result.mode_profile_draft && Array.isArray(result.actions)) {
|
||||
const operationSignature = (operation = {}) => {
|
||||
const rawTarget = String(operation.target?.instance || operation.target?.zone
|
||||
|| operation.target?.device || operation.target_scope
|
||||
|| (typeof operation.target === "string" ? operation.target : ""))
|
||||
.replaceAll("-", "_");
|
||||
const target = ({ passenger: "front_right", driver: "front_left" })[rawTarget] || rawTarget;
|
||||
const parameters = operation.parameters || {};
|
||||
return JSON.stringify([operation.capability, target,
|
||||
Object.keys(parameters).sort().map((key) => [key, parameters[key]])]);
|
||||
};
|
||||
const presentationByAction = new Map(projections.map((presentation) => [
|
||||
operationSignature(presentation.operation), presentation,
|
||||
]));
|
||||
commands = result.actions.filter((action) => action && typeof action === "object")
|
||||
.map((operation, index) => ({
|
||||
operation, operationRef: `draft-action-${index}`,
|
||||
semantic: String(operation.capability || ""),
|
||||
command: String(presentationByAction.get(operationSignature(operation))?.actual_command || ""),
|
||||
}));
|
||||
}
|
||||
return commands.map((item, index) => {
|
||||
const operation = projectionByRef.get(String(item.operationRef || ""))
|
||||
const operation = item.operation
|
||||
|| projectionByRef.get(String(item.operationRef || ""))
|
||||
|| operationByRef.get(String(item.operationRef || ""))
|
||||
|| projections[index]?.operation
|
||||
|| {};
|
||||
@@ -737,7 +770,13 @@
|
||||
const temperature = numericValue(parameters.temperature_c);
|
||||
if (temperature !== null) return `${temperature}°C`;
|
||||
const position = numericValue(parameters.position_pct ?? parameters.shade_position_pct);
|
||||
if (position !== null) return `${position}%`;
|
||||
if (position !== null) {
|
||||
if (String(item.operation?.capability || "").startsWith("window.")) {
|
||||
return position === 0 ? "0%(完全关闭)"
|
||||
: position === 100 ? "100%(完全打开)" : `${position}%`;
|
||||
}
|
||||
return `${position}%`;
|
||||
}
|
||||
const illumination = String(parameters.color_hex || "").trim();
|
||||
const brightnessPercent = numericValue(parameters.brightness_pct);
|
||||
if (illumination && brightnessPercent !== null) return `${illumination} · ${brightnessPercent}%`;
|
||||
@@ -816,17 +855,20 @@
|
||||
if (!commands.length) return;
|
||||
const previewOnly = String(mergedResult.execution_mode || "dry_run") !== "hardware"
|
||||
|| mergedResult.orchestration_route === "mode_profile_create_preview";
|
||||
const headingText = previewOnly ? "控制指令预览(未下发)" : "下发控制指令";
|
||||
const headingText = mergedResult.mode_profile_draft?.name
|
||||
? `${mergedResult.mode_profile_draft.name}(未下发)`
|
||||
: previewOnly ? "控制指令预览(未下发)" : "下发控制指令";
|
||||
|
||||
const signature = JSON.stringify(commands.map((item) => [
|
||||
const signature = JSON.stringify([headingText, commands.map((item) => [
|
||||
item.operationRef,
|
||||
item.category,
|
||||
item.command,
|
||||
item.semantic,
|
||||
assistantControlValue(item),
|
||||
item.deliveryState,
|
||||
item.deliveryLabel,
|
||||
item.deliveryDetail,
|
||||
]));
|
||||
])]);
|
||||
const vueRenderer = window.CognitiveAgentVueUI?.renderDispatchedControls;
|
||||
if (typeof vueRenderer === "function") {
|
||||
let host = $(".assistant-dispatched-controls-vue-host", message.body);
|
||||
@@ -1114,8 +1156,8 @@
|
||||
all: "全部车窗",
|
||||
front: "前排车窗",
|
||||
rear: "后排车窗",
|
||||
front_left: "主驾车窗",
|
||||
front_right: "副驾车窗",
|
||||
front_left: "左前车窗(主驾)",
|
||||
front_right: "右前车窗(副驾)",
|
||||
rear_left: "左后车窗",
|
||||
rear_right: "右后车窗",
|
||||
};
|
||||
@@ -1383,27 +1425,15 @@
|
||||
rememberModeDraftContext(draft);
|
||||
supersedeModeDraftCards(draft);
|
||||
const selector = `[data-assistant-mode-draft="${CSS.escape(String(draft.source_request_id))}"]`;
|
||||
if ($(selector, message.body)) return;
|
||||
if ($(selector, message.body)
|
||||
|| message.modeDraftCard?.dataset.assistantModeDraft === String(draft.source_request_id)) return;
|
||||
const card = document.createElement("section");
|
||||
card.className = "assistant-mode-draft";
|
||||
card.className = "assistant-mode-draft assistant-mode-draft-inline";
|
||||
card.dataset.assistantModeDraft = String(draft.source_request_id);
|
||||
card.dataset.assistantModeName = normalizeModeName(draft.name);
|
||||
message.article?.classList.add("assistant-message-mode-draft");
|
||||
|
||||
const heading = document.createElement("header");
|
||||
const headingCopy = document.createElement("span");
|
||||
const eyebrow = document.createElement("small");
|
||||
eyebrow.textContent = draft.existing_mode_id
|
||||
? "已载入现有功能模式"
|
||||
: "已为你生成功能模式(未下发)";
|
||||
const title = document.createElement("strong");
|
||||
title.textContent = `「${draft.name}」`;
|
||||
headingCopy.append(eyebrow, title);
|
||||
const badge = document.createElement("span");
|
||||
badge.className = "assistant-mode-draft-badge";
|
||||
message.modeDraftCard = card;
|
||||
const scheduleView = modeDraftScheduleView(draft);
|
||||
badge.textContent = `${scheduleView?.operationCount ?? (Number(draft.operation_count) || 0)} 项动作`;
|
||||
heading.append(headingCopy, badge);
|
||||
|
||||
const list = document.createElement("div");
|
||||
list.className = "assistant-mode-draft-list";
|
||||
@@ -1431,12 +1461,10 @@
|
||||
hint.className = "assistant-mode-schedule-hint";
|
||||
hint.textContent = scheduleView.stopHint;
|
||||
list.append(hint);
|
||||
} else {
|
||||
appendModeDraftRows(list, modeDraftRows(draft, actions));
|
||||
}
|
||||
const previewNotice = document.createElement("p");
|
||||
previewNotice.className = "assistant-mode-draft-preview-notice";
|
||||
previewNotice.textContent = "创建阶段仅生成并校验控制方案,不会向 CAN 或红外外设发送指令。";
|
||||
previewNotice.textContent = `${draft.existing_mode_id ? "已载入现有功能模式。" : ""}创建阶段仅生成并校验控制方案,不会向 CAN 或红外外设发送指令。`;
|
||||
list.append(previewNotice);
|
||||
|
||||
const controls = document.createElement("div");
|
||||
@@ -1464,8 +1492,22 @@
|
||||
void tryModeProfileDraft(card, draft, actions, buttons, status);
|
||||
});
|
||||
|
||||
card.append(heading, list, controls, status);
|
||||
message.body.append(card);
|
||||
card.append(list, controls, status);
|
||||
appendDispatchedControls(message, {
|
||||
mode_profile_draft: draft, actions, execution_mode: "dry_run",
|
||||
orchestration_route: "mode_profile_create_preview",
|
||||
});
|
||||
const host = $(".assistant-dispatched-controls-vue-host", message.body);
|
||||
const attached = host && window.CognitiveAgentVueUI?.setDispatchedControlsFooter?.(
|
||||
host, card, { hideCommands: Boolean(scheduleView) },
|
||||
);
|
||||
if (!attached) {
|
||||
const panel = $(".assistant-dispatched-controls", message.body);
|
||||
if (!panel) return;
|
||||
const commandList = $(".assistant-dispatched-controls-list", panel);
|
||||
if (commandList) commandList.hidden = Boolean(scheduleView);
|
||||
panel.append(card);
|
||||
}
|
||||
window.lucide?.createIcons({ attrs: { "aria-hidden": "true" } });
|
||||
followLatest(true);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
<script src="/pwa.js?v=android-pad-3" defer></script>
|
||||
<script src="/console-v2.js?v=local-first-79-cinema-status" defer></script>
|
||||
<script src="/self-extension.js?v=peripheral-cards-59" defer></script>
|
||||
<script src="/assistant-chat.js?v=codex-assistant-40-seat-rows" defer></script>
|
||||
<script src="/assistant-chat.js?v=codex-assistant-41-unified-preview" defer></script>
|
||||
<script src="/energy-monitor.js?v=energy-monitor-5-performance" defer></script>
|
||||
<script src="/firmware-workbench-entry.js?v=3" defer></script>
|
||||
</head>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const CACHE_VERSION = "cognitive-agent-pad-v337-seat-rows";
|
||||
const CACHE_VERSION = "cognitive-agent-pad-v338-unified-preview";
|
||||
const SHELL_CACHE = `${CACHE_VERSION}-shell`;
|
||||
const RUNTIME_CACHE = `${CACHE_VERSION}-runtime`;
|
||||
const APP_SHELL = [
|
||||
@@ -16,13 +16,13 @@ const APP_SHELL = [
|
||||
"/speech-input.css?v=sensevoice-7",
|
||||
"/speech-input.js?v=sensevoice-13",
|
||||
"/speech-audio-worklet.js?v=sensevoice-5",
|
||||
"/assistant-chat.css?v=codex-assistant-30",
|
||||
"/assistant-chat.js?v=codex-assistant-40-seat-rows",
|
||||
"/assistant-chat.css?v=codex-assistant-31-unified-preview",
|
||||
"/assistant-chat.js?v=codex-assistant-41-unified-preview",
|
||||
"/energy-monitor.css?v=energy-monitor-5-dialog-size",
|
||||
"/energy-monitor.js?v=energy-monitor-5-performance",
|
||||
"/ui-consistency.css?v=spatial-ui-8",
|
||||
"/codepen-glass-theme.css?v=creative-cloud-6-performance",
|
||||
"/vue-ui.js?v=vue-presentation-4",
|
||||
"/vue-ui.js?v=vue-presentation-5-draft-footer",
|
||||
"/firmware-workbench-entry.css?v=2",
|
||||
"/firmware-workbench-entry.js?v=3",
|
||||
"/firmware-workbench.html",
|
||||
|
||||
@@ -111,7 +111,7 @@ import { Fragment, createApp, h, nextTick, reactive } from "vue";
|
||||
}
|
||||
|
||||
function createCommandMount(container) {
|
||||
const state = reactive({ commands: [], open: true, heading: "下发控制指令" });
|
||||
const state = reactive({ commands: [], open: true, heading: "下发控制指令", footer: null, hideCommands: false });
|
||||
const app = createApp({
|
||||
name: "N7DispatchedControlsCard",
|
||||
setup() {
|
||||
@@ -138,7 +138,16 @@ import { Fragment, createApp, h, nextTick, reactive } from "vue";
|
||||
"data-lucide": "chevron-down",
|
||||
}),
|
||||
]),
|
||||
h("ol", { class: "assistant-dispatched-controls-list" }, state.commands.map(renderCommandRow)),
|
||||
h("ol", { class: "assistant-dispatched-controls-list", hidden: state.hideCommands }, state.commands.map(renderCommandRow)),
|
||||
h("div", {
|
||||
class: "assistant-dispatched-controls-footer",
|
||||
hidden: !state.footer,
|
||||
ref(element) {
|
||||
if (element && state.footer && state.footer.parentNode !== element) {
|
||||
element.replaceChildren(state.footer);
|
||||
}
|
||||
},
|
||||
}),
|
||||
]);
|
||||
},
|
||||
});
|
||||
@@ -160,12 +169,22 @@ import { Fragment, createApp, h, nextTick, reactive } from "vue";
|
||||
return true;
|
||||
}
|
||||
|
||||
function setDispatchedControlsFooter(container, footer, options = {}) {
|
||||
const mount = commandMounts.get(container);
|
||||
if (!mount || !(footer instanceof Element)) return false;
|
||||
mount.state.footer = footer;
|
||||
mount.state.hideCommands = Boolean(options.hideCommands);
|
||||
refreshIcons();
|
||||
return true;
|
||||
}
|
||||
|
||||
document.documentElement.classList.add("vue-presentation-enabled");
|
||||
document.documentElement.dataset.vueVersion = VUE_VERSION;
|
||||
window.CognitiveAgentVueUI = Object.freeze({
|
||||
available: true,
|
||||
version: VUE_VERSION,
|
||||
renderDispatchedControls,
|
||||
setDispatchedControlsFooter,
|
||||
renderModeChips,
|
||||
});
|
||||
}());
|
||||
|
||||
Reference in New Issue
Block a user