bill 1 éve
szülő
commit
bca262e569

+ 6 - 1
src/components/dialog/index.vue

@@ -24,7 +24,7 @@
 </template>
 
 <script setup lang="ts">
-import { computed, ref, watch, watchEffect } from "vue";
+import { computed, ref, watch, watchEffect, nextTick } from "vue";
 import { user } from "@/store/user";
 import { operateIsPermissionByPath } from "@/directive/permission";
 import { DialogProps } from "./type";
@@ -34,6 +34,7 @@ const props = withDefaults(defineProps<DialogProps>(), {
   show: false,
   hideFloor: false,
   showClose: true,
+  notSubmit: false,
   enterText: "保 存",
 });
 
@@ -58,6 +59,10 @@ const deleteHandle = () => {
   emit("delete");
 };
 
+if (!showFloor.value && !props.notSubmit) {
+  nextTick(() => enterHandle());
+}
+
 const disabled = computed(() => props.power && !operateIsPermissionByPath(props.power));
 </script>
 

+ 24 - 24
src/components/dialog/style.scss

@@ -1,51 +1,51 @@
 .dialog-bg {
-  background-color: rgba(0,0,0,0.5);
-  position: fixed;
-  left: 0;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  z-index: 99;
+  background-color: rgba(0, 0, 0, 0.5);
+  position        : fixed;
+  left            : 0;
+  top             : 0;
+  right           : 0;
+  bottom          : 0;
+  display         : flex;
+  align-items     : center;
+  justify-content : center;
+  z-index         : 99;
 
 }
 
 .dialog {
-  $padding: 16px;
-  width: 680px;
+  $padding        : 16px;
+  width           : 680px;
   background-color: #fff;
-  border-radius: 4px;
+  border-radius   : 4px;
 
   .head {
-    padding: $padding;
-    display: flex;
+    padding        : $padding;
+    display        : flex;
     justify-content: space-between;
 
     h3 {
-      font-size: 16px;
-      color: var(--colorColor);
+      font-size  : 16px;
+      color      : var(--colorColor);
       font-weight: normal;
     }
 
     i {
       font-size: 2rem;
-      color: rgb(145,148,154);
-      cursor: pointer;
+      color    : rgb(145, 148, 154);
+      cursor   : pointer;
     }
   }
 
   .content {
-    padding: 24px 30px;
-    border-top: 1px solid var(--bgColor);
+    padding      : 24px 30px;
+    border-top   : 1px solid var(--bgColor);
     border-bottom: 1px solid var(--bgColor);
-    max-height: 600px;
-    overflow-y: auto;
+    max-height   : 600px;
+    overflow-y   : auto;
   }
 
   .floot {
-    float: right;
+    float  : right;
     padding: $padding;
   }
 }

+ 14 - 0
src/components/dialog/type.ts

