支持从主程序导入场景模型
This commit is contained in:
@@ -22,11 +22,31 @@ type UploadModelPayload = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const defaultOperationTree = JSON.stringify({ OperationTree: "[]" });
|
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 dictionariesLoaded = false;
|
||||||
let dictionariesLoading: Promise<void> | null = null;
|
let dictionariesLoading: Promise<void> | null = null;
|
||||||
|
let sceneModelBridgeBound = false;
|
||||||
|
|
||||||
export function bindModelActions() {
|
export function bindModelActions() {
|
||||||
const isAdmin = getCurrentUser()?.role === "admin";
|
const isAdmin = getCurrentUser()?.role === "admin";
|
||||||
|
bindSceneModelBridge();
|
||||||
|
ensureImportSceneModelButton();
|
||||||
if (isAdmin) {
|
if (isAdmin) {
|
||||||
document.querySelector("#manageUsersBtn")?.addEventListener("click", async () => {
|
document.querySelector("#manageUsersBtn")?.addEventListener("click", async () => {
|
||||||
try {
|
try {
|
||||||
@@ -242,8 +262,90 @@ function syncSelectedFolderActions() {
|
|||||||
const canWrite = Boolean(currentFolder?.permissions.write);
|
const canWrite = Boolean(currentFolder?.permissions.write);
|
||||||
const addModelBtn = document.querySelector<HTMLButtonElement>("#addModelBtn");
|
const addModelBtn = document.querySelector<HTMLButtonElement>("#addModelBtn");
|
||||||
const addProcessModelBtn = document.querySelector<HTMLButtonElement>("#addProcessModelBtn");
|
const addProcessModelBtn = document.querySelector<HTMLButtonElement>("#addProcessModelBtn");
|
||||||
|
const importSceneModelBtn = document.querySelector<HTMLButtonElement>("#importSceneModelBtn");
|
||||||
if (addModelBtn) addModelBtn.hidden = !canWrite;
|
if (addModelBtn) addModelBtn.hidden = !canWrite;
|
||||||
if (addProcessModelBtn) addProcessModelBtn.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) {
|
export async function uploadModelToBackend(payload: UploadModelPayload) {
|
||||||
|
|||||||
Reference in New Issue
Block a user