Quellcode durchsuchen

新增同屏勘验

wangfumin vor 2 Monaten
Ursprung
Commit
47b8d34b04

+ 26 - 3
src/assets/icon/newfire/demo_index.html

@@ -55,6 +55,12 @@
           <ul class="icon_lists dib-box">
           
             <li class="dib">
+              <span class="icon iconfont">&#xe7da;</span>
+                <div class="name">look_t</div>
+                <div class="code-name">&amp;#xe7da;</div>
+              </li>
+          
+            <li class="dib">
               <span class="icon iconfont">&#xe64c;</span>
                 <div class="name">search</div>
                 <div class="code-name">&amp;#xe64c;</div>
@@ -174,9 +180,9 @@
 <pre><code class="language-css"
 >@font-face {
   font-family: 'iconfont';
-  src: url('iconfont.woff2?t=1763006144468') format('woff2'),
-       url('iconfont.woff?t=1763006144468') format('woff'),
-       url('iconfont.ttf?t=1763006144468') format('truetype');
+  src: url('iconfont.woff2?t=1764838829238') format('woff2'),
+       url('iconfont.woff?t=1764838829238') format('woff'),
+       url('iconfont.ttf?t=1764838829238') format('truetype');
 }
 </code></pre>
           <h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@@ -203,6 +209,15 @@
         <ul class="icon_lists dib-box">
           
           <li class="dib">
+            <span class="icon iconfont icon-look_t"></span>
+            <div class="name">
+              look_t
+            </div>
+            <div class="code-name">.icon-look_t
+            </div>
+          </li>
+          
+          <li class="dib">
             <span class="icon iconfont icon-search"></span>
             <div class="name">
               search
@@ -384,6 +399,14 @@
           
             <li class="dib">
                 <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-look_t"></use>
+                </svg>
+                <div class="name">look_t</div>
+                <div class="code-name">#icon-look_t</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
                   <use xlink:href="#icon-search"></use>
                 </svg>
                 <div class="name">search</div>

+ 7 - 3
src/assets/icon/newfire/iconfont.css

@@ -1,8 +1,8 @@
 @font-face {
   font-family: "iconfont"; /* Project id 5058908 */
-  src: url('iconfont.woff2?t=1763006144468') format('woff2'),
-       url('iconfont.woff?t=1763006144468') format('woff'),
-       url('iconfont.ttf?t=1763006144468') format('truetype');
+  src: url('iconfont.woff2?t=1764838829238') format('woff2'),
+       url('iconfont.woff?t=1764838829238') format('woff'),
+       url('iconfont.ttf?t=1764838829238') format('truetype');
 }
 
 .iconfont {
@@ -13,6 +13,10 @@
   -moz-osx-font-smoothing: grayscale;
 }
 
+.icon-look_t:before {
+  content: "\e7da";
+}
+
 .icon-search:before {
   content: "\e64c";
 }

Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
src/assets/icon/newfire/iconfont.js


+ 7 - 0
src/assets/icon/newfire/iconfont.json

