feat(perform): 演出配置页(模式切换) + 镜头可视框始终可见
P1 反馈两处修改: - 顶部加「海选审核 / 演出配置」模式切换;演出配置=独立页,左列仅已确认事件, 选中即内嵌白模预览(弃用原弹窗),为 P2 在此配置演出细节打底 - 修镜头框只在 dialogue 显式带 camera 时才画的 bug:改为镜头可视区域框始终可见, 显式镜头点优先→跟随说话人→跟玩家→场景中心,框尺寸按世界单位随舞台缩放+焦点十字 - timeline.js 从弹窗固定ID重构为挂载到任意容器 Timeline.show(host,...); 离线模型测试复跑两样张全过,重构未破坏逻辑
This commit is contained in:
@ -9,6 +9,7 @@
|
||||
status: null,
|
||||
selectedNode: null,
|
||||
dirty: false,
|
||||
mode: "review", // review=海选审核 / perform=演出配置
|
||||
by: localStorage.getItem("story_by") || "匿名",
|
||||
};
|
||||
window.App = App;
|
||||
@ -80,7 +81,7 @@
|
||||
App.current = group; App.ir = JSON.parse(JSON.stringify(d.ir));
|
||||
App.status = d.status; App.selectedNode = null; App.dirty = false;
|
||||
$("graph-empty").style.display = "none";
|
||||
["btn-save", "btn-validate", "btn-playtest", "btn-timeline", "btn-confirm", "btn-discard", "btn-addnode", "btn-autolayout", "btn-addsucc"].forEach(b => $(b).disabled = false);
|
||||
["btn-save", "btn-validate", "btn-playtest", "btn-confirm", "btn-discard", "btn-addnode", "btn-autolayout", "btn-addsucc"].forEach(b => $(b).disabled = false);
|
||||
renderAll(true);
|
||||
GraphUI.focusStart(App.ir); // 定位到开头节点
|
||||
snapReset(); // 初始化撤销栈
|
||||
@ -194,8 +195,42 @@
|
||||
// ---------- 试走 ----------
|
||||
$("btn-playtest").onclick = () => Playtest.open(App.ir, App.dict);
|
||||
|
||||
// ---------- 演出预览(白模时间线)----------
|
||||
$("btn-timeline").onclick = () => Timeline.open(App.ir, App.dict, App.pointsets);
|
||||
// ---------- 模式切换:海选审核 / 演出配置 ----------
|
||||
function setMode(m) {
|
||||
App.mode = m;
|
||||
$("mode-review").classList.toggle("active", m === "review");
|
||||
$("mode-perform").classList.toggle("active", m === "perform");
|
||||
$("wrap").classList.toggle("hidden", m !== "review");
|
||||
$("perform-wrap").classList.toggle("hidden", m !== "perform");
|
||||
$("review-toolbar").style.display = m === "review" ? "" : "none";
|
||||
Timeline.stop();
|
||||
if (m === "perform") performLoadList();
|
||||
}
|
||||
$("mode-review").onclick = () => setMode("review");
|
||||
$("mode-perform").onclick = () => setMode("perform");
|
||||
|
||||
// ---------- 演出配置页:已确认事件列表 + 内嵌白模预览 ----------
|
||||
let performCurrent = null;
|
||||
async function performLoadList() {
|
||||
let list;
|
||||
try { list = await (await api("/api/events?status=confirmed")).json(); } catch (e) { return; }
|
||||
const host = $("perform-list"); host.innerHTML = "";
|
||||
if (!list.length) { host.innerHTML = '<div class="empty" style="padding:14px">还没有已确认的事件。去「海选审核」确认事件后再来配置演出。</div>'; return; }
|
||||
list.forEach(e => {
|
||||
const d = document.createElement("div");
|
||||
d.className = "ev" + (e.group === performCurrent ? " sel" : "");
|
||||
d.innerHTML = '<div class="t">' + esc(e.title || e.group) + '</div><div class="g">' + esc(e.group) + ' · ' + esc(e.updated_by || "") + '</div>';
|
||||
d.onclick = () => performSelect(e.group);
|
||||
host.appendChild(d);
|
||||
});
|
||||
}
|
||||
async function performSelect(group) {
|
||||
let d;
|
||||
try { d = await (await api("/api/events/" + encodeURIComponent(group))).json(); } catch (e) { return; }
|
||||
performCurrent = group;
|
||||
performLoadList();
|
||||
Timeline.show($("perform-main"), d.ir, App.dict, App.pointsets);
|
||||
}
|
||||
|
||||
// ---------- 导入 ----------
|
||||
let importFiles = []; // 当前已选文件
|
||||
|
||||
Reference in New Issue
Block a user