| | |
| | | "moment": "^2.30.1", |
| | | "pinia": "^3.0.1", |
| | | "spark-md5": "^3.0.2", |
| | | "three": "^0.177.0", |
| | | "three-fbx-loader": "^1.0.3", |
| | | "three-orbitcontrols": "^2.110.3", |
| | | "vue": "^3.4.21", |
| | | "vue-router": "^4.3.0" |
| | | }, |
| | |
| | | "resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", |
| | | "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==" |
| | | }, |
| | | "node_modules/pako": { |
| | | "version": "1.0.11", |
| | | "resolved": "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz", |
| | | "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" |
| | | }, |
| | | "node_modules/parse-node-version": { |
| | | "version": "1.0.1", |
| | | "resolved": "https://registry.npmmirror.com/parse-node-version/-/parse-node-version-1.0.1.tgz", |
| | |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/mesqueeb" |
| | | } |
| | | }, |
| | | "node_modules/three": { |
| | | "version": "0.177.0", |
| | | "resolved": "https://registry.npmmirror.com/three/-/three-0.177.0.tgz", |
| | | "integrity": "sha512-EiXv5/qWAaGI+Vz2A+JfavwYCMdGjxVsrn3oBwllUoqYeaBO75J63ZfyaQKoiLrqNHoTlUc6PFgMXnS0kI45zg==" |
| | | }, |
| | | "node_modules/three-fbx-loader": { |
| | | "version": "1.0.3", |
| | | "resolved": "https://registry.npmmirror.com/three-fbx-loader/-/three-fbx-loader-1.0.3.tgz", |
| | | "integrity": "sha512-CQZ0IkwqX+ZbIca225mfKCq1feH8XJOf2zqMcC2bugvq20S7alHGsG9QEELbyN9zSL0EvkBXADVDO2lupF0E+A==", |
| | | "dependencies": { |
| | | "pako": "^1.0.6", |
| | | "three": "^0.89.0" |
| | | } |
| | | }, |
| | | "node_modules/three-fbx-loader/node_modules/three": { |
| | | "version": "0.89.0", |
| | | "resolved": "https://registry.npmmirror.com/three/-/three-0.89.0.tgz", |
| | | "integrity": "sha512-Evv3JolLQtag/lCWu1o3cgz2E5UYCSZHbh9lfBjeLz7nlK8DMmASID680Odl++ZPYk63rrZjPAMq88IrMP3GCA==" |
| | | }, |
| | | "node_modules/three-orbitcontrols": { |
| | | "version": "2.110.3", |
| | | "resolved": "https://registry.npmmirror.com/three-orbitcontrols/-/three-orbitcontrols-2.110.3.tgz", |
| | | "integrity": "sha512-BNNbksJwbN3/MmT0X/gjz5ZCchm7bjk26SUdtJYRxfEYjDfkb/0PeUTHE/KuyJ5vb/owK3mojyy3vcqDx99sRA==", |
| | | "deprecated": "three-js exposes real modules now via three/examples/jsm/...\nfor example to import Orbit, do\nimport { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'\n", |
| | | "peerDependencies": { |
| | | "three": ">= 0.110.0" |
| | | } |
| | | }, |
| | | "node_modules/tslib": { |
| | |
| | | "resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", |
| | | "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==" |
| | | }, |
| | | "pako": { |
| | | "version": "1.0.11", |
| | | "resolved": "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz", |
| | | "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" |
| | | }, |
| | | "parse-node-version": { |
| | | "version": "1.0.1", |
| | | "resolved": "https://registry.npmmirror.com/parse-node-version/-/parse-node-version-1.0.1.tgz", |
| | |
| | | } |
| | | } |
| | | }, |
| | | "three": { |
| | | "version": "0.177.0", |
| | | "resolved": "https://registry.npmmirror.com/three/-/three-0.177.0.tgz", |
| | | "integrity": "sha512-EiXv5/qWAaGI+Vz2A+JfavwYCMdGjxVsrn3oBwllUoqYeaBO75J63ZfyaQKoiLrqNHoTlUc6PFgMXnS0kI45zg==" |
| | | }, |
| | | "three-fbx-loader": { |
| | | "version": "1.0.3", |
| | | "resolved": "https://registry.npmmirror.com/three-fbx-loader/-/three-fbx-loader-1.0.3.tgz", |
| | | "integrity": "sha512-CQZ0IkwqX+ZbIca225mfKCq1feH8XJOf2zqMcC2bugvq20S7alHGsG9QEELbyN9zSL0EvkBXADVDO2lupF0E+A==", |
| | | "requires": { |
| | | "pako": "^1.0.6", |
| | | "three": "^0.89.0" |
| | | }, |
| | | "dependencies": { |
| | | "three": { |
| | | "version": "0.89.0", |
| | | "resolved": "https://registry.npmmirror.com/three/-/three-0.89.0.tgz", |
| | | "integrity": "sha512-Evv3JolLQtag/lCWu1o3cgz2E5UYCSZHbh9lfBjeLz7nlK8DMmASID680Odl++ZPYk63rrZjPAMq88IrMP3GCA==" |
| | | } |
| | | } |
| | | }, |
| | | "three-orbitcontrols": { |
| | | "version": "2.110.3", |
| | | "resolved": "https://registry.npmmirror.com/three-orbitcontrols/-/three-orbitcontrols-2.110.3.tgz", |
| | | "integrity": "sha512-BNNbksJwbN3/MmT0X/gjz5ZCchm7bjk26SUdtJYRxfEYjDfkb/0PeUTHE/KuyJ5vb/owK3mojyy3vcqDx99sRA==", |
| | | "requires": {} |
| | | }, |
| | | "tslib": { |
| | | "version": "2.8.1", |
| | | "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", |
| | |
| | | "moment": "^2.30.1", |
| | | "pinia": "^3.0.1", |
| | | "spark-md5": "^3.0.2", |
| | | "three": "^0.177.0", |
| | | "three-fbx-loader": "^1.0.3", |
| | | "three-orbitcontrols": "^2.110.3", |
| | | "vue": "^3.4.21", |
| | | "vue-router": "^4.3.0" |
| | | }, |
New file |
| | |
| | | <template> |
| | | <el-dialog |
| | | v-model="dialogVisible" |
| | | @open="openDialog" |
| | | destroy-on-close |
| | | class="prviewModel" |
| | | > |
| | | <div v-loading="loading"> |
| | | <div |
| | | id="container" |
| | | class="viewer-container" |
| | | v-if="selectData.md5" |
| | | ></div> |
| | | <el-empty v-else description="暂无数据" /> |
| | | </div> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import * as THREE from "three"; |
| | | import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader"; |
| | | import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; |
| | | import { ref, defineExpose, inject } from "vue"; |
| | | const config: any = inject("config"); |
| | | const dialogVisible = ref<boolean>(false); |
| | | const selectData = ref<any>(null); |
| | | const loading = ref<boolean>(false); |
| | | const openDialog = () => { |
| | | loading.value = true; |
| | | if (selectData.value.md5) { |
| | | initThree(); |
| | | } else { |
| | | loading.value = false |
| | | } |
| | | }; |
| | | const initThree = () => { |
| | | const container = document.getElementById("container"); |
| | | const scene = new THREE.Scene(); |
| | | const camera = new THREE.PerspectiveCamera( |
| | | 75, |
| | | container.clientWidth / container.clientHeight, |
| | | 0.1, |
| | | 10000 // 增大远平面距离 |
| | | ); |
| | | const renderer = new THREE.WebGLRenderer({ antialias: true }); |
| | | renderer.setSize(container.clientWidth, container.clientHeight); |
| | | container.appendChild(renderer.domElement); |
| | | |
| | | // 添加光源 |
| | | const light = new THREE.DirectionalLight(0xffffff, 2); |
| | | light.position.set(5, 10, 7.5); |
| | | scene.add(light); |
| | | |
| | | // 加载模型 |
| | | const loader = new FBXLoader(); |
| | | const token = localStorage.getItem(config.tokenKey); |
| | | loader.load( |
| | | config.requestCtx + |
| | | "/file/FileDownload/Download?md5=" + |
| | | selectData.value.md5 + |
| | | "&token=" + |
| | | token, |
| | | (object) => { |
| | | scene.add(object); |
| | | |
| | | // 创建控件 |
| | | const controls = new OrbitControls(camera, renderer.domElement); |
| | | controls.enableDamping = true; |
| | | controls.dampingFactor = 0.25; |
| | | controls.screenSpacePanning = false; |
| | | |
| | | // 1. 计算模型尺寸和中心点 |
| | | const box = new THREE.Box3().setFromObject(object); |
| | | const center = box.getCenter(new THREE.Vector3()); |
| | | const size = box.getSize(new THREE.Vector3()); |
| | | |
| | | // 2. 计算合适的相机距离 |
| | | const maxDim = Math.max(size.x, size.y, size.z); |
| | | const fov = camera.fov * (Math.PI / 180); |
| | | let cameraDistance = Math.abs(maxDim / (2 * Math.tan(fov / 2))); |
| | | |
| | | // 3. 设置相机位置和方向 |
| | | camera.position.copy(center); |
| | | camera.position.z += cameraDistance * 1.5; // 增加50%的额外空间 |
| | | camera.lookAt(center); |
| | | |
| | | // 4. 更新控件目标点 |
| | | controls.target.copy(center); |
| | | controls.update(); |
| | | |
| | | // 5. 调整相机剪裁平面 |
| | | const minDistance = cameraDistance * 0.1; |
| | | const maxDistance = cameraDistance * 10; |
| | | camera.near = minDistance > 0.1 ? minDistance : 0.1; |
| | | camera.far = maxDistance < 10000 ? maxDistance : 10000; |
| | | camera.updateProjectionMatrix(); |
| | | |
| | | function animate() { |
| | | requestAnimationFrame(animate); |
| | | controls.update(); |
| | | renderer.render(scene, camera); |
| | | } |
| | | animate(); |
| | | loading.value = false |
| | | }, |
| | | undefined, |
| | | (error) => { |
| | | console.error("加载模型失败:", error); |
| | | loading.value = false |
| | | }, |
| | | |
| | | ); |
| | | }; |
| | | const handleDialogVisible = (value: boolean, data: any) => { |
| | | dialogVisible.value = value; |
| | | selectData.value = data; |
| | | console.log("select", selectData.value); |
| | | }; |
| | | defineExpose({ handleDialogVisible }); |
| | | </script> |
| | | |
| | | <style lang="less"> |
| | | .prviewModel { |
| | | width: 60vw; |
| | | min-height: 580px; |
| | | .viewer-container { |
| | | width: 100%; |
| | | height: 60vh; |
| | | .el-empty { |
| | | margin-top: 100px !important; |
| | | } |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="showModel" v-loading="loading"> |
| | | <div :id="'container' + props.md5 + props.index" class="viewer-container" v-if="props.md5"></div> |
| | | <el-empty v-else description="暂无数据" image-size="80" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { ref, onMounted, defineProps,inject } from "vue"; |
| | | import * as THREE from "three"; |
| | | import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader"; |
| | | import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; |
| | | const props = defineProps<{md5:string,index:number}>(); |
| | | const config: any = inject("config"); |
| | | const loading = ref<boolean>(false); |
| | | onMounted(() => { |
| | | loading.value = true; |
| | | if(props.md5) { |
| | | initThree(); |
| | | } else { |
| | | loading.value = false; |
| | | } |
| | | }); |
| | | const initThree = () => { |
| | | const container = document.getElementById("container" + props.md5 + props.index); |
| | | const scene = new THREE.Scene(); |
| | | const camera = new THREE.PerspectiveCamera( |
| | | 75, |
| | | container.clientWidth / container.clientHeight, |
| | | 0.1, |
| | | 10000 // 增大远平面距离 |
| | | ); |
| | | const renderer = new THREE.WebGLRenderer({ antialias: true }); |
| | | renderer.setSize(container.clientWidth, container.clientHeight); |
| | | container.appendChild(renderer.domElement); |
| | | |
| | | // 添加光源 |
| | | const light = new THREE.DirectionalLight(0xffffff, 2); |
| | | light.position.set(5, 10, 7.5); |
| | | scene.add(light); |
| | | |
| | | // 加载模型 |
| | | const loader = new FBXLoader(); |
| | | const token = localStorage.getItem(config.tokenKey); |
| | | loader.load( |
| | | config.requestCtx + |
| | | "/file/FileDownload/Download?md5=" + |
| | | props.md5 + |
| | | "&token=" + |
| | | token, |
| | | (object) => { |
| | | scene.add(object); |
| | | |
| | | // 创建控件 |
| | | const controls = new OrbitControls(camera, renderer.domElement); |
| | | controls.enableDamping = true; |
| | | controls.dampingFactor = 0.25; |
| | | controls.screenSpacePanning = false; |
| | | |
| | | // 1. 计算模型尺寸和中心点 |
| | | const box = new THREE.Box3().setFromObject(object); |
| | | const center = box.getCenter(new THREE.Vector3()); |
| | | const size = box.getSize(new THREE.Vector3()); |
| | | |
| | | // 2. 计算合适的相机距离 |
| | | const maxDim = Math.max(size.x, size.y, size.z); |
| | | const fov = camera.fov * (Math.PI / 180); |
| | | let cameraDistance = Math.abs(maxDim / (2 * Math.tan(fov / 2))); |
| | | |
| | | // 3. 设置相机位置和方向 |
| | | camera.position.copy(center); |
| | | camera.position.z += cameraDistance * 1.5; // 增加50%的额外空间 |
| | | camera.lookAt(center); |
| | | |
| | | // 4. 更新控件目标点 |
| | | controls.target.copy(center); |
| | | controls.update(); |
| | | |
| | | // 5. 调整相机剪裁平面 |
| | | const minDistance = cameraDistance * 0.1; |
| | | const maxDistance = cameraDistance * 10; |
| | | camera.near = minDistance > 0.1 ? minDistance : 0.1; |
| | | camera.far = maxDistance < 10000 ? maxDistance : 10000; |
| | | camera.updateProjectionMatrix(); |
| | | |
| | | function animate() { |
| | | requestAnimationFrame(animate); |
| | | controls.update(); |
| | | renderer.render(scene, camera); |
| | | } |
| | | animate(); |
| | | loading.value = false; |
| | | }, |
| | | undefined, |
| | | (error) => { |
| | | console.error("加载模型失败:", error); |
| | | loading.value = false; |
| | | } |
| | | ); |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .showModel, |
| | | .viewer-container { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | </style> |
| | |
| | | /> |
| | | </div> |
| | | </div> |
| | | <el-dialog v-model="dialogTableVisible" title="预览"> |
| | | <div> |
| | | <iframe |
| | | style="width: 100%; height: 500px" |
| | | src="../static/modelView/index.html?md5=62d4eadc420b7403fce2be993baa095d&name=飞行棋&domain=https://www.jlstp.cn&target=iframe" |
| | | frameborder="0" |
| | | ></iframe> |
| | | </div> |
| | | </el-dialog> |
| | | |
| | | <!-- 预览 --> |
| | | <previewModule ref="previewModelRef"></previewModule> |
| | | <el-dialog v-model="dialogFormVisible" title="新建模型"> |
| | | <el-form :rules="rules" :model="form" ref="formRef"> |
| | | <el-form-item |
| | |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="模型文件" :label-width="formLabelWidth"> |
| | | <el-upload :before-upload="beforeUpload" :limit="1" v-if="!form.ModelFile"> |
| | | <el-upload |
| | | :before-upload="beforeUpload" |
| | | :limit="1" |
| | | v-if="!form.ModelFile" |
| | | > |
| | | <template #trigger> |
| | | <el-button type="primary">上传模型</el-button> |
| | | </template> |
| | |
| | | import { Plus } from "@element-plus/icons-vue"; |
| | | import { curStoreInfo } from "@/store/index"; |
| | | import SparkMD5 from "spark-md5"; |
| | | import previewModule from "@/components/previewModelDialog.vue"; |
| | | import { |
| | | ComponentSize, |
| | | ElMessage, |
| | |
| | | JointData: "", |
| | | IsSimulation: false, |
| | | ModelRemarks: "", |
| | | ModelFile: null |
| | | ModelFile: null, |
| | | }); |
| | | |
| | | const progress = ref(0); |
| | |
| | | getTableData(); |
| | | }; |
| | | //预览操作 |
| | | const handlePreview = (row) => { |
| | | dialogTableVisible.value = true; |
| | | const previewModelRef = ref<any>(); |
| | | const showModelData = ref<any>(null); |
| | | const handlePreview = (row: any) => { |
| | | let md5: any = null; |
| | | try { |
| | | const fileData = row.fieldList.find((item: any) => item.FileList.length); |
| | | md5 = fileData.FileList[0].File.Md5; |
| | | } catch (error) {} |
| | | previewModelRef.value.handleDialogVisible(true, { |
| | | name: row.name, |
| | | md5, |
| | | }); |
| | | }; |
| | | //上移操作 |
| | | const handleMoveUp = (row) => {}; |
| | |
| | | > |
| | | <div class="model-body-box"> |
| | | <div class="model-img"> |
| | | <iframe |
| | | <!-- <iframe |
| | | style="width: 100%; height: 100%" |
| | | src="./static/modelView/index.html?md5=62d4eadc420b7403fce2be993baa095d&name=飞行棋&domain=https://www.jlstp.cn&target=iframe" |
| | | frameborder="0" |
| | | ></iframe> |
| | | ></iframe> --> |
| | | <showModel :md5="item.md5" :index="index"></showModel> |
| | | </div> |
| | | <div class="model-info"> |
| | | <h1 class="model-title" :title="item.name"> |
| | |
| | | <script setup lang="ts"> |
| | | import { ref, onMounted, watch, inject } from "vue"; |
| | | import { useRouter, useRoute } from "vue-router"; |
| | | import showModel from "../../../components/showModel.vue"; |
| | | const router = useRouter(); |
| | | const route = useRoute(); |
| | | import { curStoreInfo } from "@/store/index"; |
| | |
| | | }, |
| | | { |
| | | ModelName: [], |
| | | ModelFile: [], |
| | | JointData: [], |
| | | IsSimulation: [], |
| | | ModelRemarks: [], |
| | | ChildrenCount: [], |
| | | } |
| | | ); |
| | | for (let index = 0; index < treeData.datas.length; index++) { |
| | | const item = treeData.datas[index]; |
| | | item.md5 = null; |
| | | try { |
| | | const fileData = item.fieldList.find((citem: any) => citem.FileList.length); |
| | | item.md5 = fileData.FileList[0].File.Md5; |
| | | } catch (error) {} |
| | | } |
| | | console.log(treeData, "getModelList"); |
| | | modelDataList.value = treeData.datas; |
| | | listLoading.value = false; |
| | |
| | | const gotoReport = (item) => { |
| | | router.push({ |
| | | name: "simulation-testReport", |
| | | |
| | | }); |
| | | }; |
| | | //打开仿真 |