1
This commit is contained in:
6
.env
Normal file
6
.env
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# API 配置
|
||||||
|
# 开发环境
|
||||||
|
VITE_API_BASE_URL=https://ztserver.zguiy.com
|
||||||
|
|
||||||
|
# 生产环境示例(部署时修改)
|
||||||
|
# VITE_API_BASE_URL=https://api.yourdomain.com
|
||||||
BIN
ScreenShot_2026-05-17_165150_324.png
Normal file
BIN
ScreenShot_2026-05-17_165150_324.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 137 KiB |
286
examples/README.md
Normal file
286
examples/README.md
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
# SDK 调用示例
|
||||||
|
|
||||||
|
本目录包含两种 SDK 调用方式的完整示例。
|
||||||
|
|
||||||
|
## 📁 文件说明
|
||||||
|
|
||||||
|
- `example-module.html` - ES Module 方式调用示例
|
||||||
|
- `example-global.html` - 全局脚本方式调用示例
|
||||||
|
|
||||||
|
## 🚀 两种调用方式对比
|
||||||
|
|
||||||
|
### 1. ES Module 方式 (推荐)
|
||||||
|
|
||||||
|
**文件:** `example-module.html`
|
||||||
|
|
||||||
|
**特点:**
|
||||||
|
- ✅ 现代化的模块化开发方式
|
||||||
|
- ✅ 支持按需导入,代码更清晰
|
||||||
|
- ✅ 更好的 IDE 智能提示
|
||||||
|
- ✅ 适合现代前端框架(Vue、React、Angular)
|
||||||
|
|
||||||
|
**引入方式:**
|
||||||
|
```html
|
||||||
|
<script type="module">
|
||||||
|
import { kernel } from 'https://sdk.zguiy.com/zt/assets/index.js';
|
||||||
|
|
||||||
|
kernel.init(config);
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
**适用场景:**
|
||||||
|
- 现代浏览器环境(Chrome 61+, Firefox 60+, Safari 11+, Edge 16+)
|
||||||
|
- 使用构建工具的项目(Vite、Webpack、Rollup)
|
||||||
|
- Vue/React/Angular 等框架项目
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. 全局脚本方式 (兼容性好)
|
||||||
|
|
||||||
|
**文件:** `example-global.html`
|
||||||
|
|
||||||
|
**特点:**
|
||||||
|
- ✅ 兼容性最好,支持所有浏览器
|
||||||
|
- ✅ 无需构建工具,直接引入即可使用
|
||||||
|
- ✅ 适合传统 HTML 页面
|
||||||
|
- ⚠️ 会污染全局命名空间
|
||||||
|
|
||||||
|
**引入方式:**
|
||||||
|
```html
|
||||||
|
<script src="https://sdk.zguiy.com/zt/assets/index.global.js"></script>
|
||||||
|
<script>
|
||||||
|
const sdkKernel = window.faceSDK.kernel;
|
||||||
|
|
||||||
|
sdkKernel.init(config);
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
**适用场景:**
|
||||||
|
- 需要兼容旧版浏览器
|
||||||
|
- 传统 HTML 页面(无构建工具)
|
||||||
|
- 快速原型开发
|
||||||
|
- 第三方页面集成
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📖 使用方法
|
||||||
|
|
||||||
|
### 基础配置
|
||||||
|
|
||||||
|
两种方式的配置参数完全相同:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const config = {
|
||||||
|
// 必填:渲染容器 ID
|
||||||
|
container: 'renderDom',
|
||||||
|
|
||||||
|
// 方式1:自动加载模型(从后端 API 获取)
|
||||||
|
autoLoadModels: true,
|
||||||
|
autoLoadModelsUrl: 'https://ztserver.zguiy.com/api/models/auto-load/list',
|
||||||
|
|
||||||
|
// 方式2:手动指定模型列表
|
||||||
|
// modelUrlList: [
|
||||||
|
// 'https://sdk.zguiy.com/resurces/model/model1.glb',
|
||||||
|
// 'https://sdk.zguiy.com/resurces/model/model2.glb'
|
||||||
|
// ],
|
||||||
|
|
||||||
|
// 环境配置
|
||||||
|
env: {
|
||||||
|
envPath: 'https://sdk.zguiy.com/resurces/hdr/hdr.env',
|
||||||
|
intensity: 1.2, // 环境光强度
|
||||||
|
rotationY: 0.3 // 环境贴图旋转角度
|
||||||
|
},
|
||||||
|
|
||||||
|
// 相机配置
|
||||||
|
camera: {
|
||||||
|
alpha: Math.PI / 2, // 水平角度
|
||||||
|
beta: Math.PI / 3, // 垂直角度
|
||||||
|
radius: 50 // 距离
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 事件监听
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 模型加载进度
|
||||||
|
kernel.on('model:load:progress', (data) => {
|
||||||
|
console.log('加载进度:', data.progress); // 0-1
|
||||||
|
});
|
||||||
|
|
||||||
|
// 模型加载完成
|
||||||
|
kernel.on('model:loaded', (data) => {
|
||||||
|
console.log('加载完成:', data.models);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 模型点击事件
|
||||||
|
kernel.on('model:click', (data) => {
|
||||||
|
console.log('点击:', data.meshName, data.position);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 热点点击事件
|
||||||
|
kernel.on('hotspot:click', (event) => {
|
||||||
|
console.log('热点:', event.name, event.payload);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 错误事件
|
||||||
|
kernel.on('error', (error) => {
|
||||||
|
console.error('错误:', error.message);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌐 在线演示
|
||||||
|
|
||||||
|
### 本地运行
|
||||||
|
|
||||||
|
1. **ES Module 方式:**
|
||||||
|
```bash
|
||||||
|
# 需要本地服务器(因为 ES Module 不支持 file:// 协议)
|
||||||
|
npx serve .
|
||||||
|
# 访问 http://localhost:3000/example-module.html
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **全局脚本方式:**
|
||||||
|
```bash
|
||||||
|
# 可以直接双击打开,或使用本地服务器
|
||||||
|
# 双击 example-global.html 即可
|
||||||
|
```
|
||||||
|
|
||||||
|
### 部署到服务器
|
||||||
|
|
||||||
|
将示例文件上传到任意 Web 服务器即可访问。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 集成到项目
|
||||||
|
|
||||||
|
### Vue 3 项目
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<canvas ref="canvasRef"></canvas>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue';
|
||||||
|
import { kernel } from 'https://sdk.zguiy.com/zt/assets/index.js';
|
||||||
|
|
||||||
|
const canvasRef = ref(null);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
kernel.init({
|
||||||
|
container: canvasRef.value,
|
||||||
|
autoLoadModels: true,
|
||||||
|
autoLoadModelsUrl: 'https://ztserver.zguiy.com/api/models/auto-load/list'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
### React 项目
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import { useEffect, useRef } from 'react';
|
||||||
|
|
||||||
|
function ModelViewer() {
|
||||||
|
const canvasRef = useRef(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
import('https://sdk.zguiy.com/zt/assets/index.js').then(({ kernel }) => {
|
||||||
|
kernel.init({
|
||||||
|
container: canvasRef.current,
|
||||||
|
autoLoadModels: true,
|
||||||
|
autoLoadModelsUrl: 'https://ztserver.zguiy.com/api/models/auto-load/list'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return <canvas ref={canvasRef} />;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 原生 HTML
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>3D 模型展示</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<canvas id="renderDom"></canvas>
|
||||||
|
|
||||||
|
<script src="https://sdk.zguiy.com/zt/assets/index.global.js"></script>
|
||||||
|
<script>
|
||||||
|
window.faceSDK.kernel.init({
|
||||||
|
container: 'renderDom',
|
||||||
|
autoLoadModels: true,
|
||||||
|
autoLoadModelsUrl: 'https://ztserver.zguiy.com/api/models/auto-load/list'
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 API 文档
|
||||||
|
|
||||||
|
### 初始化
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
kernel.init(config)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 事件系统
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
kernel.on(eventName, callback) // 监听事件
|
||||||
|
kernel.off(eventName, callback) // 取消监听
|
||||||
|
kernel.emit(eventName, data) // 触发事件
|
||||||
|
```
|
||||||
|
|
||||||
|
### 可用事件
|
||||||
|
|
||||||
|
| 事件名 | 说明 | 回调参数 |
|
||||||
|
|--------|------|----------|
|
||||||
|
| `model:load:progress` | 模型加载进度 | `{ progress: number }` |
|
||||||
|
| `model:loaded` | 模型加载完成 | `{ models: Array }` |
|
||||||
|
| `model:click` | 模型点击 | `{ meshName, position, materialName }` |
|
||||||
|
| `hotspot:click` | 热点点击 | `{ id, name, payload }` |
|
||||||
|
| `error` | 错误 | `{ message, code }` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ❓ 常见问题
|
||||||
|
|
||||||
|
### Q: ES Module 方式报错 "CORS policy"?
|
||||||
|
**A:** ES Module 必须通过 HTTP(S) 协议访问,不能使用 `file://` 协议。请使用本地服务器(如 `npx serve`)。
|
||||||
|
|
||||||
|
### Q: 全局脚本方式找不到 `window.faceSDK`?
|
||||||
|
**A:** 确保 `index.global.js` 已完全加载。可以在 `<script>` 标签中添加 `onload` 事件:
|
||||||
|
```html
|
||||||
|
<script src="https://sdk.zguiy.com/zt/assets/index.global.js" onload="initSDK()"></script>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Q: 如何选择使用哪种方式?
|
||||||
|
**A:**
|
||||||
|
- 现代项目 + 构建工具 → 使用 **ES Module**
|
||||||
|
- 传统 HTML 页面 + 无构建工具 → 使用 **全局脚本**
|
||||||
|
- 需要兼容旧浏览器 → 使用 **全局脚本**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📞 技术支持
|
||||||
|
|
||||||
|
- SDK 文档: https://sdk.zguiy.com/docs
|
||||||
|
- 后端 API: https://ztserver.zguiy.com
|
||||||
|
- 问题反馈: [GitHub Issues](https://github.com/your-repo/issues)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📄 许可证
|
||||||
|
|
||||||
|
MIT License
|
||||||
207
examples/example-global.html
Normal file
207
examples/example-global.html
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>SDK 调用示例 - 全局脚本方式</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;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#renderDom {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
color: #fff;
|
||||||
|
font-size: 18px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-bar {
|
||||||
|
width: 300px;
|
||||||
|
height: 4px;
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
border-radius: 2px;
|
||||||
|
margin-top: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-progress {
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, #4CAF50, #8BC34A);
|
||||||
|
width: 0%;
|
||||||
|
transition: width 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-panel {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
left: 20px;
|
||||||
|
background: rgba(30, 30, 45, 0.9);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
padding: 15px 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 14px;
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-title {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: #4CAF50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<canvas id="renderDom"></canvas>
|
||||||
|
<div class="loading" id="loading">
|
||||||
|
<div>加载中...</div>
|
||||||
|
<div class="loading-bar">
|
||||||
|
<div class="loading-progress" id="progress"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-panel" style="display: none;" id="info">
|
||||||
|
<div class="info-title">SDK 信息</div>
|
||||||
|
<div class="info-item">调用方式: 全局脚本</div>
|
||||||
|
<div class="info-item">SDK 地址: https://sdk.zguiy.com/zt/assets/index.global.js</div>
|
||||||
|
<div class="info-item" id="modelCount">模型数量: 0</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 全局脚本方式引入 SDK -->
|
||||||
|
<script src="https://sdk.zguiy.com/zt/assets/index.global.js"></script>
|
||||||
|
<script>
|
||||||
|
// 从全局对象获取 SDK kernel
|
||||||
|
const sdkKernel = window.faceSDK && window.faceSDK.kernel;
|
||||||
|
|
||||||
|
if (!sdkKernel) {
|
||||||
|
console.error('faceSDK kernel 不可用,请确认 index.global.js 已正确加载');
|
||||||
|
alert('SDK 加载失败,请检查网络连接');
|
||||||
|
} else {
|
||||||
|
// SDK 配置
|
||||||
|
const config = {
|
||||||
|
container: 'renderDom',
|
||||||
|
// 自动加载的模型列表(从后端 API 获取)
|
||||||
|
autoLoadModels: true,
|
||||||
|
autoLoadModelsUrl: 'https://ztserver.zguiy.com/api/models/auto-load/list',
|
||||||
|
// 或者手动指定模型列表
|
||||||
|
// modelUrlList: ['https://sdk.zguiy.com/resurces/model/model.glb'],
|
||||||
|
// 环境配置
|
||||||
|
env: {
|
||||||
|
envPath: 'https://sdk.zguiy.com/resurces/hdr/hdr.env',
|
||||||
|
intensity: 1.2,
|
||||||
|
rotationY: 0.3
|
||||||
|
},
|
||||||
|
// 相机配置
|
||||||
|
camera: {
|
||||||
|
alpha: Math.PI / 2,
|
||||||
|
beta: Math.PI / 3,
|
||||||
|
radius: 50
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化 SDK
|
||||||
|
sdkKernel.init(config);
|
||||||
|
|
||||||
|
// 监听加载进度
|
||||||
|
sdkKernel.on('model:load:progress', function (data) {
|
||||||
|
console.log('模型加载进度:', data);
|
||||||
|
var progress = document.getElementById('progress');
|
||||||
|
if (progress && data.progress !== undefined) {
|
||||||
|
progress.style.width = (data.progress * 100) + '%';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听模型加载完成
|
||||||
|
sdkKernel.on('model:loaded', function (data) {
|
||||||
|
console.log('模型加载完成:', data);
|
||||||
|
|
||||||
|
// 隐藏加载提示
|
||||||
|
var loading = document.getElementById('loading');
|
||||||
|
if (loading) {
|
||||||
|
loading.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示信息面板
|
||||||
|
var info = document.getElementById('info');
|
||||||
|
if (info) {
|
||||||
|
info.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新模型数量
|
||||||
|
var modelCount = document.getElementById('modelCount');
|
||||||
|
if (modelCount && data.models) {
|
||||||
|
modelCount.textContent = '模型数量: ' + data.models.length;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听模型点击事件
|
||||||
|
sdkKernel.on('model:click', function (data) {
|
||||||
|
console.log('模型被点击:', data);
|
||||||
|
var meshName = data.meshName;
|
||||||
|
var position = data.position;
|
||||||
|
var materialName = data.materialName;
|
||||||
|
|
||||||
|
alert('点击了模型:\n网格: ' + meshName + '\n材质: ' + materialName + '\n位置: [' + position.x.toFixed(2) + ', ' + position.y.toFixed(2) + ', ' + position.z.toFixed(2) + ']');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听热点点击事件
|
||||||
|
sdkKernel.on('hotspot:click', function (event) {
|
||||||
|
console.log('热点被点击:', event);
|
||||||
|
var id = event.id;
|
||||||
|
var name = event.name;
|
||||||
|
var payload = event.payload;
|
||||||
|
|
||||||
|
if (payload && payload.skus && payload.skus.length > 0) {
|
||||||
|
console.log('热点关联的SKU列表:', payload.skus);
|
||||||
|
alert('热点: ' + name + '\nSKU数量: ' + payload.skus.length);
|
||||||
|
} else {
|
||||||
|
alert('热点: ' + name + '\n暂无关联产品');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听错误事件
|
||||||
|
sdkKernel.on('error', function (error) {
|
||||||
|
console.error('SDK 错误:', error);
|
||||||
|
alert('加载失败: ' + error.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 暴露到全局,方便调试
|
||||||
|
window.kernel = sdkKernel;
|
||||||
|
console.log('SDK 已初始化,可通过 window.kernel 访问');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
197
examples/example-module.html
Normal file
197
examples/example-module.html
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>SDK 调用示例 - ES Module 方式</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;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#renderDom {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
color: #fff;
|
||||||
|
font-size: 18px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-bar {
|
||||||
|
width: 300px;
|
||||||
|
height: 4px;
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
border-radius: 2px;
|
||||||
|
margin-top: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-progress {
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, #4CAF50, #8BC34A);
|
||||||
|
width: 0%;
|
||||||
|
transition: width 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-panel {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
left: 20px;
|
||||||
|
background: rgba(30, 30, 45, 0.9);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
padding: 15px 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 14px;
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-title {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: #4CAF50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<canvas id="renderDom"></canvas>
|
||||||
|
<div class="loading" id="loading">
|
||||||
|
<div>加载中...</div>
|
||||||
|
<div class="loading-bar">
|
||||||
|
<div class="loading-progress" id="progress"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-panel" style="display: none;" id="info">
|
||||||
|
<div class="info-title">SDK 信息</div>
|
||||||
|
<div class="info-item">调用方式: ES Module</div>
|
||||||
|
<div class="info-item">SDK 地址: https://sdk.zguiy.com/zt/assets/index.js</div>
|
||||||
|
<div class="info-item" id="modelCount">模型数量: 0</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ES Module 方式引入 -->
|
||||||
|
<script type="module">
|
||||||
|
// 从 CDN 导入 SDK
|
||||||
|
import { kernel } from 'https://sdk.zguiy.com/zt/assets/index.js';
|
||||||
|
|
||||||
|
// SDK 配置
|
||||||
|
const config = {
|
||||||
|
container: 'renderDom',
|
||||||
|
// 自动加载的模型列表(从后端 API 获取)
|
||||||
|
autoLoadModels: true,
|
||||||
|
autoLoadModelsUrl: 'https://ztserver.zguiy.com/api/models/auto-load/list',
|
||||||
|
// 或者手动指定模型列表
|
||||||
|
// modelUrlList: ['https://sdk.zguiy.com/resurces/model/model.glb'],
|
||||||
|
// 环境配置
|
||||||
|
env: {
|
||||||
|
envPath: 'https://sdk.zguiy.com/resurces/hdr/hdr.env',
|
||||||
|
intensity: 1.2,
|
||||||
|
rotationY: 0.3
|
||||||
|
},
|
||||||
|
// 相机配置
|
||||||
|
camera: {
|
||||||
|
alpha: Math.PI / 2,
|
||||||
|
beta: Math.PI / 3,
|
||||||
|
radius: 50
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化 SDK
|
||||||
|
kernel.init(config);
|
||||||
|
|
||||||
|
// 监听加载进度
|
||||||
|
kernel.on('model:load:progress', (data) => {
|
||||||
|
console.log('模型加载进度:', data);
|
||||||
|
const progress = document.getElementById('progress');
|
||||||
|
if (progress && data.progress !== undefined) {
|
||||||
|
progress.style.width = `${data.progress * 100}%`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听模型加载完成
|
||||||
|
kernel.on('model:loaded', (data) => {
|
||||||
|
console.log('模型加载完成:', data);
|
||||||
|
|
||||||
|
// 隐藏加载提示
|
||||||
|
const loading = document.getElementById('loading');
|
||||||
|
if (loading) {
|
||||||
|
loading.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示信息面板
|
||||||
|
const info = document.getElementById('info');
|
||||||
|
if (info) {
|
||||||
|
info.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新模型数量
|
||||||
|
const modelCount = document.getElementById('modelCount');
|
||||||
|
if (modelCount && data.models) {
|
||||||
|
modelCount.textContent = `模型数量: ${data.models.length}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听模型点击事件
|
||||||
|
kernel.on('model:click', (data) => {
|
||||||
|
console.log('模型被点击:', data);
|
||||||
|
const { meshName, position, materialName } = data;
|
||||||
|
|
||||||
|
alert(`点击了模型:\n网格: ${meshName}\n材质: ${materialName}\n位置: [${position.x.toFixed(2)}, ${position.y.toFixed(2)}, ${position.z.toFixed(2)}]`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听热点点击事件
|
||||||
|
kernel.on('hotspot:click', (event) => {
|
||||||
|
console.log('热点被点击:', event);
|
||||||
|
const { id, name, payload } = event;
|
||||||
|
|
||||||
|
if (payload && payload.skus && payload.skus.length > 0) {
|
||||||
|
console.log('热点关联的SKU列表:', payload.skus);
|
||||||
|
alert(`热点: ${name}\nSKU数量: ${payload.skus.length}`);
|
||||||
|
} else {
|
||||||
|
alert(`热点: ${name}\n暂无关联产品`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听错误事件
|
||||||
|
kernel.on('error', (error) => {
|
||||||
|
console.error('SDK 错误:', error);
|
||||||
|
alert(`加载失败: ${error.message}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 暴露到全局,方便调试
|
||||||
|
window.kernel = kernel;
|
||||||
|
console.log('SDK 已初始化,可通过 window.kernel 访问');
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
18
index.html
18
index.html
@ -454,7 +454,7 @@
|
|||||||
<script type="module" src="./index.js"></script>
|
<script type="module" src="./index.js"></script>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import { kernel } from './src/main.ts';
|
import { kernel } from './src/main.ts';
|
||||||
import { init, getAutoLoadModelList, getPlacementZone, getEvent, getHotspot,executeEvent2 } from './index.js';
|
import { init, getAutoLoadModelList, getPlacementZone, getEvent, getHotspot,executeEvent2 ,getProductConfig} from './index.js';
|
||||||
|
|
||||||
await init()
|
await init()
|
||||||
await getAutoLoadModelList()
|
await getAutoLoadModelList()
|
||||||
@ -531,21 +531,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
const currentText = this.textContent;
|
const currentText = this.textContent;
|
||||||
const response = await fetch(`http://localhost:3001/api/product-configs/by-sku/${currentText}`);
|
await getProductConfig(currentText)
|
||||||
const result = await response.json();
|
|
||||||
if (result.code === 200) {
|
|
||||||
console.log(result.data);
|
|
||||||
const { enable_placement_zone } = result.data;
|
|
||||||
sku = currentText;
|
|
||||||
// await initPlacementZoneConfig();
|
|
||||||
if (enable_placement_zone) {
|
|
||||||
getPlacementZone(currentText)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
executeEvent2(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
41
index.js
41
index.js
@ -1,5 +1,6 @@
|
|||||||
import { EXRCubeTexture } from '@babylonjs/core';
|
import { EXRCubeTexture } from '@babylonjs/core';
|
||||||
import { kernel } from './src/main.ts';
|
import { kernel } from './src/main.ts';
|
||||||
|
import apiConfig from './src/config.js';
|
||||||
|
|
||||||
//初始化
|
//初始化
|
||||||
export const init = async () => {
|
export const init = async () => {
|
||||||
@ -28,7 +29,10 @@ export const init = async () => {
|
|||||||
|
|
||||||
//初始化加载模型
|
//初始化加载模型
|
||||||
export const getAutoLoadModelList = async () => {
|
export const getAutoLoadModelList = async () => {
|
||||||
const response = await fetch('http://localhost:3001/api/models/auto-load/list')
|
const url = apiConfig.getApiUrl('/api/models/auto-load/list')
|
||||||
|
console.log('API URL:', url)
|
||||||
|
console.log('apiConfig:', apiConfig)
|
||||||
|
const response = await fetch(url)
|
||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
const models = data.data // 这就是模型列表
|
const models = data.data // 这就是模型列表
|
||||||
|
|
||||||
@ -58,7 +62,7 @@ export const getAutoLoadModelList = async () => {
|
|||||||
|
|
||||||
//获取放置区域
|
//获取放置区域
|
||||||
export const getPlacementZone = async (sku) => {
|
export const getPlacementZone = async (sku) => {
|
||||||
const response = await fetch(`http://localhost:3001/api/product-configs/by-sku/${sku}`);
|
const response = await fetch(apiConfig.getApiUrl(`/api/product-configs/by-sku/${sku}`));
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
if (result.code === 200) {
|
if (result.code === 200) {
|
||||||
// await initPlacementZoneConfig();
|
// await initPlacementZoneConfig();
|
||||||
@ -84,7 +88,7 @@ export const getPlacementZone = async (sku) => {
|
|||||||
export const getEvent = async (dropzone_data, sku) => {
|
export const getEvent = async (dropzone_data, sku) => {
|
||||||
// 将模型放置到该区域
|
// 将模型放置到该区域
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`http://localhost:3001/api/product-configs/by-sku/${sku}`);
|
const response = await fetch(apiConfig.getApiUrl(`/api/product-configs/by-sku/${sku}`));
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (result.code === 200 && result.data) {
|
if (result.code === 200 && result.data) {
|
||||||
@ -118,7 +122,7 @@ export const executeEvent = async (dropzone_data, result) => {
|
|||||||
|
|
||||||
// 先记录模型放置(会自动处理替换逻辑)
|
// 先记录模型放置(会自动处理替换逻辑)
|
||||||
kernel.dropZone.recordModelPlacement(wallName, index, modelId);
|
kernel.dropZone.recordModelPlacement(wallName, index, modelId);
|
||||||
console.log(Math.abs(rotation.y - 90) ,Math.abs(rotation.y - 90) > 5 ? 'x' : 'z' );
|
console.log(Math.abs(rotation.y - 90), Math.abs(rotation.y - 90) > 5 ? 'x' : 'z');
|
||||||
// 加载并放置模型
|
// 加载并放置模型
|
||||||
await kernel.model.add({
|
await kernel.model.add({
|
||||||
modelId: modelId,
|
modelId: modelId,
|
||||||
@ -126,7 +130,7 @@ export const executeEvent = async (dropzone_data, result) => {
|
|||||||
modelControlType: model_control_type,
|
modelControlType: model_control_type,
|
||||||
drag: {
|
drag: {
|
||||||
enable: true,
|
enable: true,
|
||||||
axis:rotation.y === 0 || rotation.y === 180 ? 'x' : 'z',
|
axis: rotation.y === 0 || rotation.y === 180 ? 'x' : 'z',
|
||||||
step: 0.1,
|
step: 0.1,
|
||||||
},
|
},
|
||||||
transform: {
|
transform: {
|
||||||
@ -159,6 +163,7 @@ export const executeEvent = async (dropzone_data, result) => {
|
|||||||
|
|
||||||
//换棚子
|
//换棚子
|
||||||
export const executeEvent2 = async (result) => {
|
export const executeEvent2 = async (result) => {
|
||||||
|
|
||||||
// 检查是否有模型更换事件
|
// 检查是否有模型更换事件
|
||||||
const hasModelChange = result.data.events.some(e => e.event_type === 'change_model');
|
const hasModelChange = result.data.events.some(e => e.event_type === 'change_model');
|
||||||
|
|
||||||
@ -173,6 +178,10 @@ export const executeEvent2 = async (result) => {
|
|||||||
if (event.event_type === 'change_model') {
|
if (event.event_type === 'change_model') {
|
||||||
const { target_data } = event;
|
const { target_data } = event;
|
||||||
console.log(event.target_data);
|
console.log(event.target_data);
|
||||||
|
if (!target_data) {
|
||||||
|
console.error('change_model事件缺少target_data')
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
const { id, name, file_url, model_control_type, category, placement_zone } = target_data;
|
const { id, name, file_url, model_control_type, category, placement_zone } = target_data;
|
||||||
console.log('替换百叶模型:', event);
|
console.log('替换百叶模型:', event);
|
||||||
@ -227,7 +236,7 @@ export const executeEvent2 = async (result) => {
|
|||||||
export const getHotspot = async () => {
|
export const getHotspot = async () => {
|
||||||
try {
|
try {
|
||||||
// 从后端获取激活状态的热点列表
|
// 从后端获取激活状态的热点列表
|
||||||
const response = await fetch('http://localhost:3001/api/hotspots?status=active&page=1&pageSize=100');
|
const response = await fetch(apiConfig.getApiUrl('/api/hotspots?status=active&page=1&pageSize=100'));
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (result.code === 200 && result.data.list.length > 0) {
|
if (result.code === 200 && result.data.list.length > 0) {
|
||||||
@ -256,3 +265,23 @@ export const getHotspot = async () => {
|
|||||||
console.error('获取热点数据失败:', error);
|
console.error('获取热点数据失败:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getProductConfig = async (sku) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${apiConfig.getApiUrl(`/api/product-configs/by-sku/${sku}`)}`);
|
||||||
|
const result = await response.json();
|
||||||
|
if (result.code === 200) {
|
||||||
|
console.log(result.data);
|
||||||
|
const { enable_placement_zone } = result.data;
|
||||||
|
// await initPlacementZoneConfig();
|
||||||
|
if (enable_placement_zone) {
|
||||||
|
getPlacementZone(sku)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
executeEvent2(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取产品配置失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,7 +8,7 @@ export type HttpClient = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const httpClient: HttpClient = {
|
export const httpClient: HttpClient = {
|
||||||
baseURL: 'http://localhost:3000',
|
baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:3000',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
|
|||||||
12
src/config.js
Normal file
12
src/config.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// SDK 配置
|
||||||
|
const config = {
|
||||||
|
// API 基础地址
|
||||||
|
apiBaseUrl: import.meta.env.VITE_API_BASE_URL || 'http://localhost:26517',
|
||||||
|
|
||||||
|
// 获取完整的 API 地址
|
||||||
|
getApiUrl(path) {
|
||||||
|
return `${this.apiBaseUrl}${path}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default config
|
||||||
Reference in New Issue
Block a user