@@ -2,6 +2,7 @@ export type DialogProps = {
   show?: boolean;
   title: string;
   hideFloor?: boolean;
+  notSubmit?: boolean;
   enterText?: string;
   width?: number;
   power?: string;
@@ -9,3 +10,16 @@ export type DialogProps = {
   showDelete?: boolean;
   cornerClose?: boolean;
 };
+
+export const dialogPropsKeys: (keyof DialogProps)[] = [
+  "show",
+  "title",
+  "hideFloor",
+  "notSubmit",
+  "enterText",
+  "width",
+  "power",
+  "showClose",
+  "showDelete",
+  "cornerClose",
+];

+ 26 - 14
src/helper/mount.ts

@@ -1,7 +1,7 @@
 import { router } from "@/router";
 import { createVNode, reactive, render, watch, watchEffect } from "vue";
 import Locale from "@/config/locale.vue";
-import type { App, VNode } from "vue";
+import type { App, Ref, VNode } from "vue";
 
 export type MountContext<P = any> = {
   props?: P;
@@ -80,12 +80,12 @@ export const mountComponent = <P>(
 };
 
 import Dialog from "@/components/dialog/index.vue";
-import { DialogProps } from "@/components/dialog/type";
+import { DialogProps, dialogPropsKeys } from "@/components/dialog/type";
 
 export type QuiskExpose = {
   submit?: () => void;
   quit?: () => void;
-};
+} & Partial<{ [key in keyof DialogProps]?: Ref<DialogProps[key]> }>;
 
 export const quiskMountFactory =
   <P>(comp: ComponentConstructor<P>, dprops: DialogProps) =>
@@ -94,6 +94,7 @@ export const quiskMountFactory =
     dRef?: (expose: { quit: () => void; submit: () => void }) => void
   ): Promise<T> => {
     let ref: QuiskExpose;
+
     return new Promise((resolve) => {
       const api = {
         onQuit: async () => {
@@ -103,6 +104,7 @@ export const quiskMountFactory =
           } else {
             resolve(false as any);
           }
+          console.error("?");
           destroy();
         },
         onSubmit: async () => {
@@ -112,21 +114,31 @@ export const quiskMountFactory =
           } else {
             resolve(true as any);
           }
+          console.error("?");
           destroy();
         },
       };
 
-      const destroy = mountComponent(
-        Dialog,
-        { ...dprops, ref: undefined, show: true, ...api },
-        {
-          default: () =>
-            createVNode(comp, {
-              ...props,
-              ref: (v: any) => (ref = v),
-            }),
-        }
-      );
+      const layoutProps = reactive({
+        ...dprops,
+        ref: undefined,
+        show: true,
+        ...api,
+      });
+      const destroy = mountComponent(Dialog, layoutProps, {
+        default: () =>
+          createVNode(comp, {
+            ...props,
+            ref: (v: any) => {
+              for (const key in v) {
+                if (dialogPropsKeys.includes(key as any)) {
+                  layoutProps[key] = v[key];
+                }
+              }
+              ref = v;
+            },
+          }),
+      });
 
       dRef &&
         dRef({

+ 2 - 0
src/request/config.ts

@@ -4,6 +4,7 @@ import {
   getAttachListByPsw,
   getCode,
   getCompanyList,
+  getDownloadProcess,
   getFireList,
   getMessageList,
   getModelSceneList,
@@ -65,4 +66,5 @@ export const baseURL = import.meta.env.DEV ? "/api" : "";
 export const notOpenUrls: string[] = [
   uploadModel,
   "/fusion/scene/getSceneProgress",
+  getDownloadProcess,
 ];

+ 4 - 3
src/request/urls.ts

@@ -197,11 +197,12 @@ export const uploadAttachImage = "/web/fireProject/uploadImage";
 /** ------------------------------------------ */
 
 // 下载校验
-export const checkHasDownload = "/web/scene/checkDownload/";
+export const checkHasDownload = "/fusion/sceneDownLog/checkDownLoad";
 // 下载获取进度条
-export const getDownloadProcess = "/web/scene/downloadProcess";
+export const getDownloadProcess = "/fusion/sceneDownLog/downloadProcess";
 // 下载
-export const downloadScene = "/web/scene/downloadScene/";
+export const downloadScene = "/fusion/sceneDownLog/downScene";
+
 // 带看相关接口
 export const offLine = "/web/fireProject/offLine"; //{roomId}
 export const onLine = "/web/fireProject/onLine"; //{roomId}

+ 24 - 0
src/view/vrmodel/quisk.ts

@@ -1,7 +1,31 @@
+import { QuoteScene, SceneType } from "@/store/scene";
 import EditModel from "./editModel.vue";
 import { quiskMountFactory } from "@/helper/mount";
+import axios from "axios";
+import SceneDownload from "./sceneDownload.vue";
+import { checkHasDownload } from "@/request";
 
 export const editModelScene = quiskMountFactory(EditModel, {
   title: "编辑模型",
   width: 500,
 });
+
+export type SceneDpwnloadProps = { scene: QuoteScene };
+export const sceneDownload = async (props: SceneDpwnloadProps) => {
+  const params = {
+    num: props.scene.num,
+    isObj: Number(
+      ![SceneType.SWSS, SceneType.SWYDSS].includes(props.scene.type)
+    ),
+  };
+  const res = await axios.get(checkHasDownload, { params });
+  const hideFloor = Number(res.data.downloadStatus) !== 3;
+
+  const sceneDownloadDialog = quiskMountFactory(SceneDownload, {
+    title: "场景离线包下载",
+    width: 500,
+    hideFloor: hideFloor,
+    enterText: "下 载",
+  });
+  return await sceneDownloadDialog(props);
+};

+ 8 - 3
src/view/vrmodel/sceneContent.vue

@@ -70,14 +70,14 @@
       >
         删除
       </span>
-      <!-- <span
+      <span
         class="oper-span"
         v-pdpath="['download']"
-        @click="sceneDownload({ scene: row })"
+        @click="sceneDownloadHandler(row)"
         v-if="row.num"
       >
         下载
-      </span> -->
+      </span>
     </el-table-column>
   </el-table>
 </template>
@@ -95,6 +95,11 @@ import { ScenePagging } from "./pagging";
 import { QuoteSceneStatusDesc } from "@/constant/scene";
 import { OpenType, openSceneUrl } from "../case/help";
 import { confirm } from "@/helper/message";
+import { sceneDownload } from "./quisk";
+
+const sceneDownloadHandler = (scene: QuoteScene) => {
+  sceneDownload({ scene });
+};
 
 const props = defineProps<{ pagging: ScenePagging }>();
 const delSceneHandler = async (scene: QuoteScene) => {

+ 133 - 0
src/view/vrmodel/sceneDownload.vue

@@ -0,0 +1,133 @@
+<template>
+  <!-- hideFloor: state === State.package -->
+  <div>
+    <div class="title">
+      {{ stateTitle[state] }}
+    </div>
+
+    <div v-if="state === State.package">
+      <div
+        class="text"
+        style="display: flex; justify-content: space-between; margin-top: 15px"
+      >
+        <span>{{ filename }}</span>
+        <span>{{ percent }}%</span>
+      </div>
+      <div style="pointer-events: none">
+        <el-slider v-model="percent" :show-tooltip="false" />
+      </div>
+    </div>
+    <div v-else-if="state === State.readDown">
+      <span>正在下载中……</span>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed, onMounted, onUnmounted, ref } from "vue";
+import saveAs from "@/util/file-serve";
+import { checkHasDownload, getDownloadProcess, downloadScene, axios } from "@/request";
+import { ElLoading, ElMessage } from "element-plus";
+import { QuoteScene, SceneType } from "@/store/scene";
+import { QuiskExpose } from "@/helper/mount";
+
+const props = defineProps<{ scene: QuoteScene }>();
+enum State {
+  uncreate,
+  package,
+  readDown,
+}
+const getState = (type: number) => {
+  const stateTypes = [
+    { codes: [0, 2], state: State.uncreate },
+    { codes: [1], state: State.package },
+    { codes: [3], state: State.readDown },
+  ];
+  return (
+    stateTypes.find((stateType) => stateType.codes.includes(type))?.state ||
+    State.uncreate
+  );
+};
+
+const state = ref<State>(State.uncreate);
+const count = ref<number>(0);
+const filename = ref<string>(props.scene.title + ".zip");
+const downloadURL = ref<string>();
+const percent = ref(0);
+
+const stateTitle = {
+  [State.uncreate]: "下载场景离线数据包,可在本地运行查看。",
+  [State.package]: "正在打包场景离线数据",
+  [State.readDown]: filename.value,
+};
+
+const params = {
+  num: props.scene.num,
+  isObj: Number(![SceneType.SWSS, SceneType.SWYDSS].includes(props.scene.type)),
+};
+// 初始化
+const initial = async () => {
+  const res = await axios.get(checkHasDownload, { params });
+  state.value = getState(res.data.downloadStatus);
+  count.value = res.data.count;
+  downloadURL.value = res.data.downloadUrl;
+
+  if (state.value === State.uncreate) {
+    const downRes = await axios.get(downloadScene, { params });
+    state.value = getState(downRes.data.downloadStatus);
+    // const unCountFlag =
+    //   count.value == 0 ||(await axios.get(downloadScene, { params })).data.downloadStatus !== 1;
+    if (state.value === State.uncreate) {
+      ElMessage.error("下载失败,请联系管理员");
+      throw "暂无剩余下载次数";
+    }
+  }
+
+  if (state.value === State.package) {
+    await new Promise<void>((resolve) => requestUpdateURL(resolve));
+  } else {
+    downloadURL.value = res.data.downloadUrl;
+  }
+};
+
+// 下载
+const download = () => {
+  if (!downloadURL.value) {
+    ElMessage.error("下载链接未生成,请稍等!");
+    throw "下载链接未生成,请稍等!";
+  } else {
+    return saveAs(downloadURL.value, filename.value);
+  }
+};
+
+// 进度请求
+let timer: any;
+const requestUpdateURL = async (callback: () => void) => {
+  const res = await axios.get(getDownloadProcess, { params });
+
+  percent.value = parseInt(res.data.percent);
+  downloadURL.value = res.data.url;
+  if (downloadURL.value) {
+    state.value = State.readDown;
+    callback();
+  } else {
+    timer = setTimeout(() => requestUpdateURL(callback), 1000);
+  }
+};
+
+onUnmounted(() => clearTimeout(timer));
+
+defineExpose<QuiskExpose>({
+  submit: async () => {
+    await initial();
+    const loading = ElLoading.service({
+      lock: true,
+      text: "下载中",
+      background: "rgba(255, 255, 255, 0.4)",
+    });
+    await download();
+    loading.close();
+    ElMessage.success("下载完成");
+  },
+});
+</script>