Browse Source

feat: save

gemercheung 1 year ago
parent
commit
620f381991

+ 3 - 3
src/app/fire/constant.ts

@@ -2,10 +2,10 @@ import { AppConstant } from "../";
 import banner from "@/assets/image/fireBanner.png";
 import ico from "@/assets/image/fire.ico";
 import { fireDeptId } from "@/constant/appDeptId";
-
+// 新疆消防救援总队火灾现场重建平台
 export const appConstant: AppConstant = {
-  title: "新疆消防救援总队火灾现场重建平台",
-  desc: "",
+  title: "消防火调三维远程勘验平台",
+  desc: "Three-dimensional remote prospecting platform for fire scenes",
   ico,
   banner,
   name: "fire",

+ 10 - 22
src/core/Scene.js

@@ -4,23 +4,12 @@ import Player from "./player/Player.js";
 import BoxManager from "./box/BoxManager.js";
 import { Mitt } from "./mitt.js";
 import testData from "./save.json";
+import { dataURItoBlob, saveFile } from "./utils/utils.js";
 const stats = new Stats();
 
 function sleep(ms) {
   return new Promise((resolve) => setTimeout(resolve, ms));
 }
-const saveFile = function (strData, filename) {
-  var link = document.createElement("a");
-  if (typeof link.download === "string") {
-    document.body.appendChild(link); //Firefox requires the link to be in the body
-    link.download = filename;
-    link.href = strData;
-    link.click();
-    document.body.removeChild(link); //remove the link when done
-  } else {
-    location.replace(uri);
-  }
-};
 
 export default class Scene extends Mitt {
   constructor(domElement) {
@@ -36,7 +25,7 @@ export default class Scene extends Mitt {
     this.defaultZoom = 250;
     this.initCamPView = new THREE.Vector3();
     this.initCamRView = new THREE.Vector3();
-
+    this.blobScreens = [];
     this.inited = false;
 
     this.init = () => {
@@ -213,8 +202,8 @@ export default class Scene extends Mitt {
     this.renderer.render(this.scene, this.orthCamera, null, false);
 
     const dataURL = this.renderer.domElement.toDataURL("image/jpeg");
-
-    saveFile(dataURL, `${index}.jpg`);
+    this.blobScreens.push(dataURItoBlob(dataURL));
+    // saveFile(dataURL, `${index}.jpg`);
     this.onResize(this.width, this.height);
   }
 
@@ -222,16 +211,11 @@ export default class Scene extends Mitt {
     this.orthCamera.zoom = this.defaultZoom;
     const object = this.boxManager.model;
     let total;
-    if (this.sceneType === 2) {
-      total = this.boxManager.imgList.length;
-    } else {
-      total = this.boxManager.imgList.length / 2;
-    }
+    total = object.children.length;
 
     object.updateMatrixWorld();
     this.orthCamera.updateProjectionMatrix();
     const boundingBox = new THREE.Box3().setFromObject(object);
-
     // 计算宽度、高度和深度
     const width = boundingBox.max.x - boundingBox.min.x;
     const one = width / total;
@@ -244,8 +228,12 @@ export default class Scene extends Mitt {
             const offset = -(one * 3 * index);
             console.log("Iteration:", offset);
             that.screenshot(offset, index);
-
             console.log(`Width: ${offset}`);
+            if (index === slides) {
+              console.log("last");
+              that.scene.position.x = 0;
+              this.scene.emit('submitScreenshot')
+            }
           }, index * 1000);
         })(i, this); // 传递当前迭代的索引i给setTimeout的回调函数
       }

+ 12 - 2
src/core/player/Player.js

@@ -11,6 +11,7 @@ import CircleTextLabel from "../box/object/CircleTextLabel.js";
 import PureTextLabel from "../box/object/PureTextLabel.js";
 import { LineMaterial } from "three/examples/jsm/lines/LineMaterial.js";
 
+
 const convertScreenToNDC = function (event, domElement) {
   let x = (event.offsetX / domElement.clientWidth) * 2 - 1;
   let y = -(event.offsetY / domElement.clientHeight) * 2 + 1;
@@ -49,6 +50,7 @@ export default class Player {
     this.activeEdges = [];
     this.renderSymbols = [];
     this.renderTexts = [];
+
     this.matLine = null;
     this.lineColor = 0xe44d54;
     // 1是画线,2是标方向, 3符号, 4文本
@@ -846,14 +848,21 @@ export default class Player {
     this.scene.clearDrawScene();
     this.syncDrawData();
   }
+
   //单多张图片删除时要删除相关数据
   deleteImageDataByIds(ids) {
+    setTimeout(() => {
+      console.warn("单多张图片删除时要删除相关数据");
+      this.clear();
+      // this.t_deleteImageDataByIds(ids);
+    }, 500);
+  }
+  t_deleteImageDataByIds(ids) {
     ids.forEach((id) => {
       const makerIndex = this.renderMarkers.findIndex((item) => item.id === id);
       if (makerIndex > -1) {
         this.renderMarkers.splice(makerIndex, 1);
       }
-
       const lines = this.renderLines.filter(
         (item) => item.imgId === id || item.startId === id
       );
@@ -887,8 +896,9 @@ export default class Player {
       });
       console.log("lines", lines);
     });
-    this.syncDrawData();
+
     setTimeout(() => {
+      this.syncDrawData();
       this.scene.emit("autoSave");
     }, 2500);
   }

+ 37 - 0
src/core/utils/utils.js

@@ -0,0 +1,37 @@
+export function dataURItoBlob(dataURI) {
+  // convert base64 to raw binary data held in a string
+  // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
+  var byteString = atob(dataURI.split(",")[1]);
+
+  // separate out the mime component
+  var mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0];
+
+  // write the bytes of the string to an ArrayBuffer
+  var ab = new ArrayBuffer(byteString.length);
+
+  // create a view into the buffer
+  var ia = new Uint8Array(ab);
+
+  // set the bytes of the buffer to the correct values
+  for (var i = 0; i < byteString.length; i++) {
+    ia[i] = byteString.charCodeAt(i);
+  }
+
+  // write the ArrayBuffer to a blob, and you're done
+  var blob = new Blob([ab], { type: mimeString });
+  return blob;
+}
+
+export const saveFile = function (strData, filename) {
+    var link = document.createElement("a");
+    if (typeof link.download === "string") {
+      document.body.appendChild(link); //Firefox requires the link to be in the body
+      link.download = filename;
+      link.href = strData;
+      link.click();
+      document.body.removeChild(link); //remove the link when done
+    } else {
+      location.replace(uri);
+    }
+  };
+  

+ 5 - 1
src/request/config.ts

@@ -28,6 +28,7 @@ import {
   cameraVersionUpload,
   cameraVersionAppUpload,
   getCaseHasDownloadProcess,
+  ffmpegMergeImage
 } from "./urls";
 
 // 不需要登录就能请求的接口
@@ -44,7 +45,9 @@ export const notLoginUrls = [
   getAttachListByPsw,
 ];
 // 需要用表单提交的数据
-export const fromUrls: string[] = [];
+export const fromUrls: string[] = [
+  // ffmpegMergeImage
+];
 // 带文件的请求
 export const fileUrls = [
   uploadAttachFile,
@@ -56,6 +59,7 @@ export const fileUrls = [
   saveCaseFileInfo,
   cameraVersionUpload,
   cameraVersionAppUpload,
+  ffmpegMergeImage
 ];
 // 需要限定卫GET请求方式的url
 export const GetUrls = [getRoleList, getCompanyList];

+ 10 - 2
src/request/index.ts

@@ -26,7 +26,7 @@ export type AuthHook = () => {
   clear: () => void;
 };
 export const setAuthHook = (hook: AuthHook) => (getAuth = hook);
-let getAuth: AuthHook = () => ({ token: "", userId: "0", clear: () => {} });
+let getAuth: AuthHook = () => ({ token: "", userId: "0", clear: () => { } });
 
 axios.defaults.baseURL = baseURL;
 
@@ -74,7 +74,15 @@ axios.interceptors.request.use(async (config) => {
     const fromData = new FormData();
 
     Object.keys(config.data).forEach((key) => {
-      fromData.append(key, config.data[key]);
+      if (key === 'files') {
+        Array.from(config.data[key]).forEach(file => {
+          fromData.append('files', file as any as File);
+        })
+      } else {
+        fromData.append(key, config.data[key]);
+      }
+
+
     });
     config.data = fromData;
     config.headers["Content-Type"] = "multipart/form-data";

+ 3 - 0
src/request/urls.ts

@@ -267,3 +267,6 @@ export const cameraVersionAppUpload = `/fusion-xj/cameraVersionApp/addAndUpload`
 export const cameraVersionAppUpdate = `/fusion-xj/cameraVersionApp/update`;
 export const cameraVersionAppDelete = `/fusion-xj/cameraVersionApp/delete`;
 export const cameraVersionAppList = `/fusion-xj/cameraVersionApp/list`;
+
+//相片合成
+export const ffmpegMergeImage = `fusion-xj/caseImg/ffmpegImage`;

+ 7 - 1
src/store/case.ts

@@ -20,7 +20,8 @@ import {
   caseExtractDetailExport,
   copyExample,
   saveCaseImgTag,
-  getCaseImgTag
+  getCaseImgTag,
+  ffmpegMergeImage
 } from "@/request";
 import { ModelScene, QuoteScene, Scene, SceneType } from "./scene";
 import { CaseFile } from "./caseFile";
@@ -152,3 +153,8 @@ export const saveCaseImgTagData = (params: any) =>
 
 export const getCaseImgTagData = (caseId: number) =>
   axios.get(getCaseImgTag, { params: { caseId } });
+
+
+export const submitMergePhotos = (data) => {
+  axios.post(ffmpegMergeImage, { ...data });
+}

+ 13 - 1
src/view/case/photos/draggable.vue

@@ -45,6 +45,7 @@ import { caseImgList, CaseImg, caseDel, caseUpdateSort } from "@/store/case";
 import { VueDraggable } from "vue-draggable-plus";
 import { openErrorMsg } from "@/request/errorMsg.js";
 import { addCaseImgFile } from "../quisk";
+import { ElMessage, ElMessageBox } from "element-plus";
 // import { IconRabbish } from '@element-plus/icons-vue'
 const props = defineProps({ sortType: Boolean, caseId: Number });
 const emit = defineEmits<{
@@ -102,12 +103,23 @@ async function getList() {
   list.value = lists.data;
   emit("changeList", list.value);
 }
-function handleDet(index: Number, id: Number) {
+async function handleDet(index: Number, id: Number) {
+  // const res = await ElMessageBox.confirm(
+  //   "删除图像影响排图会重置标记数据,是否继续?",
+  //   "温馨提示",
+  //   {
+  //     confirmButtonText: "确定",
+  //     cancelButtonText: "取消",
+  //     type: "default",
+  //   }
+  // );
+  // if (res) {
   caseDel(id).then((res) => {
     emit("delImage", [id]);
     list.value.splice(index, 1);
     emit("changeList", list.value);
   });
+  // }
 }
 async function handleEdit(params) {
   await addCaseImgFile({

+ 21 - 1
src/view/case/photos/index.vue

@@ -68,7 +68,11 @@ import { Swiper, SwiperSlide } from "swiper/vue";
 import "swiper/css";
 // import { addCaseFile } from "@/store/caseFile";
 import { addCaseImgFile, addCaseImgFileAll } from "../quisk";
-import { saveCaseImgTagData, getCaseImgTagData } from "@/store/case";
+import {
+  saveCaseImgTagData,
+  getCaseImgTagData,
+  submitMergePhotos,
+} from "@/store/case";
 import Scene from "@/core/Scene.js";
 import draggable from "./draggable.vue";
 import edit from "./edit.vue";
@@ -210,6 +214,22 @@ const renderCanvas = () => {
     console.log("autoSave");
     handleAutoSave();
   });
+  scene.on("submitScreenshot", () => {
+    if (window.scene) {
+      // const data = new FormData();
+      // window.scene.blobScreens.forEach((b, index) => {
+      //   data.append("files", b, index);
+      // });
+      const data = {
+        files: window.scene.blobScreens,
+        caseId: caseId.value,
+      };
+      
+      setTimeout(() => {
+        submitMergePhotos(data);
+      }, 500);
+    }
+  });
 };
 const onSwiper = (swiper) => {
   console.log("onSwiper");