From e47eb010fb80120ff02508fe89f917a68a24398d Mon Sep 17 00:00:00 2001 From: "X1627315083@163.com" <1627315083@qq.com> Date: Tue, 10 Mar 2026 16:59:18 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E5=85=A53d=20=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E7=94=BB=E5=B8=83=E7=9B=B8=E5=85=B3=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 2 +- src/api/flow-canvas.ts | 54 +++++ .../components/tools/threeModel/detail.vue | 123 ++++++++++++ .../components/tools/threeModel/index.vue | 49 +++++ .../components/tools/threeModel/model.vue | 188 ++++++++++++++++++ .../components/tools/threeModel/threeTool.ts | 125 ++++++++++++ .../Canvas/FlowCanvas/flow-canvas.vue | 58 ++++-- .../Canvas/components/base-modal.vue | 22 +- 8 files changed, 599 insertions(+), 22 deletions(-) create mode 100644 src/api/flow-canvas.ts create mode 100644 src/components/Canvas/FlowCanvas/components/tools/threeModel/detail.vue create mode 100644 src/components/Canvas/FlowCanvas/components/tools/threeModel/index.vue create mode 100644 src/components/Canvas/FlowCanvas/components/tools/threeModel/model.vue create mode 100644 src/components/Canvas/FlowCanvas/components/tools/threeModel/threeTool.ts diff --git a/.env.development b/.env.development index f844c2d..8eca712 100644 --- a/.env.development +++ b/.env.development @@ -1,5 +1,5 @@ # VITE_APP_URL = http://192.168.31.82:8771 VITE_APP_URL = http://18.167.251.121:10015 # VITE_APP_URL = http://192.168.31.118:8080 -# VITE_APP_URL = http://192.168.31.82:8755 +VITE_APP_URL = http://192.168.31.82:8755 VITE_GOOGLE_CLIENT_ID = 216037134725-7q8vqp0ohtmohlosltkfg7bd2v29rm5a.apps.googleusercontent.com diff --git a/src/api/flow-canvas.ts b/src/api/flow-canvas.ts new file mode 100644 index 0000000..062708d --- /dev/null +++ b/src/api/flow-canvas.ts @@ -0,0 +1,54 @@ +import request from '@/utils/request' + +/** + * 获取sketch的画布详情 + * @param data 获取sketch的画布详情的参数 + * @param data.id sketch id + * @returns 获取sketch的画布详情 + */ +export interface getSketchFlowCanvasData { + id: string +} +export const getSketchFlowCanvas = (data:getSketchFlowCanvasData) => { + return request({ + url: `/api/canvas/detail/${data.id}`, + method: 'get', + }) +} + +/** + * 保存或者更新sketch的画布详情 + * @param data 获取sketch的画布详情的参数 + * @param data.id sketch id + * @param data.canvasData sketch id + * @returns 获取sketch的画布详情 + */ +export interface saveSketchFlowCanvasData { + id?: string + canvasData: string +} +export const putSketchFlowCanvas = (data:saveSketchFlowCanvasData) => { + return request({ + url: `/api/canvas/detail/${data.id}`, + method: 'put', + data: data.canvasData + }) +} + +/** + * 删除sketch和画布详情 + * @param data 删除sketch的画布详情的参数 + * @param data.id sketch id + * @param data.versionNodeId 节点id + * @returns 获取sketch的画布详情 + */ +export interface deleteSketchFlowCanvasData { + id?: string + versionNodeId?: string +} +export const deleteSketchFlowCanvas = (data:deleteSketchFlowCanvasData) => { + return request({ + url: `/api/canvas/detail/${data.versionNodeId}/${data.id}`, + method: 'delete', + }) +} diff --git a/src/components/Canvas/FlowCanvas/components/tools/threeModel/detail.vue b/src/components/Canvas/FlowCanvas/components/tools/threeModel/detail.vue new file mode 100644 index 0000000..d828c77 --- /dev/null +++ b/src/components/Canvas/FlowCanvas/components/tools/threeModel/detail.vue @@ -0,0 +1,123 @@ + + + \ No newline at end of file diff --git a/src/components/Canvas/FlowCanvas/components/tools/threeModel/index.vue b/src/components/Canvas/FlowCanvas/components/tools/threeModel/index.vue new file mode 100644 index 0000000..7f12bfa --- /dev/null +++ b/src/components/Canvas/FlowCanvas/components/tools/threeModel/index.vue @@ -0,0 +1,49 @@ + + + \ No newline at end of file diff --git a/src/components/Canvas/FlowCanvas/components/tools/threeModel/model.vue b/src/components/Canvas/FlowCanvas/components/tools/threeModel/model.vue new file mode 100644 index 0000000..bdab5fa --- /dev/null +++ b/src/components/Canvas/FlowCanvas/components/tools/threeModel/model.vue @@ -0,0 +1,188 @@ + + + \ No newline at end of file diff --git a/src/components/Canvas/FlowCanvas/components/tools/threeModel/threeTool.ts b/src/components/Canvas/FlowCanvas/components/tools/threeModel/threeTool.ts new file mode 100644 index 0000000..2236ced --- /dev/null +++ b/src/components/Canvas/FlowCanvas/components/tools/threeModel/threeTool.ts @@ -0,0 +1,125 @@ +import * as THREE from 'three'; +import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; +import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"; +import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js' + +export const initThree = (threeDom)=>{ + const scene = new THREE.Scene(); + const group = new THREE.Group() + scene.add(group) + + //创建相机对象 + // this.camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000); + const camera = new THREE.PerspectiveCamera(45, threeDom.offsetWidth / threeDom.offsetHeight, 0.1, 10000); + camera.position.set(0, 90, 6); //设置相机位置 + camera.lookAt(scene.position); //设置相机方向(指向的场景对象) + /** + * 创建渲染器对象 + */ + let width = threeDom.offsetWidth; //窗口宽度 + let height = threeDom.offsetHeight; //窗口高度 + const renderer = new THREE.WebGLRenderer({ + antialias: true, + logarithmicDepthBuffer: true,//深度缓存 防止模型闪烁重影 + }); + + renderer.toneMapping = THREE.ACESFilmicToneMapping;//设置色调 + renderer.toneMappingExposure = 1.3; + + renderer.shadowMap.enabled = true; + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(width, height); //设置渲染区域尺寸 + renderer.setClearColor(0xffffff, 1); //设置背景颜色 + threeDom.innerHTML = ''; + threeDom.appendChild(renderer.domElement); + + // 设置渲染器大小 + //环境光 + let ambient = new THREE.AmbientLight(0xffffff,.8); + scene.add(ambient); + let controls = new OrbitControls(camera,renderer.domElement)//监听鼠标、键盘事件; + // controls.minDistance = 500; // 设置相机与焦点的最小距离 + // controls.maxDistance = 4000; // 设置相机与焦点的最大距离 + controls.mouseButtons = { + // LEFT:THREE.MOUSE.PAN, // 左键 拖动(默认旋转:ROTATE) + LEFT:THREE.MOUSE.ROTATE, // 左键 拖动(默认旋转:ROTATE) + MIDDLE:THREE.MOUSE.DOLLY, // 滑轮 缩放 + RIGHT:THREE.MOUSE.PAN // 右键 旋转(默认拖动:PAN) + // RIGHT:THREE.MOUSE.ROTAafTE // 右键 旋转(默认拖动:PAN) + } + /** + * 光源设置 + */ + //点光源 + /** + * AmbientLight 环境光 + PointLight 点光源 + DirectionalLight 平行光,比如太阳光 + SpotLight 聚光源 + */ + const pointLight = new THREE.DirectionalLight(0xffffff,.5); + pointLight.intensity = 1.2 + pointLight.castShadow = true//开启阴影 + pointLight.shadow.mapSize = new THREE.Vector2(width, height) + scene.add(pointLight); //点光源添加到场景中 + // pointLight.position.set(400, 200, 300); //点光源位置 + pointLight.position.y = 400; + pointLight.position.z = 200; + pointLight.position.x = 200; + let floorGeometry = new THREE.PlaneGeometry(5000, 3000)//地板大小 + let floorMaterial = new THREE.MeshPhongMaterial({ color: "#7e7ab0", }) + let floorMesh = new THREE.Mesh(floorGeometry, floorMaterial); + floorMesh.rotation.x = -0.5 * Math.PI; + floorMesh.receiveShadow = true; + floorMesh.position.y = -0.001; + // scene.add(floorMesh); + const textureLoader = new THREE.TextureLoader(); + // const texture = textureLoader.load('/3dModel/sketch-thick.jpg'); + scene.background = new THREE.Color("#fff"); + return {scene,group,camera,renderer,ambient,controls,pointLight} +} +export const clearModel = (group,scene)=>{ + const oldGroup:any = group.value; + group.value = new THREE.Group(); + scene.value.add(group.value); + scene.value.remove(oldGroup); +} + + +export const addModel = async ( + url:any, + controls:OrbitControls, + camera:THREE.PerspectiveCamera, + pointLight:THREE.DirectionalLight, + group:THREE.Group, + load:any)=>{ + await new Promise((resolve, reject) => { + var fbxLoader = new GLTFLoader(); + let drac = new DRACOLoader() + drac.setDecoderPath('/draco/') + fbxLoader.setDRACOLoader(drac) + // fbxLoader.load('/3dModel/222/1111.glb', + fbxLoader.load(url, + + (obj:any) => { + let scene = obj.scene; + var box = new THREE.Box3().setFromObject(scene); + var center = box.getCenter(new THREE.Vector3()); + controls.value.target.copy(center); + // controls.autoRotate = true + camera.value.position.y = center.y; + camera.value.position.z = 1000; + pointLight.value.position.y = 250; + pointLight.value.position.z = 1250; + group.value.add(scene); + resolve('') + },(xhr:any) => { // 加载进度回调 + const percent = xhr.total == 0?100:(xhr.loaded / xhr.total * 100).toFixed(2); + load.value.progress = percent + // updateProgressBar(Number(percent)); + },(error:any) => { // 加载失败回调 + console.error('模型加载失败:', error); + reject('') + }) + }) +} \ No newline at end of file diff --git a/src/components/Canvas/FlowCanvas/flow-canvas.vue b/src/components/Canvas/FlowCanvas/flow-canvas.vue index fd24821..56a7893 100644 --- a/src/components/Canvas/FlowCanvas/flow-canvas.vue +++ b/src/components/Canvas/FlowCanvas/flow-canvas.vue @@ -53,8 +53,8 @@ @home="() => fitView({ maxZoom: 1 })" /> - - + + @@ -68,11 +68,16 @@ import zoom from '../components/zoom.vue' import imagePreview from '../components/image-preview.vue' import baseModal from '../components/base-modal.vue' + // 工具 + import threeModel from './components/tools/threeModel/index.vue' // 节点 import node from './components/node.vue' import resultImage from './components/nodes/result-image.vue' import card from './components/nodes/cards/index.vue' import text from './components/nodes/text.vue' + + // 接口 + import { getSketchFlowCanvas, putSketchFlowCanvas } from '@/api/flow-canvas' const components = { [NODE_COMPONENT.RESULT_IMAGE]: resultImage, [NODE_COMPONENT.CARD]: card, @@ -166,16 +171,25 @@ // 导出流程 const exportFlow = () => { // flowManager.exportFlow() + const str = JSON.stringify(stateManager.nodes.value) const json = JSON.parse(str) - localStorage.setItem('flow_json', str) + putSketchFlowCanvas({ + id: props.config.id || '==========', + canvasData: str + }).then((res) => { + if (res) { + console.log(res) + } + }) + // localStorage.setItem('flow_json', str) } // 导入流程 - const importFlow = async () => { + const importFlow = async (json) => { try { stateManager.nodes.value = [] await nextTick() - const json = JSON.parse(localStorage.getItem('flow_json') || '[]') + // const json = JSON.parse(localStorage.getItem('flow_json') || '[]') stateManager.nodes.value = json setTimeout(() => { nextTick(() => { @@ -188,24 +202,42 @@ } const imagePreviewRef = ref() + const threeModelRef = ref() /** 打开图片预览 */ const openImagePreview = (url: string) => { imagePreviewRef.value.open(url) } provide('openImagePreview', openImagePreview) - onMounted(() => { + onMounted(async () => { // window['vueFlow'] = vueFlow // window['nodes'] = nodes - nodeManager.createResultNode({ - data: { - disableDelete: true, - isHeader: false, - data: { - url: props.config.url + let json = [] + await new Promise((resolve) => { + getSketchFlowCanvas({ id: props.config.id || '==========' }).then((res) => { + if (res) { + console.log(res) + json = res.data } - } + resolve(true) + }).catch(() => { + resolve(true) + }) }) + if(json.length > 0){ + importFlow(json) + }else{ + nodeManager.createResultNode({ + data: { + disableDelete: true, + isHeader: false, + data: { + url: props.config.url + } + } + }) + } + }) onBeforeMount(() => { eventManager.removeEvents() // 移除事件 diff --git a/src/components/Canvas/components/base-modal.vue b/src/components/Canvas/components/base-modal.vue index ba6e67d..0ce7ed6 100644 --- a/src/components/Canvas/components/base-modal.vue +++ b/src/components/Canvas/components/base-modal.vue @@ -4,8 +4,8 @@ v-model="showDialog" align-center :show-close="false" - width="70vw" - style="border-radius: 20px; padding: 0; --el-dialog-padding-primary: 0" + :width="modalWidth" + style="border-radius: 2.9rem; padding: 0; --el-dialog-padding-primary: 0;background-color: #f7f7f7;" >