This commit is contained in:
2026-04-24 11:20:27 +08:00
parent e7c1611f6b
commit 09359a1647
20 changed files with 1565 additions and 259 deletions

View File

@ -21,6 +21,12 @@
#app {
width: 100vw;
height: 100vh;
display: flex;
position: relative;
}
#canvas-container {
flex: 1;
position: relative;
}
@ -30,6 +36,157 @@
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;
@ -63,108 +220,210 @@
<body>
<div id="app">
<canvas id="renderDom"></canvas>
<div id="progress-container" style="display: none;">
<div id="progress-bar"></div>
<div id="progress-text">0%</div>
<!-- 画布区域 -->
<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">百叶A</label>
</div>
<div class="option-checkbox">
<input type="checkbox" id="louver-2" data-option="louver-2">
<label for="louver-2">百叶B</label>
</div>
<div class="option-checkbox">
<input type="checkbox" id="louver-3" data-option="louver-3">
<label for="louver-3">百叶C</label>
</div>
<div class="option-checkbox">
<input type="checkbox" id="louver-4" data-option="louver-4">
<label for="louver-4">百叶D</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';
// import { kernel } from 'https://sdk.zguiy.com/zt/assets/index.js';
// ========== UI 交互逻辑 ==========
const config = {
container: document.querySelector('#renderDom'),
modelUrlList: ['/assets/model.glb'],
env: { envPath: '/assets/hdr.env', intensity: 1.2, rotationY: 0.3, background: false },
};
// 折叠面板切换
document.querySelectorAll('.category-header').forEach(header => {
header.addEventListener('click', function () {
const content = this.nextElementSibling;
const arrow = this.querySelector('.category-arrow');
kernel.init(config);
kernel.on('model:load:progress', (data) => {
console.log('模型加载事件', data);
const progress = data.progress || 0;
const progressBar = document.getElementById('progress-bar');
const progressText = document.getElementById('progress-text');
const progressContainer = document.getElementById('progress-container');
if (progressContainer) {
progressContainer.style.display = 'block';
}
if (progressBar) {
progressBar.style.width = `${progress * 100}%`;
}
if (progressText) {
progressText.textContent = `${Math.round(progress * 100)}%`;
}
});
kernel.on('model:loaded', (data) => {
console.log('模型加载完成', data);
// 隐藏进度条
const progressContainer = document.getElementById('progress-container');
if (progressContainer) {
progressContainer.style.display = 'none';
}
});
kernel.on('all:ready', (data) => {
console.log('所有模块加载完,', data);
kernel.material.apply({
target: 'Material__2',
attribute: 'alpha',
value: 0.5,
// 切换展开/收起状态
content.classList.toggle('expanded');
arrow.classList.toggle('expanded');
this.classList.toggle('active');
});
kernel.hotspot.render([
{
id: "h1",
name: "卷帘门",
meshName: "Valve_01",
icon: "/assets/btn_热点.png",
offset: [25, 25, 0],
radius: 20,
color: "#21c7ff",
payload: { type: "valve", code: "A" },
},
]);
});
// 单选按钮逻辑
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;
kernel.on('model:click', (data) => {
console.log('模型点击事件', data);
console.log(data);
// 同一组内取消其他选中状态
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
});
});
});
kernel.on('hotspot:click', (data) => {
console.log('热点被点击:', data);
const { id, name } = data
if (name === "卷帘门") {
kernel.door.toggle({ upY: 28, downY: 0, speed: 12 });
// 多选复选框逻辑
document.querySelectorAll('.option-checkbox input[type="checkbox"]').forEach(checkbox => {
checkbox.addEventListener('change', function () {
const category = this.closest('.config-category');
const categoryName = category.querySelector('.category-header').dataset.category;
const optionGroup = this.closest('.option-group');
// Y轴剖切只作用于卷帘门网格保留下方剖掉上方
const clipHeight = 28; // 调整这个值找到合适的剖切高度
console.log('设置剖切:', clipHeight);
kernel.clipping.setY(clipHeight, true, ['Box005.001', 'Box006.001']);
}
// 获取当前组所有选中的值
const selectedValues = Array.from(
optionGroup.querySelectorAll('input[type="checkbox"]:checked')
).map(cb => ({
value: cb.dataset.option,
text: cb.nextElementSibling.textContent
}));
// data 包含: { id, name, meshName, payload }
// 触发自定义事件
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 (category === "louver") {
selectedValues.forEach(element => {
if (checked) {
kernel.model.add(element.text,`https://sdk.zguiy.com/resurces/model/${element.text}.glb`);
} else {
kernel.model.destroy(element.text);
}
});
}
// kernel.model.add('https://sdk.zguiy.com/resurces/model/百叶1.glb');
});
});
// 监听配置变更事件(供外部使用)
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>