提交代码

This commit is contained in:
yuding
2026-03-16 16:13:36 +08:00
parent 507112fcf9
commit dd4600bb5b
35 changed files with 31811 additions and 9696 deletions

View File

@@ -210,6 +210,38 @@
<div>状态: <span id="engine-status">未初始化</span></div>
</div>
</div>
<!-- 2D 图纸 -->
<div class="control-group">
<h2>📐 2D 图纸 (Engine2D)</h2>
<div class="btn-container">
<button class="primary" id="btn-init2d" onclick="initEngine2d()">初始化 2D 引擎</button>
<button id="btn-load2d" onclick="loadDrawing()" disabled>加载图纸</button>
</div>
<div style="margin-top: 8px;">
<input type="text" id="url-input-2d"
style="width:100%;padding:6px 8px;font-size:0.85rem;border:1px solid #ddd;border-radius:4px;font-family:Consolas,Monaco,monospace;outline:none;"
placeholder="输入新的图纸 URL" />
</div>
<div class="btn-container" style="margin-top: 6px;">
<button class="primary" id="btn-switch2d" onclick="switchDrawing()" disabled>切换图纸</button>
</div>
<div style="margin-top: 6px; font-size: 0.85rem; color: #666;">
<div>状态: <span id="engine2d-status">未初始化</span></div>
</div>
</div>
<!-- 720 全景 -->
<div class="control-group">
<h2>🎥 720 全景 (Engine720)</h2>
<div class="btn-container">
<button class="primary" id="btn-init720" onclick="initEngine720()">初始化 720 引擎</button>
<button id="btn-load720" onclick="loadPanorama()" disabled>加载全景图</button>
</div>
<div style="margin-top: 6px; font-size: 0.85rem; color: #666;">
<div>状态: <span id="engine720-status">未初始化</span></div>
</div>
</div>
</aside>
<!-- 右侧主区域 -->
@@ -218,11 +250,15 @@
</main>
<!-- 自动组合弹窗 -->
<div id="combine-overlay" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,.45); z-index:9999; display:none; justify-content:center; align-items:center;">
<div style="background:#fff; border-radius:10px; padding:24px; width:520px; max-width:90vw; box-shadow:0 8px 32px rgba(0,0,0,.18);">
<div id="combine-overlay"
style="display:none; position:fixed; inset:0; background:rgba(0,0,0,.45); z-index:9999; display:none; justify-content:center; align-items:center;">
<div
style="background:#fff; border-radius:10px; padding:24px; width:520px; max-width:90vw; box-shadow:0 8px 32px rgba(0,0,0,.18);">
<h3 style="margin:0 0 12px; font-size:1.1rem; color:#333;">自动组合加载</h3>
<p style="margin:0 0 10px; font-size:.85rem; color:#888;">请输入模型 URL每行一个或用英文逗号分隔</p>
<textarea id="combine-urls" rows="6" style="width:100%; padding:10px; font-size:.85rem; border:1px solid #ddd; border-radius:6px; resize:vertical; font-family:monospace;" placeholder="https://example.com/model1/&#10;https://example.com/model2/"></textarea>
<textarea id="combine-urls" rows="6"
style="width:100%; padding:10px; font-size:.85rem; border:1px solid #ddd; border-radius:6px; resize:vertical; font-family:monospace;"
placeholder="https://example.com/model1/&#10;https://example.com/model2/"></textarea>
<div style="display:flex; justify-content:flex-end; gap:8px; margin-top:14px;">
<button onclick="closeCombineDialog()" style="min-width:72px;">取消</button>
<button class="primary" onclick="confirmCombineLoad()" style="min-width:72px;">确定加载</button>
@@ -231,21 +267,28 @@
</div>
<script>
let engine = null;
let engine = null; // BimEngine (3D) 实例
let engine2d = null; // BimEngine2d 实例
let engine720 = null; // BimEngine720 实例
let isToolbarVisible = true;
let isLabelVisible = true;
let isLocationVisible = true;
let customGroupAdded = false;
let engine3DInitialized = false;
// 初始化引擎
/**
* 销毁所有引擎实例
*/
function destroyAllEngines() {
if (engine) { engine.destroy(); engine = null; }
if (engine2d) { engine2d.destroy(); engine2d = null; }
if (engine720) { engine720.destroy(); engine720 = null; }
}
// 页面加载完成后默认初始化 3D 引擎
window.onload = () => {
if (window.IflowEngine) {
const Engine = window.IflowEngine.BimEngine;
try {
engine = new Engine('app', { locale: 'zh-CN' });
initEngine3D();
console.log('Engine initialized:', engine);
} catch (err) {
console.error('Init failed:', err);
}
@@ -327,14 +370,14 @@
alert('Please add custom group first / 请先添加自定义组');
return;
}
const btnId = 'custom-btn-' + Date.now();
var btnId = 'custom-btn-' + Date.now();
engine.toolbar.addButton({
id: btnId,
groupId: 'custom-group',
type: 'button',
label: 'New',
icon: '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><path d="M8 14s1.5 2 4 2 4-2 4-2"></path><line x1="9" y1="9" x2="9.01" y2="9"></line><line x1="15" y1="9" x2="15.01" y2="9"></line></svg>',
onClick: (btn) => {
onClick: function (btn) {
alert('Clicked: ' + btn.label);
}
});
@@ -349,60 +392,52 @@
// --- 主题操作 ---
function setTheme(themeName) {
if (engine) engine.setTheme(themeName);
if (engine2d) engine2d.setTheme(themeName);
if (engine720) engine720.setTheme(themeName);
}
function setCustomTheme() {
if (!engine) return;
// 定义一个红色主题
engine.setCustomTheme({
name: 'red-alert',
primary: '#d32f2f',
primaryHover: '#b71c1c',
background: '#ffebee', // 浅红背景
background: '#ffebee',
panelBackground: 'rgba(255, 255, 255, 0.9)',
textPrimary: '#b71c1c',
textSecondary: '#e57373',
border: '#ffcdd2',
icon: '#d32f2f',
iconActive: '#b71c1c',
componentBackground: 'rgba(255, 205, 210, 0.3)',
componentHover: 'rgba(255, 205, 210, 0.8)',
componentActive: '#e57373'
});
}
// --- 3D 引擎操作 ---
// ====== 3D 引擎操作 ======
/**
* 初始化 3D 引擎
* 初始化 3D 引擎(独立实例,销毁其他引擎类型)
*/
function initEngine3D() {
if (!engine || !engine.engine) {
alert('引擎未创建,请先等待页面加载完成');
return;
}
if (engine.engine.isInitialized()) {
alert('3D 引擎已经初始化过了');
updateEngineStatus('已初始化');
return;
}
destroyAllEngines();
updateEngineStatus('初始化中...');
update2dStatus('未初始化');
update720Status('未初始化');
document.getElementById('btn-load2d').disabled = true;
document.getElementById('btn-load720').disabled = true;
try {
// 初始化引擎,使用默认配置
const success = engine.engine.initialize({
backgroundColor: 0x333333, // 深色背景
version: 'v2', // WebGL 版本
showStats: false, // 显示性能统计
showViewCube: true // 显示视图立方体
engine = new IflowEngine.BimEngine('app', { locale: 'zh-CN' });
var success = engine.engine.initialize({
backgroundColor: 0x333333,
version: 'v2',
showStats: false,
showViewCube: true
});
if (success) {
engine3DInitialized = true;
updateEngineStatus('已初始化');
console.log('✅ 3D 引擎初始化成功');
loadModel();
@@ -416,72 +451,46 @@
}
}
/**
* 加载 3D 模型
*/
function loadModel() {
if (!engine || !engine.engine) {
alert('引擎未创建,请先等待页面加载完成');
return;
}
if (!engine.engine.isInitialized()) {
if (!engine || !engine.engine || !engine.engine.isInitialized()) {
alert('请先初始化 3D 引擎!');
return;
}
try {
// 加载模型文件(从 model 目录)
const modelUrl = 'https://lyz-1259524260.cos.ap-guangzhou.myqcloud.com/iflow/models/417664a3-76c8-4d94-9344-1337246a5d4e/';
var modelUrl = 'https://lyz-1259524260.cos.ap-guangzhou.myqcloud.com/iflow/models/417664a3-76c8-4d94-9344-1337246a5d4e/';
engine.engine.loadModel([modelUrl], {
position: [0, 0, 0], // 初始位置
rotation: [0, 0, 0], // 初始旋转
scale: [1, 1, 1] // 初始缩放
position: [0, 0, 0],
rotation: [0, 0, 0],
scale: [1, 1, 1]
});
console.log('✅ 模型加载请求已发送:', modelUrl);
} catch (error) {
console.error('❌ 模型加载错误:', error);
}
}
/**
* 加载组合模型 - 同时加载多个模型
*/
function loadCombinedModel() {
if (!engine || !engine.engine) {
alert('引擎未创建,请先等待页面加载完成');
return;
}
if (!engine.engine.isInitialized()) {
if (!engine || !engine.engine || !engine.engine.isInitialized()) {
alert('请先初始化 3D 引擎!');
return;
}
try {
const modelUrls = [
var modelUrls = [
'https://lyz-1259524260.cos.ap-guangzhou.myqcloud.com/iflow/models/974feae2-4be3-4e85-9d5e-ea655b0c890d/',
'https://lyz-1259524260.cos.ap-guangzhou.myqcloud.com/iflow/models/6129815d-9ae4-4414-a9ab-e7c3ee1b2584/',
'https://lyz-1259524260.cos.ap-guangzhou.myqcloud.com/iflow/models/8ddf95f4-28cc-4218-94c3-165e69fa51b1/'
];
engine.engine.loadModel(modelUrls, {
position: [0, 0, 0],
rotation: [0, 0, 0],
scale: [1, 1, 1]
});
console.log('✅ 组合模型加载请求已发送:', modelUrls);
} catch (error) {
console.error('❌ 组合模型加载错误:', error);
}
}
/**
* 暂停渲染
*/
function pauseRendering() {
if (!engine || !engine.engine || !engine.engine.isInitialized()) {
alert('请先初始化 3D 引擎!');
@@ -491,9 +500,6 @@
console.log('✅ 渲染已暂停');
}
/**
* 恢复渲染
*/
function resumeRendering() {
if (!engine || !engine.engine || !engine.engine.isInitialized()) {
alert('请先初始化 3D 引擎!');
@@ -503,26 +509,13 @@
console.log('✅ 渲染已恢复');
}
/**
* 切换模型 - 输入新的模型 URL
*/
function switchModel() {
if (!engine || !engine.engine) {
alert('引擎未创建,请先等待页面加载完成');
return;
}
if (!engine.engine.isInitialized()) {
if (!engine || !engine.engine || !engine.engine.isInitialized()) {
alert('请先初始化 3D 引擎!');
return;
}
const newUrl = prompt('请输入新的模型 URL:', 'https://lyz-1259524260.cos.ap-guangzhou.myqcloud.com/iflow/models/8634e556-a94e-4ba7-be3e-2ea1507cced5/');
if (!newUrl || newUrl.trim() === '') {
return;
}
var newUrl = prompt('请输入新的模型 URL:', 'https://lyz-1259524260.cos.ap-guangzhou.myqcloud.com/iflow/models/8634e556-a94e-4ba7-be3e-2ea1507cced5/');
if (!newUrl || newUrl.trim() === '') return;
try {
engine.engine.loadModel([newUrl.trim()], {
position: [0, 0, 0],
@@ -535,9 +528,6 @@
}
}
/**
* 打开属性面板
*/
function openPropertyPanel() {
if (!engine || !engine.propertyPanel) {
console.error('Property panel not available');
@@ -546,13 +536,12 @@
engine.propertyPanel.show();
}
// --- 构件树数据 ---
function getLevelTree() {
if (!engine || !engine.engine || !engine.engine.isInitialized()) {
alert('请先初始化 3D 引擎并加载模型!');
return;
}
const data = engine.engine.getLevelTreeData();
var data = engine.engine.getLevelTreeData();
console.log('🌳 楼层树数据:', data);
}
@@ -561,7 +550,7 @@
alert('请先初始化 3D 引擎并加载模型!');
return;
}
const data = engine.engine.getTypeTreeData();
var data = engine.engine.getTypeTreeData();
console.log('🌳 类型树数据:', data);
}
@@ -570,25 +559,20 @@
alert('请先初始化 3D 引擎并加载模型!');
return;
}
const data = engine.engine.getMajorTreeData();
var data = engine.engine.getMajorTreeData();
console.log('🌳 专业树数据:', data);
}
/**
* 更新引擎状态显示
*/
function updateEngineStatus(status) {
const statusEl = document.getElementById('engine-status');
if (statusEl) {
statusEl.textContent = status;
// 根据状态设置颜色
if (status === '已初始化') {
statusEl.style.color = '#28a745';
} else if (status === '初始化失败' || status === '初始化错误') {
statusEl.style.color = '#dc3545';
} else {
statusEl.style.color = '#666';
}
var statusEl = document.getElementById('engine-status');
if (!statusEl) return;
statusEl.textContent = status;
if (status === '已初始化') {
statusEl.style.color = '#28a745';
} else if (status.indexOf('失败') !== -1 || status.indexOf('错误') !== -1) {
statusEl.style.color = '#dc3545';
} else {
statusEl.style.color = '#666';
}
}
@@ -598,69 +582,48 @@
alert('请先初始化 3D 引擎!');
return;
}
const overlay = document.getElementById('combine-overlay');
overlay.style.display = 'flex';
document.getElementById('combine-overlay').style.display = 'flex';
}
function closeCombineDialog() {
const overlay = document.getElementById('combine-overlay');
overlay.style.display = 'none';
document.getElementById('combine-overlay').style.display = 'none';
}
function confirmCombineLoad() {
let raw = document.getElementById('combine-urls').value.trim();
if (!raw) {
alert('请输入至少一个模型 URL');
return;
}
var raw = document.getElementById('combine-urls').value.trim();
if (!raw) { alert('请输入至少一个模型 URL'); return; }
// 1) 统一清洗去除智能引号、零宽字符、BOM 等不可见字符
raw = raw
.replace(/[\u2018\u2019]/g, "'") // “” → '
.replace(/[\u201C\u201D]/g, '"') // “” → "
.replace(/[\u200B\uFEFF\u00A0]/g, '') // 零宽空格、BOM、不换行空格
.replace(/[\u2018\u2019]/g, "'")
.replace(/[\u201C\u201D]/g, '"')
.replace(/[\u200B\uFEFF\u00A0]/g, '')
.trim();
// 2) 尝试当 JSON 数组解析
let urls = [];
var urls = [];
try {
const jsonStr = raw.replace(/'/g, '"');
const parsed = JSON.parse(jsonStr);
var jsonStr = raw.replace(/'/g, '"');
var parsed = JSON.parse(jsonStr);
if (Array.isArray(parsed)) {
urls = parsed.map(s => String(s).trim()).filter(Boolean);
urls = parsed.map(function (s) { return String(s).trim(); }).filter(Boolean);
}
} catch(e) {
// 3) JSON 失败,走分割逻辑
} catch (e) {
urls = raw.split(/[,;\n\r]+/)
.map(s => s.trim().replace(/^['"|\[\]\s]+|['"|\[\]\s]+$/g, ''))
.map(function (s) { return s.trim().replace(/^['"|\[\]\s]+|['"|\[\]\s]+$/g, ''); })
.filter(Boolean);
}
// 4) 只保留 http/https 开头的合法 URL
urls = urls.filter(s => /^https?:\/\//i.test(s));
urls = urls.filter(function (s) { return /^https?:\/\//i.test(s); });
if (urls.length === 0) { alert('未解析到有效的 URL'); return; }
if (urls.length === 0) {
alert('未解析到有效的 URL请确保以 http:// 或 https:// 开头');
return;
}
// 5) 逐个校验 URL 是否合法
for (let i = 0; i < urls.length; i++) {
try {
new URL(urls[i]);
} catch(e) {
alert('第 ' + (i+1) + ' 个 URL 无效:\n' + urls[i] + '\n\n请检查是否包含特殊字符');
console.error('❌ 无效 URL原始字符:', JSON.stringify(urls[i]));
for (var i = 0; i < urls.length; i++) {
try { new URL(urls[i]); } catch (e) {
alert('第 ' + (i + 1) + ' 个 URL 无效:\n' + urls[i]);
return;
}
}
try {
engine.engine.loadModel(urls, {
position: [0, 0, 0],
rotation: [0, 0, 0],
scale: [1, 1, 1]
});
engine.engine.loadModel(urls, { position: [0, 0, 0], rotation: [0, 0, 0], scale: [1, 1, 1] });
console.log('✅ 自动组合加载已发送:', urls);
closeCombineDialog();
document.getElementById('combine-urls').value = '';
@@ -669,6 +632,162 @@
}
}
// ====== 2D 图纸操作 ======
/**
* 初始化 2D 引擎(独立实例,销毁其他引擎类型)
*/
function initEngine2d() {
destroyAllEngines();
updateEngineStatus('未初始化');
update2dStatus('初始化中...');
update720Status('未初始化');
document.getElementById('btn-load720').disabled = true;
try {
engine2d = new IflowEngine.BimEngine2d('app', {
backgroundColor: 0x1a1a1a,
gridEnabled: true,
axesEnabled: true,
enablePerformanceMonitoring: true
});
update2dStatus('已初始化');
document.getElementById('btn-load2d').disabled = false;
document.getElementById('btn-switch2d').disabled = false;
console.log('✅ 2D 引擎初始化成功');
loadDrawing();
} catch (error) {
update2dStatus('初始化错误');
console.error('❌ 2D 引擎初始化错误:', error);
}
}
function loadDrawing() {
if (!engine2d) {
alert('请先初始化 2D 引擎!');
return;
}
var url = 'https://lyz-1259524260.cos.ap-guangzhou.myqcloud.com/iflow/models/cc389dc8-c6d5-43db-81f1-6998d4eee8f6/312';
update2dStatus('正在加载...');
try {
engine2d.loadDrawing(url).then(function () {
update2dStatus('图纸已加载');
console.log('✅ 2D 图纸加载完成');
}).catch(function (err) {
update2dStatus('加载失败');
console.error('❌ 2D 图纸加载失败:', err);
});
} catch (error) {
update2dStatus('加载错误');
console.error('❌ 2D 图纸加载错误:', error);
}
}
function switchDrawing() {
var urlInput = document.getElementById('url-input-2d');
var newUrl = urlInput.value.trim();
if (!newUrl) {
alert('请输入图纸 URL');
return;
}
if (!engine2d) {
alert('请先初始化 2D 引擎!');
return;
}
update2dStatus('正在切换...');
try {
engine2d.loadDrawing(newUrl).then(function () {
update2dStatus('图纸已加载');
console.log('✅ 2D 图纸切换完成: ' + newUrl);
}).catch(function (err) {
update2dStatus('切换失败');
console.error('❌ 2D 图纸切换失败:', err);
});
} catch (error) {
update2dStatus('切换错误');
console.error('❌ 2D 图纸切换错误:', error);
}
}
function update2dStatus(status) {
var el = document.getElementById('engine2d-status');
if (!el) return;
el.textContent = status;
if (status === '已初始化' || status === '图纸已加载') {
el.style.color = '#28a745';
} else if (status === '正在加载...' || status === '初始化中...') {
el.style.color = '#1565c0';
} else if (status.indexOf('失败') !== -1 || status.indexOf('错误') !== -1) {
el.style.color = '#dc3545';
} else {
el.style.color = '#666';
}
}
// ====== 720 全景操作 ======
/**
* 初始化 720 引擎(独立实例,销毁其他引擎类型)
*/
function initEngine720() {
destroyAllEngines();
updateEngineStatus('未初始化');
update2dStatus('未初始化');
update720Status('初始化中...');
document.getElementById('btn-load2d').disabled = true;
try {
engine720 = new IflowEngine.BimEngine720('app', {
fov: 75,
enableZoom: true,
enableRotate: true,
sphereRadius: 500
});
update720Status('已初始化');
document.getElementById('btn-load720').disabled = false;
console.log('✅ 720 引擎初始化成功');
loadPanorama();
} catch (error) {
update720Status('初始化错误');
console.error('❌ 720 引擎初始化错误:', error);
}
}
function loadPanorama() {
if (!engine720) {
alert('请先初始化 720 引擎!');
return;
}
var url = 'http://lyz-1259524260.cos.ap-guangzhou.myqcloud.com/qcloud/2026/03/10/8ed54edd7e2740c7b6a3f534dd672d12.png';
update720Status('正在加载...');
try {
engine720.loadPanorama(url).then(function () {
update720Status('全景图已加载');
console.log('✅ 720 全景图加载完成');
}).catch(function (err) {
update720Status('加载失败');
console.error('❌ 720 全景图加载失败:', err);
});
} catch (error) {
update720Status('加载错误');
console.error('❌ 720 全景图加载错误:', error);
}
}
function update720Status(status) {
var el = document.getElementById('engine720-status');
if (!el) return;
el.textContent = status;
if (status === '已初始化' || status === '全景图已加载') {
el.style.color = '#28a745';
} else if (status === '正在加载...' || status === '初始化中...') {
el.style.color = '#1565c0';
} else if (status.indexOf('失败') !== -1 || status.indexOf('错误') !== -1) {
el.style.color = '#dc3545';
} else {
el.style.color = '#666';
}
}
</script>
</body>