@@ -6,6 +6,13 @@
   "description": "",
   "glyphs": [
     {
+      "icon_id": "46269927",
+      "name": "look_t",
+      "font_class": "look_t",
+      "unicode": "e7da",
+      "unicode_decimal": 59354
+    },
+    {
       "icon_id": "25631464",
       "name": "search",
       "font_class": "search",

BIN
src/assets/icon/newfire/iconfont.ttf


BIN
src/assets/icon/newfire/iconfont.woff


BIN
src/assets/icon/newfire/iconfont.woff2


+ 3 - 0
src/request/urls.ts

@@ -312,3 +312,6 @@ export const downloadOfflineFusion = `/fusion/offlinePackage/downOfflineFusion`;
 // 多元融合离线包进度条
 export const getOfflineFusionProcess = `/fusion/offlinePackage/downFusionProcess`;
 
+// 同屏勘验
+export const SYNC_INFO = `/fusion/caseLive/getTakeLookRoom`;
+

+ 68 - 1
src/store/scene.ts

@@ -20,9 +20,12 @@ import {
   uploadModel,
   cameraTypeAllList,
   getMix3dList,
+  SYNC_INFO,
 } from "@/request";
 import saveAs from "@/util/file-serve";
 import { ElMessage } from "element-plus";
+import { user } from "@/store/user";
+import { getCaseSceneList } from "@/store/case";
 
 interface BaseScene {
   title: string;
@@ -88,7 +91,6 @@ export enum SceneType {
   SWSS,
   SWMX,
   SWSSMX,
-
   SWYDSS,
   SWYDMX,
 }
@@ -268,3 +270,68 @@ export const getMix3dPagging = async (params: ScenePaggingParams) => {
 
   return data;
 };
+
+// 获取同屏勘验信息
+export const getSyncSceneInfo = async (scene: Scene, caseId: number) => {
+  return (await axios.post<string>(SYNC_INFO, { caseId, num: scene.num }));
+};
+
+export const SceneTypePaths: { [key in SceneType]: string[] } = {
+  [SceneType.SWKK]: [
+    "/swkk/spg.html",
+    "/swkk/epg.html",
+    `/livestream/fd/criminal.html`,
+  ],
+  [SceneType.SWKJ]: ["/swkk/spg.html", "/swkk/epg.html"],
+  [SceneType.DSFXJ]: ["/swkk/spg.html", "/swkk/epg.html"],
+  [SceneType.SWSS]: ["/swss/index.html", "/swss/index.html"],
+  [SceneType.SWMX]: import.meta.env.DEV
+    ? ["/dev-code/index.html", "/dev-code/index.html"]
+    : ["/code/index.html", "/code/index.html"],
+  [SceneType.SWSSMX]: ["/swkk/spg.html", "/swkk/epg.html"],
+  [SceneType.SWYDSS]: ["/swss/index.html", "/swss/index.html"],
+  [SceneType.SWYDMX]: ["/swkk/spg.html", "/swkk/epg.html"],
+};
+
+const SceneTypeDesc: { [key in SceneType]: string } = {
+  [SceneType.SWKK]: "八目",
+  [SceneType.SWKJ]: "双目转台",
+  [SceneType.SWSS]: "激光转台点云场景",
+  [SceneType.SWMX]: "三维模型",
+  [SceneType.SWSSMX]: "激光转台Mesh场景",
+  [SceneType.SWYDSS]: "激光移动点云场景",
+  [SceneType.SWYDMX]: "激光移动Mesh场景",
+  // [SceneType.QJKK]: '全景看看',
+};
+
+export const getSWKKSyncLink = async (scene: Scene, caseId: number) => {
+  console.log('scene', scene)
+  const supportTypes = [SceneType.SWKJ, SceneType.SWSSMX, SceneType.SWYDMX];
+  const kkScenes = supportTypes.includes(scene.sceneType)
+
+  let msg: string | null = null;
+  if (!kkScenes) {
+    msg = `带看仅支持${supportTypes
+      .map((type) => SceneTypeDesc[type])
+      .join("、")}类型场景,请添加此类型场景。`;
+  }
+  if (msg) {
+    throw msg;
+  }
+
+  const url = new URL(SceneTypePaths[SceneType.SWKK][2], window.location.href.includes('localhost')?'https://test-mix3d.4dkankan.com/':window.location.href);
+  const userInfo = user.value.info;
+  const roomId = await getSyncSceneInfo(scene, caseId);
+  const params = {
+    vruserId: userInfo.userName,
+    roomId: roomId.data,
+    role: "leader",
+    redirect: encodeURIComponent(location.href),
+    name: userInfo.userName,
+    m: scene.num,
+  };
+  for (const [name, val] of Object.entries(params)) {
+    url.searchParams.append(name, val || "");
+  }
+  return url;
+};

+ 13 - 1
src/view/newFireCase/dyManager/sceneContent.vue

@@ -15,7 +15,18 @@
         {{ pagging.state.pag.size * (pagging.state.pag.currentPage - 1) + $index + 1 }}
       </span>
     </el-table-column>
-    <el-table-column label="场景标题" prop="name"></el-table-column>
+    <el-table-column label="场景标题" prop="name" width="120">
+      <template v-slot:default="{ row }">
+        <span class="oper-span" @click="openSceneUrl(row, OpenType.query)">
+          {{ row.name }}
+        </span>
+      </template>
+    </el-table-column>
+    <el-table-column label="设备类型" width="120">
+      <template #default="{ row }">
+        {{ SceneTypeDesc[row.type] }}
+      </template>
+    </el-table-column>
     <el-table-column label="S/N码" prop="snCode"></el-table-column>
     <!-- <el-table-column label="浏览数量" prop="viewCount"></el-table-column> -->
     <el-table-column label="拍摄时间" prop="createTime" v-slot:default="{ row }">
@@ -68,6 +79,7 @@ import { confirm } from "@/helper/message";
 import { sceneDownload } from "./quisk";
 import { sceneShare as openSceneShare } from "@/view/case/quisk";
 import { downSceneHash } from "@/request";
+import { SceneTypeDesc } from '@/constant/scene';
 
 const props = defineProps<{ pagging: ScenePagging }>();
 const delSceneHandler = async (scene: QuoteScene) => {

+ 7 - 1
src/view/newFireCase/meshManager/sceneContent.vue

@@ -15,13 +15,18 @@
         {{ pagging.state.pag.size * (pagging.state.pag.currentPage - 1) + $index + 1 }}
       </span>
     </el-table-column>
-    <el-table-column label="场景标题" prop="name">
+    <el-table-column label="场景标题" prop="name" width="120">
       <template v-slot:default="{ row }">
         <span class="oper-span" @click="openSceneUrl(row, OpenType.query)">
           {{ row.name }}
         </span>
       </template>
     </el-table-column>
+    <el-table-column label="设备类型" width="120">
+      <template #default="{ row }">
+        {{ SceneTypeDesc[row.type] }}
+      </template>
+    </el-table-column>
     <el-table-column label="S/N码" prop="snCode"></el-table-column>
     <!-- <el-table-column label="浏览数量" prop="viewCount"></el-table-column> -->
     <el-table-column label="拍摄时间" prop="createTime" v-slot:default="{ row }">
@@ -74,6 +79,7 @@ import { confirm } from "@/helper/message";
 import { sceneDownload } from "./quisk";
 import { sceneShare as openSceneShare } from "@/view/case/quisk";
 import { downSceneHash } from "@/request";
+import { SceneTypeDesc } from '@/constant/scene';
 
 const props = defineProps<{ pagging: ScenePagging }>();
 const delSceneHandler = async (scene: QuoteScene) => {

+ 15 - 7
src/view/newFireCase/newFireDetails/components/scene.vue

@@ -30,16 +30,18 @@
               <div class="title" :title="item.title">{{ item.title }}</div>
               <div class="sub">{{ SceneTypeDesc[item.sceneType] }}</div>
             </div>
-            <div class="actions" v-if="editOrShow === 'edit'" v-show="String(item.sceneNumId) === activeId">
-              <el-tooltip content="编辑">
+            <div class="actions" v-show="String(item.sceneNumId) === activeId">
+              <el-tooltip content="编辑" v-if="editOrShow === 'edit'">
                 <span class="act" @click.stop="onOpen(item)"><i class="iconfont icon-Edit" /></span>
               </el-tooltip>
-              <el-tooltip content="移除">
+              <el-tooltip content="移除" v-if="editOrShow === 'edit'">
                 <span class="act" @click.stop="onDelete(item)"><i class="iconfont icon-CloseCircle" /></span>
-                <!-- <el-icon class="act" :size="18" @click.stop="onDelete(item)"><Delete /></el-icon> -->
+              </el-tooltip>
+              <el-tooltip content="带看" v-if="editOrShow === 'show'">
+                <span class="act" @click.stop="openDaiKan(item)"><i class="iconfont icon-look_t" /></span>
               </el-tooltip>
               <el-tooltip content="全屏">
-                <el-icon class="act" :size="18" @click.stop="onFullscreen()"><FullScreen /></el-icon>
+                <span class="act" @click.stop="onFullscreen()"><i class="iconfont icon-window_m" /></span>
               </el-tooltip>
             </div>
           </el-menu-item>
@@ -150,7 +152,7 @@ import screenfull from 'screenfull';
 import { useRoute, useRouter } from 'vue-router';
 import { DocumentAdd, Edit, Delete, FullScreen } from '@element-plus/icons-vue';
 import comPagination from "@/components/pagination/index.vue";
-import { Scene, SceneType, getScenePagging } from '@/store/scene';
+import { Scene, SceneType, getScenePagging, getSWKKSyncLink } from '@/store/scene';
 import { SceneTypeDesc } from '@/constant/scene';
 import { getCaseScenes, replaceCaseScenes, getSceneKey, getCaseScenesBySceneType } from '@/store/case';
 import { getFusionAndSceneList } from '@/store/editCsae';
@@ -379,6 +381,12 @@ const onSizeChange = (size: number) => {
   fetchTableData();
 };
 
+// 同屏带看
+const openDaiKan = async (scene: Scene) => {
+  const link = await getSWKKSyncLink(scene, caseId.value);
+  window.open(link);
+};
+
 const onSfChange = () => {
   isFullscreen.value = screenfull.isFullscreen;
 };
@@ -517,7 +525,7 @@ onMounted(async () => {
         }
         .actions{
           position: absolute;
-          right: 0;
+          right: 20px;
           bottom: 26px;
           display: flex;
           align-items: center;

+ 1 - 1
src/view/newFireCase/newFireDetails/editIndex.vue

@@ -71,7 +71,7 @@ const startShot = (payload?: any) => {
   emit("start", payload);
 }
 // 从路由查询参数中获取当前菜单项,如果没有则默认为 'info'
-let currentMenuKey = ref(route.query.tab as string || 'info');
+let currentMenuKey = ref(route.query.tab as string || 'scene');
 // 处理菜单点击事件
 const handleMenuClick = async(menu) => {
   currentMenuKey.value = menu.key;

+ 53 - 11
src/view/newFireCase/newFireDetails/showIndex.vue

@@ -33,7 +33,7 @@
 </template>
 
 <script setup lang="ts">
-import { ref, computed, watch } from "vue";
+import { ref, computed, watch, onMounted } from "vue";
 import { useRoute, useRouter } from 'vue-router';
 import BasicInfo from './components/basicInfo.vue';
 import ScreenShot from './components/screenShot.vue';
@@ -41,6 +41,7 @@ import Scene from './components/scene.vue';
 import Mix3d from './components/mix3d.vue';
 import SiteInspection from './components/siteInspection.vue';
 import OtherFiles from './components/otherFiles.vue';
+import { getFusionAndSceneList } from '@/store/editCsae';
 
 const props = defineProps<{
   caseId: number;
@@ -69,8 +70,51 @@ watch(() => props.currentRecord, (newVal, oldVal) => {
 const startShot = (payload?: any) => {
   emit("start", payload);
 }
-// 从路由查询参数中获取当前菜单项,如果没有则默认为 'info'
-let currentMenuKey = ref(route.query.tab as string || 'info');
+// 从路由查询参数中获取当前菜单项,如果没有则默认为 'scene'
+let currentMenuKey = ref(route.query.tab as string || 'scene');
+
+// 是否存在“实景三维”数据,用于控制菜单项显示
+const hasScene3D = ref(false);
+const refreshSceneAvailability = async () => {
+  try {
+    if (caseId.value) {
+      const list: any = await getFusionAndSceneList({ caseId: caseId.value, type: 'scene' });
+      hasScene3D.value = Array.isArray(list) && list.length > 0;
+      if (!hasScene3D.value) {
+        currentMenuKey.value = 'mix3d';
+        vueRouter.replace({
+          path: route.path,
+          query: { ...route.query, tab: 'mix3d' }
+        });
+      }
+    } else {
+      hasScene3D.value = false;
+      currentMenuKey.value = 'mix3d';
+      vueRouter.replace({
+        path: route.path,
+        query: { ...route.query, tab: 'mix3d' }
+      });
+    }
+  } catch (e) {
+    hasScene3D.value = false;
+  }
+};
+onMounted(() => {
+  refreshSceneAvailability();
+});
+watch(() => caseId.value, () => {
+  refreshSceneAvailability();
+});
+// 若无实景三维且当前在该页,回退到“多元融合”
+watch(hasScene3D, (has) => {
+  if (!has && currentMenuKey.value === 'scene') {
+    currentMenuKey.value = 'mix3d';
+    vueRouter.replace({
+      path: route.path,
+      query: { ...route.query, tab: 'mix3d' }
+    });
+  }
+});
 // 处理菜单点击事件
 const handleMenuClick = async(menu) => {
   currentMenuKey.value = menu.key;
@@ -85,12 +129,6 @@ const handleMenuClick = async(menu) => {
     
     // 执行菜单项的点击事件
     menu.onClick();
-    // const caseInfo = await getCaseInfo(caseId.value!);
-    // if (caseInfo) {
-    //   // 设置页面标题,使用案件信息
-    //   pageTitle.value = caseInfo.caseTitle + " | 编辑"; // 使用 pageTitle
-    //   desc.value = "";
-    // }
 };
 const menus = computed(() => {
   if (!caseId.value) {
@@ -99,7 +137,7 @@ const menus = computed(() => {
   const currentCaseId = caseId.value;
   // const fuseLink = getFuseCodeLink(currentCaseId);
 
-  return [
+  const list = [
     {
       key: "info",
       disabled: false, // 默认不禁用,与原来不同
@@ -148,6 +186,8 @@ const menus = computed(() => {
       },
     },
   ];
+  // 若无实景三维,则不显示该项
+  return list.filter(item => item.key !== 'scene' || hasScene3D.value);
 });
 const menusAbstract = computed(() => {
   if (!caseId.value) {
@@ -156,7 +196,7 @@ const menusAbstract = computed(() => {
   const currentCaseId = caseId.value;
   // const fuseLink = getFuseCodeLink(currentCaseId);
 
-  return [
+  const list = [
     {
       key: "info",
       disabled: false, // 默认不禁用,与原来不同
@@ -182,5 +222,7 @@ const menusAbstract = computed(() => {
       },
     }
   ];
+  // 若无实景三维,则不显示该项
+  return list.filter(item => item.key !== 'scene' || hasScene3D.value);
 });
 </script>