440 lines
15 KiB
HTML
440 lines
15 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>3D Model Showcase SDK - TS</title>
|
|
<style>
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
overflow: hidden;
|
|
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
|
|
}
|
|
|
|
#app {
|
|
width: 100vw;
|
|
height: 100vh;
|
|
display: flex;
|
|
position: relative;
|
|
}
|
|
|
|
#canvas-container {
|
|
flex: 1;
|
|
position: relative;
|
|
}
|
|
|
|
#renderDom {
|
|
width: 100%;
|
|
height: 100%;
|
|
display: block;
|
|
}
|
|
|
|
#config-panel {
|
|
width: 320px;
|
|
background: rgba(30, 30, 45, 0.95);
|
|
backdrop-filter: blur(10px);
|
|
overflow-y: auto;
|
|
padding: 20px;
|
|
box-shadow: -2px 0 10px rgba(0, 0, 0, 0.3);
|
|
}
|
|
|
|
#config-panel::-webkit-scrollbar {
|
|
width: 6px;
|
|
}
|
|
|
|
#config-panel::-webkit-scrollbar-track {
|
|
background: rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
#config-panel::-webkit-scrollbar-thumb {
|
|
background: rgba(255, 255, 255, 0.3);
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.config-title {
|
|
color: #fff;
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
margin-bottom: 20px;
|
|
padding-bottom: 10px;
|
|
border-bottom: 2px solid rgba(255, 255, 255, 0.2);
|
|
}
|
|
|
|
.config-category {
|
|
margin-bottom: 15px;
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
background: rgba(255, 255, 255, 0.05);
|
|
}
|
|
|
|
.category-header {
|
|
padding: 12px 15px;
|
|
background: rgba(255, 255, 255, 0.1);
|
|
color: #fff;
|
|
cursor: pointer;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
transition: background 0.3s;
|
|
user-select: none;
|
|
}
|
|
|
|
.category-header:hover {
|
|
background: rgba(255, 255, 255, 0.15);
|
|
}
|
|
|
|
.category-header.active {
|
|
background: rgba(76, 175, 80, 0.3);
|
|
}
|
|
|
|
.category-title {
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.category-arrow {
|
|
transition: transform 0.3s;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.category-arrow.expanded {
|
|
transform: rotate(180deg);
|
|
}
|
|
|
|
.category-content {
|
|
display: grid;
|
|
grid-template-rows: 0fr;
|
|
overflow: hidden;
|
|
transition: grid-template-rows 0.3s ease, padding 0.3s ease;
|
|
padding: 0 15px;
|
|
}
|
|
|
|
.category-content.expanded {
|
|
grid-template-rows: 1fr;
|
|
padding: 15px;
|
|
}
|
|
|
|
.category-content>* {
|
|
min-height: 0;
|
|
}
|
|
|
|
.option-item {
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.option-label {
|
|
color: rgba(255, 255, 255, 0.8);
|
|
font-size: 13px;
|
|
margin-bottom: 8px;
|
|
display: block;
|
|
}
|
|
|
|
.option-group {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
}
|
|
|
|
.option-btn {
|
|
padding: 8px 16px;
|
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
|
background: rgba(255, 255, 255, 0.05);
|
|
color: #fff;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-size: 12px;
|
|
transition: all 0.3s;
|
|
}
|
|
|
|
.option-btn:hover {
|
|
background: rgba(255, 255, 255, 0.1);
|
|
border-color: rgba(255, 255, 255, 0.5);
|
|
}
|
|
|
|
.option-btn.selected {
|
|
background: rgba(76, 175, 80, 0.6);
|
|
border-color: #4CAF50;
|
|
}
|
|
|
|
.option-checkbox {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 8px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
transition: background 0.3s;
|
|
}
|
|
|
|
.option-checkbox:hover {
|
|
background: rgba(255, 255, 255, 0.05);
|
|
}
|
|
|
|
.option-checkbox input[type="checkbox"] {
|
|
margin-right: 8px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.option-checkbox label {
|
|
color: rgba(255, 255, 255, 0.8);
|
|
font-size: 12px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
/* 进度条样式 */
|
|
#progress-container {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
width: 80%;
|
|
max-width: 500px;
|
|
background: rgba(255, 255, 255, 0.2);
|
|
border-radius: 10px;
|
|
padding: 10px;
|
|
z-index: 1000;
|
|
}
|
|
|
|
#progress-bar {
|
|
width: 0%;
|
|
height: 10px;
|
|
background: linear-gradient(90deg, #4CAF50, #45a049);
|
|
border-radius: 5px;
|
|
transition: width 0.1s ease;
|
|
}
|
|
|
|
#progress-text {
|
|
color: white;
|
|
text-align: center;
|
|
margin-top: 5px;
|
|
font-size: 14px;
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<div id="app">
|
|
<!-- 画布区域 -->
|
|
<div id="canvas-container">
|
|
<canvas id="renderDom"></canvas>
|
|
<div id="progress-container" style="display: none;">
|
|
<div id="progress-bar"></div>
|
|
<div id="progress-text">0%</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 配置面板 -->
|
|
<div id="config-panel">
|
|
<div class="config-title">选装选配</div>
|
|
|
|
<!-- 棚子尺寸 -->
|
|
<div class="config-category">
|
|
<div class="category-header" data-category="size">
|
|
<span class="category-title">棚子尺寸</span>
|
|
<span class="category-arrow">▼</span>
|
|
</div>
|
|
<div class="category-content">
|
|
<div class="option-group">
|
|
<button class="option-btn" data-option="size-1">3x3米</button>
|
|
<button class="option-btn" data-option="size-2">4x4米</button>
|
|
<button class="option-btn" data-option="size-3">5x5米</button>
|
|
<button class="option-btn" data-option="size-4">6x6米</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 棚子类型 -->
|
|
<div class="config-category">
|
|
<div class="category-header" data-category="type">
|
|
<span class="category-title">棚子类型</span>
|
|
<span class="category-arrow">▼</span>
|
|
</div>
|
|
<div class="category-content">
|
|
<div class="option-group">
|
|
<button class="option-btn" data-option="type-1">平顶</button>
|
|
<button class="option-btn" data-option="type-2">尖顶</button>
|
|
<button class="option-btn" data-option="type-3">弧形</button>
|
|
<button class="option-btn" data-option="type-4">异形</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 百叶 (多选) -->
|
|
<div class="config-category">
|
|
<div class="category-header" data-category="louver">
|
|
<span class="category-title">百叶</span>
|
|
<span class="category-arrow">▼</span>
|
|
</div>
|
|
<div class="category-content">
|
|
<div class="option-group">
|
|
<div class="option-checkbox">
|
|
<input type="checkbox" id="louver-1" data-option="louver-1">
|
|
<label for="louver-1">百叶1</label>
|
|
</div>
|
|
<div class="option-checkbox">
|
|
<input type="checkbox" id="louver-2" data-option="louver-2">
|
|
<label for="louver-2">百叶2</label>
|
|
</div>
|
|
<div class="option-checkbox">
|
|
<input type="checkbox" id="louver-3" data-option="louver-3">
|
|
<label for="louver-3">百叶3</label>
|
|
</div>
|
|
<div class="option-checkbox">
|
|
<input type="checkbox" id="louver-4" data-option="louver-4">
|
|
<label for="louver-4">百叶4</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 配色 -->
|
|
<div class="config-category">
|
|
<div class="category-header" data-category="color">
|
|
<span class="category-title">配色</span>
|
|
<span class="category-arrow">▼</span>
|
|
</div>
|
|
<div class="category-content">
|
|
<div class="option-group">
|
|
<button class="option-btn" data-option="color-1">白色</button>
|
|
<button class="option-btn" data-option="color-2">灰色</button>
|
|
<button class="option-btn" data-option="color-3">黑色</button>
|
|
<button class="option-btn" data-option="color-4">木色</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script type="module" src="./index.js"></script>
|
|
<script type="module">
|
|
import { kernel } from './src/main.ts';
|
|
|
|
// ========== UI 交互逻辑 ==========
|
|
|
|
// 折叠面板切换
|
|
document.querySelectorAll('.category-header').forEach(header => {
|
|
header.addEventListener('click', function () {
|
|
const content = this.nextElementSibling;
|
|
const arrow = this.querySelector('.category-arrow');
|
|
|
|
// 切换展开/收起状态
|
|
content.classList.toggle('expanded');
|
|
arrow.classList.toggle('expanded');
|
|
this.classList.toggle('active');
|
|
});
|
|
});
|
|
|
|
// 单选按钮逻辑
|
|
document.querySelectorAll('.option-btn').forEach(btn => {
|
|
btn.addEventListener('click', function () {
|
|
const optionGroup = this.parentElement;
|
|
const category = this.closest('.config-category');
|
|
const categoryName = category.querySelector('.category-header').dataset.category;
|
|
|
|
// 同一组内取消其他选中状态
|
|
optionGroup.querySelectorAll('.option-btn').forEach(b => {
|
|
b.classList.remove('selected');
|
|
});
|
|
|
|
// 选中当前按钮
|
|
this.classList.add('selected');
|
|
|
|
// 触发自定义事件
|
|
const event = new CustomEvent('config:change', {
|
|
detail: {
|
|
category: categoryName,
|
|
value: this.dataset.option,
|
|
text: this.textContent
|
|
}
|
|
});
|
|
document.dispatchEvent(event);
|
|
|
|
console.log('配置变更:', {
|
|
category: categoryName,
|
|
value: this.dataset.option,
|
|
text: this.textContent
|
|
});
|
|
});
|
|
});
|
|
|
|
// 多选复选框逻辑
|
|
document.querySelectorAll('.option-checkbox input[type="checkbox"]').forEach(checkbox => {
|
|
checkbox.addEventListener('change', async function () {
|
|
const category = this.closest('.config-category');
|
|
const categoryName = category.querySelector('.category-header').dataset.category;
|
|
const optionGroup = this.closest('.option-group');
|
|
const checked = this.checked;
|
|
|
|
// 获取当前组所有选中的值
|
|
const selectedValues = Array.from(
|
|
optionGroup.querySelectorAll('input[type="checkbox"]:checked')
|
|
).map(cb => ({
|
|
value: cb.dataset.option,
|
|
text: cb.nextElementSibling.textContent
|
|
}));
|
|
|
|
// 触发自定义事件
|
|
const event = new CustomEvent('config:change', {
|
|
detail: {
|
|
category: categoryName,
|
|
values: selectedValues,
|
|
checked: this.checked,
|
|
currentValue: this.dataset.option
|
|
}
|
|
});
|
|
document.dispatchEvent(event);
|
|
|
|
console.log('配置变更(多选):', {
|
|
category: categoryName,
|
|
selectedValues: selectedValues,
|
|
checked: this.checked,
|
|
currentValue: this.dataset.option
|
|
});
|
|
|
|
// 百叶模型加载/卸载逻辑
|
|
if (categoryName === "louver") {
|
|
const currentText = this.nextElementSibling.textContent;
|
|
const modelUrl = `https://sdk.zguiy.com/resurces/model/${currentText}.glb`;
|
|
console.log(modelUrl);
|
|
if (checked) {
|
|
// 加载模型
|
|
try {
|
|
await kernel.model.add(currentText, modelUrl);
|
|
console.log(`模型 ${currentText} 加载成功`);
|
|
} catch (error) {
|
|
console.error(`模型 ${currentText} 加载失败:`, error);
|
|
}
|
|
} else {
|
|
// 卸载模型
|
|
kernel.model.remove(currentText);
|
|
console.log(`模型 ${currentText} 已卸载`);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// 监听配置变更事件(供外部使用)
|
|
document.addEventListener('config:change', function (e) {
|
|
// 这里可以根据配置变更来操作 3D 模型
|
|
// 例如:
|
|
// if (e.detail.category === 'size') {
|
|
// kernel.model.replace('shed', `/models/shed-${e.detail.value}.glb`);
|
|
// }
|
|
// if (e.detail.category === 'color') {
|
|
// kernel.material.apply({
|
|
// target: 'ShedMaterial',
|
|
// attribute: 'baseColor',
|
|
// value: getColorValue(e.detail.value)
|
|
// });
|
|
// }
|
|
});
|
|
</script>
|
|
</body>
|
|
|
|
</html> |