支持从主程序导入场景模型

This commit is contained in:
zhangshun
2026-05-29 16:59:52 +08:00
parent c923e9e54d
commit b27bf2c83b

View File

@@ -22,11 +22,31 @@ type UploadModelPayload = {
};
const defaultOperationTree = JSON.stringify({ OperationTree: "[]" });
const requestSceneModelMessageType = "DMT_MODEL_LIBRARY_REQUEST_SCENE_MODEL";
const sceneModelMessageType = "DMT_MODEL_LIBRARY_SCENE_MODEL";
const sceneModelErrorMessageType = "DMT_MODEL_LIBRARY_SCENE_MODEL_ERROR";
type SceneModelMessagePayload = {
modelName?: string;
fileName?: string;
modelBuffer?: ArrayBuffer;
operationTreeJson?: string;
};
type SceneModelMessage = {
type?: string;
payload?: SceneModelMessagePayload;
message?: string;
};
let dictionariesLoaded = false;
let dictionariesLoading: Promise<void> | null = null;
let sceneModelBridgeBound = false;
export function bindModelActions() {
const isAdmin = getCurrentUser()?.role === "admin";
bindSceneModelBridge();
ensureImportSceneModelButton();
if (isAdmin) {
document.querySelector("#manageUsersBtn")?.addEventListener("click", async () => {
try {
@@ -242,8 +262,90 @@ function syncSelectedFolderActions() {
const canWrite = Boolean(currentFolder?.permissions.write);
const addModelBtn = document.querySelector<HTMLButtonElement>("#addModelBtn");
const addProcessModelBtn = document.querySelector<HTMLButtonElement>("#addProcessModelBtn");
const importSceneModelBtn = document.querySelector<HTMLButtonElement>("#importSceneModelBtn");
if (addModelBtn) addModelBtn.hidden = !canWrite;
if (addProcessModelBtn) addProcessModelBtn.hidden = !canWrite;
if (importSceneModelBtn) importSceneModelBtn.hidden = !canWrite;
}
function ensureImportSceneModelButton() {
if (document.querySelector("#importSceneModelBtn")) return;
const addModelBtn = document.querySelector<HTMLButtonElement>("#addModelBtn");
if (!addModelBtn) return;
const button = document.createElement("button");
button.id = "importSceneModelBtn";
button.type = "button";
button.textContent = "导入场景模型";
button.addEventListener("click", requestSceneModelImport);
addModelBtn.insertAdjacentElement("afterend", button);
}
function bindSceneModelBridge() {
if (sceneModelBridgeBound) return;
sceneModelBridgeBound = true;
window.addEventListener("message", (event) => {
const data = event.data as SceneModelMessage;
if (data?.type !== sceneModelMessageType && data?.type !== sceneModelErrorMessageType) return;
if (!isAllowedParentOrigin(event.origin)) return;
void handleSceneModelMessage(data);
});
}
function requestSceneModelImport() {
if (!appState.selectedFolderId) {
notify("请先选择目录");
return;
}
if (!window.parent || window.parent === window) {
notify("请在 DMT 主程序中使用导入场景模型");
return;
}
window.parent.postMessage({
type: requestSceneModelMessageType
}, resolveParentOrigin());
notify("已请求主程序导出当前选中模型");
}
async function handleSceneModelMessage(data: SceneModelMessage) {
if (data.type === sceneModelErrorMessageType) {
notifyError(data.message || "主程序导出模型失败");
return;
}
const payload = data.payload;
if (!payload?.modelBuffer) {
notifyError("主程序返回的模型数据为空");
return;
}
const fileName = ensureGlbFileName(payload.fileName || payload.modelName || "scene-model.glb");
const file = new File([payload.modelBuffer], fileName, { type: "model/gltf-binary" });
await openProcessModelUploadDialog({
file,
modelName: payload.modelName || modelNameFromFile(fileName),
operationTreeJson: payload.operationTreeJson || defaultOperationTree
});
}
function isAllowedParentOrigin(origin: string) {
const expectedOrigin = resolveParentOrigin();
return expectedOrigin === "*" || origin === expectedOrigin;
}
function resolveParentOrigin() {
try {
const meta = import.meta as ImportMeta & { env?: Record<string, string | undefined> };
const configuredOrigin = meta.env?.VITE_DMT_PARENT_ORIGIN;
if (configuredOrigin) return configuredOrigin;
if (document.referrer) return new URL(document.referrer).origin;
} catch {
return "*";
}
return "*";
}
function ensureGlbFileName(fileName: string) {
return fileName.toLowerCase().endsWith(".glb") ? fileName : `${fileName}.glb`;
}
export async function uploadModelToBackend(payload: UploadModelPayload) {