update
This commit is contained in:
@@ -278,7 +278,7 @@
|
||||
|
||||
const state = loadState();
|
||||
const pages = Object.fromEntries(Object.keys(TOY_TYPES).map((key) => [key, 0]));
|
||||
let activeMode = sessionStorage.getItem(MODE_KEY) === "control" ? "control" : "study";
|
||||
let activeMode = "study";
|
||||
let selectedAddType = "light";
|
||||
let learning = freshLearningSession();
|
||||
let isPlanning = false;
|
||||
@@ -290,6 +290,8 @@
|
||||
let latestVehicleStateTurn = -1;
|
||||
let sharedTwinBand = null;
|
||||
let sharedTwinHome = null;
|
||||
let petTimer = null;
|
||||
let petPhraseIndex = 0;
|
||||
|
||||
function uid(prefix) {
|
||||
if (globalThis.crypto?.randomUUID) return `${prefix}-${crypto.randomUUID()}`;
|
||||
@@ -347,6 +349,14 @@
|
||||
: {};
|
||||
saved.selectedDeviceByType = saved.selectedDeviceByType || {};
|
||||
saved.settings = { actionDelayMs: Number(saved.settings?.actionDelayMs) || 520 };
|
||||
// Learned capabilities are durable configuration; execution lamps, history,
|
||||
// and protocol feedback belong to one virtual run and must never survive a restart.
|
||||
saved.history = [];
|
||||
saved.lastProtocol = null;
|
||||
saved.vehicleExecutions = {};
|
||||
saved.sessionStartedAt = null;
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(saved));
|
||||
sessionStorage.removeItem(MODE_KEY);
|
||||
return saved;
|
||||
} catch (error) {
|
||||
console.warn("读取自扩展能力数据失败,已恢复默认状态。", error);
|
||||
@@ -506,7 +516,18 @@
|
||||
<span><i>CH0 / CH1</i>等待权威车端状态</span>
|
||||
</div>
|
||||
<div class="v2-extension-run-plan" id="extensionRunPlan" hidden></div>
|
||||
</section>`;
|
||||
</section>
|
||||
<aside class="v2-extension-pet" id="extensionDesktopPet" data-mood="idle" aria-live="polite">
|
||||
<span class="v2-extension-pet-bubble" id="extensionPetBubble">嗨,我会陪你学习新能力</span>
|
||||
<button class="v2-extension-pet-body" id="extensionPetBody" type="button" aria-label="网页版桌宠,拖动可移动,点击可互动">
|
||||
<span class="v2-extension-pet-antenna"><i></i></span>
|
||||
<span class="v2-extension-pet-ear left"></span><span class="v2-extension-pet-ear right"></span>
|
||||
<span class="v2-extension-pet-face"><i class="eye left"></i><i class="eye right"></i><b></b><em></em></span>
|
||||
<span class="v2-extension-pet-screen"><i></i><b>EXT</b></span>
|
||||
<span class="v2-extension-pet-foot left"></span><span class="v2-extension-pet-foot right"></span>
|
||||
<span class="v2-extension-pet-tail"></span>
|
||||
</button>
|
||||
</aside>`;
|
||||
moduleSwitcher.insertAdjacentElement("afterend", root);
|
||||
|
||||
buildDialogs();
|
||||
@@ -1603,6 +1624,91 @@
|
||||
}
|
||||
}
|
||||
|
||||
function initializeDesktopPet() {
|
||||
const pet = $("#extensionDesktopPet");
|
||||
const body = $("#extensionPetBody");
|
||||
const bubble = $("#extensionPetBubble");
|
||||
const host = $("#v2SelfExtension");
|
||||
if (!pet || !body || !bubble || !host) return;
|
||||
const phrases = [
|
||||
"嗨,我会陪你学习新能力",
|
||||
"拖动我可以换个位置",
|
||||
"玩具动作和车端设备都能一起编排",
|
||||
"虚拟运行重启后,我也会恢复待命",
|
||||
"点击车端动作,我会帮你盯着执行状态",
|
||||
];
|
||||
const pointer = { active: false, moved: false, x: 0, y: 0, startX: 0, startY: 0 };
|
||||
|
||||
const say = (message, mood = "talking") => {
|
||||
bubble.textContent = message;
|
||||
pet.dataset.mood = mood;
|
||||
window.clearTimeout(Number(pet.dataset.moodTimer || 0));
|
||||
pet.dataset.moodTimer = String(window.setTimeout(() => {
|
||||
pet.dataset.mood = "idle";
|
||||
}, 2600));
|
||||
};
|
||||
|
||||
const clampPosition = (x, y) => {
|
||||
const hostRect = host.getBoundingClientRect();
|
||||
const petRect = pet.getBoundingClientRect();
|
||||
return {
|
||||
x: Math.max(-hostRect.width + petRect.width + 10, Math.min(0, x)),
|
||||
y: Math.max(-hostRect.height + petRect.height + 10, Math.min(0, y)),
|
||||
};
|
||||
};
|
||||
|
||||
body.addEventListener("pointerdown", (event) => {
|
||||
if (event.button !== 0) return;
|
||||
pointer.active = true;
|
||||
pointer.moved = false;
|
||||
pointer.startX = event.clientX;
|
||||
pointer.startY = event.clientY;
|
||||
pointer.x = Number(pet.dataset.x || 0);
|
||||
pointer.y = Number(pet.dataset.y || 0);
|
||||
body.setPointerCapture?.(event.pointerId);
|
||||
pet.dataset.dragging = "true";
|
||||
});
|
||||
body.addEventListener("pointermove", (event) => {
|
||||
if (!pointer.active) return;
|
||||
const deltaX = event.clientX - pointer.startX;
|
||||
const deltaY = event.clientY - pointer.startY;
|
||||
pointer.moved ||= Math.hypot(deltaX, deltaY) > 4;
|
||||
const position = clampPosition(pointer.x + deltaX, pointer.y + deltaY);
|
||||
pet.dataset.x = String(position.x);
|
||||
pet.dataset.y = String(position.y);
|
||||
pet.style.setProperty("--pet-x", `${position.x}px`);
|
||||
pet.style.setProperty("--pet-y", `${position.y}px`);
|
||||
});
|
||||
const endDrag = () => {
|
||||
pointer.active = false;
|
||||
delete pet.dataset.dragging;
|
||||
};
|
||||
body.addEventListener("pointerup", endDrag);
|
||||
body.addEventListener("pointercancel", endDrag);
|
||||
body.addEventListener("click", () => {
|
||||
if (pointer.moved) return;
|
||||
petPhraseIndex = (petPhraseIndex + 1) % phrases.length;
|
||||
say(phrases[petPhraseIndex], petPhraseIndex % 2 ? "happy" : "talking");
|
||||
});
|
||||
window.addEventListener("resize", () => {
|
||||
const position = clampPosition(Number(pet.dataset.x || 0), Number(pet.dataset.y || 0));
|
||||
pet.dataset.x = String(position.x);
|
||||
pet.dataset.y = String(position.y);
|
||||
pet.style.setProperty("--pet-x", `${position.x}px`);
|
||||
pet.style.setProperty("--pet-y", `${position.y}px`);
|
||||
});
|
||||
window.addEventListener("cognitive-agent:module-change", (event) => {
|
||||
if (event.detail?.module === "self-extension") say("自扩展工作台已就绪", "happy");
|
||||
});
|
||||
petTimer = window.setInterval(() => {
|
||||
if (document.visibilityState !== "visible"
|
||||
|| document.body.dataset.module !== "self-extension") return;
|
||||
petPhraseIndex = (petPhraseIndex + 1) % phrases.length;
|
||||
say(phrases[petPhraseIndex]);
|
||||
}, 14000);
|
||||
window.addEventListener("pagehide", () => window.clearInterval(petTimer));
|
||||
}
|
||||
|
||||
function bindEvents() {
|
||||
$$('[data-extension-mode]').forEach((button) => {
|
||||
button.addEventListener("click", () => setMode(button.dataset.extensionMode));
|
||||
@@ -1723,6 +1829,7 @@
|
||||
|
||||
function init() {
|
||||
if (!buildShell()) return;
|
||||
initializeDesktopPet();
|
||||
bindEvents();
|
||||
renderAll();
|
||||
setMode(activeMode);
|
||||
|
||||
Reference in New Issue
Block a user