Ver código fonte

Merge branch 'jiangmeng2.0' into jiangmeng

tangning 3 meses atrás
pai
commit
714a6277f4
57 arquivos alterados com 6326 adições e 366 exclusões
  1. 2 1
      .env.development
  2. 170 0
      public/browser.html
  3. 12 0
      src/api/jyUserPlatform/index.ts
  4. 164 0
      src/api/operate/case.ts
  5. 140 0
      src/api/operate/draw.ts
  6. 52 3
      src/api/operate/index.ts
  7. 8 5
      src/components/Modal/src/BasicModal.vue
  8. 49 0
      src/components/Prompt/dialog.vue
  9. 39 0
      src/components/Prompt/index.ts
  10. 69 0
      src/components/Prompt/state.ts
  11. 6 5
      src/components/Upload/src/UploadModal.vue
  12. 14 7
      src/components/Upload/src/data.tsx
  13. 6 0
      src/components/Upload/src/props.ts
  14. 5 1
      src/components/Upload/src/useUpload.ts
  15. 9 0
      src/design/public.less
  16. 1 1
      src/layouts/default/tabs/index.vue
  17. 1 1
      src/locales/lang/en/component.ts
  18. 2 2
      src/locales/lang/zh-CN/component.ts
  19. 8 0
      src/settings/siteSetting.ts
  20. 45 31
      src/utils/file/download.ts
  21. 122 122
      src/views/case/addCaseModal.vue
  22. 227 0
      src/views/case/addResultModal.vue
  23. 104 0
      src/views/case/data.tsx
  24. 31 24
      src/views/case/list.vue
  25. 223 0
      src/views/case/resultListModal.vue
  26. 6 5
      src/views/device/index.vue
  27. 78 0
      src/views/diversity/DownLoadModal.vue
  28. 147 0
      src/views/diversity/MoveModal.vue
  29. 315 0
      src/views/diversity/addCaseModal.vue
  30. 508 0
      src/views/diversity/list.vue
  31. 78 0
      src/views/draw/DownLoadModal.vue
  32. 303 0
      src/views/draw/addCaseModal.vue
  33. 603 0
      src/views/draw/list.vue
  34. 125 0
      src/views/draw/reName.vue
  35. 9 0
      src/views/mediaLibrary/list.vue
  36. 1 1
      src/views/mediaLibrary/modal/grouping.vue
  37. 4 0
      src/views/mediaLibrary/modal/uploadModal.vue
  38. 78 0
      src/views/planImg/DownLoadModal.vue
  39. 157 0
      src/views/planImg/addCaseModal.vue
  40. 511 0
      src/views/planImg/list.vue
  41. 140 64
      src/views/productOperation/cameraScene.vue
  42. 25 25
      src/views/productOperation/modal/PowersModal.vue
  43. 8 1
      src/views/productOperation/modal/detailModal.vue
  44. 147 0
      src/views/productOperation/modal/resultListModal.vue
  45. 168 0
      src/views/productOperation/modal/uploadModal.vue
  46. 209 0
      src/views/staffShare/addModal.vue
  47. 29 0
      src/views/staffShare/data.ts
  48. 121 0
      src/views/staffShare/giveList.vue
  49. 142 0
      src/views/staffShare/index.vue
  50. 166 0
      src/views/staffShare/sceneListModal.vue
  51. 65 64
      src/views/statistics/components/sceneEchart.vue
  52. 3 3
      src/views/statistics/scene/index.vue
  53. 194 0
      src/views/workerShare/addModal.vue
  54. 38 0
      src/views/workerShare/data.ts
  55. 121 0
      src/views/workerShare/giveList.vue
  56. 152 0
      src/views/workerShare/index.vue
  57. 166 0
      src/views/workerShare/sceneListModal.vue

+ 2 - 1
.env.development

@@ -6,7 +6,8 @@ VITE_PUBLIC_PATH = ./
 
 # Cross-domain proxy, you can configure multiple
 # Please note that no line breaks
-VITE_PROXY = [["/service","http://192.168.9.27:1804"], ["/fusion","http://192.168.9.27:1804"]]
+# VITE_PROXY = [["/service","http://192.168.9.27:1804"], ["/fusion","http://192.168.9.27:1804"]]
+VITE_PROXY = [["/service","http://192.168.0.125:1804"], ["/fusion","http://192.168.0.125:1804"]]
 # VITE_PROXY=[["/api","https://vvbin.cn/test"]]
 
 # Delete console

+ 170 - 0
public/browser.html

@@ -0,0 +1,170 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+  <meta charset="UTF-8" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
+  <title><%= title %></title>
+  <link rel="icon" href="/favicon.ico" />
+  <style>
+    /* 基础重置与布局 */
+    * {
+      margin: 0; 
+      padding: 0; 
+      box-sizing: border-box;
+    }
+    body {
+      font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
+      background-color: #fff;
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
+      align-items: center;
+      min-height: 100vh;
+      color: #999;
+    }
+    /* 容器与文本样式 */
+    .container {
+      text-align: center;
+    }
+    .tips {
+      margin: 8px 0;
+      line-height: 1.6;
+    }
+    /* 浏览器图标区域布局 */
+    .browser-icons {
+      display: flex;
+      justify-content: center;
+      gap: 40px;
+      margin-top: 20px;
+      flex-wrap: wrap; /* 适配小屏幕换行 */
+    }
+    .browser-item {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      cursor: pointer;
+      transition: transform 0.2s ease;
+    }
+    .browser-item:hover {
+      transform: scale(1.05);
+    }
+    .browser-item img {
+      width: 60px;
+      height: 60px;
+      margin-bottom: 8px;
+    }
+    .browser-item span {
+      font-size: 14px;
+    }
+    /* 国产系统专属提示(可选样式) */
+    .domestic-os-tip {
+      color: #ff6600;
+      font-weight: bold;
+      margin-top: 20px;
+    }
+    .icon-area {
+      display: flex;
+      justify-content: center;
+      gap: 40px;
+      margin-top: 20px;
+    }
+
+    /* 单个图标及文字的样式 */
+    .browser-icon {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      cursor: pointer;
+    }
+
+    .browser-icon img {
+      width: 60px;
+      height: 60px;
+      margin-bottom: 8px;
+    }
+
+    .browser-icon span {
+      font-size: 14px;
+    }
+
+    /* 顶部提示文字样式 */
+    .tips {
+      margin-bottom: 10px;
+    }
+  </style>
+</head>
+<body>
+  <div class="container">
+    <!-- 通用提示文案 -->
+    <p class="tips">无法打开页面,请升级或更换浏览器后重新打开</p>
+    <p class="tips">建议使用以下浏览器</p>
+    
+    <!-- 浏览器图标区 -->
+    <div class="browser-icons" id="noDomestic">
+      <div class="browser-item">
+        <!-- 可替换为 Firefox 官方图标地址或本地资源 -->
+        <span style="font-size: 60px; color: #FF7B00;">🦊</span> 
+        <span>Firefox</span>
+      </div>
+      <div class="browser-item">
+        <!-- Edge 图标 -->
+        <span style="font-size: 60px; color: #0078D7;">🌊</span> 
+        <span>Microsoft Edge</span>
+      </div>
+      <div class="browser-item">
+        <!-- Chrome 图标 -->
+        <span style="font-size: 60px; color: #000;">🍎</span> 
+        <span>Chrome</span>
+      </div>
+    </div>
+    <!-- 国产系统检测结果展示区 -->
+    <div class="icon-area" id="domestic">
+      <div class="browser-icon">
+        <!-- 这里用文字简单模拟图标,实际可替换为 Firefox 浏览器图标的路径 -->
+        <span style="font-size: 60px; color: #FF7B00;">🦊</span> 
+        <span>火狐</span>
+      </div>
+      <div class="browser-icon">
+        <!-- 同理,替换为 Edge 浏览器图标的路径 -->
+        <span style="font-size: 60px; color: #0078D7;">🌊</span> 
+        <span>奇安信可浏览器</span>
+      </div>
+      <div class="browser-icon">
+        <!-- 替换为 Safari 浏览器图标的路径 -->
+        <span style="font-size: 60px; color: #000;">🍎</span> 
+        <span>360安全浏览器</span>
+      </div>
+      <div class="browser-icon">
+        <!-- 替换为 Chrome 浏览器图标的路径 -->
+        <span style="font-size: 60px; color: #4285F4;">🔴</span> 
+        <span>Chromeium</span>
+      </div>
+    </div>
+  </div>
+
+  <script>
+    // 识别国产操作系统逻辑(示例覆盖常见标识,可根据需要补充)
+    function isDomesticOS() {
+      const userAgent = navigator.userAgent.toLowerCase();
+      const platform = navigator.platform.toLowerCase();
+      // 统信 UOS、银河麒麟、深度 Deepin、中标麒麟等标识
+      return /uos|kylin|deepin|neokylin/.test(userAgent) 
+          || /linux/.test(platform) && /国产|中国/.test(userAgent); 
+    }
+
+    // 执行检测
+    const isDomestic = isDomesticOS();
+    const domestic = document.getElementById('domestic');
+    const noDomestic = document.getElementById('noDomestic');
+    
+    if (isDomestic) {
+      domestic.style.display = 'flex'; 
+      noDomestic.style.display = 'none'; 
+    } else {
+      // 非国产系统可隐藏或自定义提示
+      domestic.style.display = 'none'; 
+      noDomestic.style.display = 'flex'; 
+    }
+  </script>
+</body>
+</html>

+ 12 - 0
src/api/jyUserPlatform/index.ts

@@ -17,6 +17,7 @@ enum Api {
   yhupdate = '/service/manage/jyUserPlatform/update',
   yhdel = '/service/manage/jyUserPlatform/del',
   addressKey = '/service/manage/index/addressKey/',
+  sceneGroupCount = '/service/manage/scene/sceneGroupCount/',
 }
 
 /**
@@ -34,6 +35,17 @@ export const allList = (params: PageParams) =>
     },
   });
 
+export const sceneGroupCount = ({ type = 'platform' }) =>
+  defHttp.get<userList>({
+    url: Api.sceneGroupCount + type,
+    params: {},
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
 export const jyPlatformlist = (params: PageParams) =>
   defHttp.post({
     url: Api.list,

+ 164 - 0
src/api/operate/case.ts

@@ -0,0 +1,164 @@
+import { defHttp } from '/@/utils/http/axios';
+import { PageParams } from './model';
+import { Result } from '/#/axios';
+import { getToken } from '/@/utils/auth';
+
+const token = getToken();
+
+enum Api {
+  caseOverviewList = '/service/manage/caseOverview/list',
+  caseOverviewCopy = '/service/manage/caseOverview/copy',
+  caseOverviewRename = '/service/manage/caseOverview/rename',
+  caseOverviewDel = '/service/manage/caseOverview/del',
+  caseTabulationList = '/service/manage/caseTabulation/list',
+  caseTabulationCopy = '/service/manage/caseTabulation/copy',
+  caseTabulationRename = '/service/manage/caseTabulation/rename',
+  caseTabulationDel = '/service/manage/caseTabulation/del',
+  caseFusionAdd = '/service/manage/caseFusion/addOrUpdate',
+  caseFusionList = '/service/manage/caseFusion/list',
+  caseFusionMove = '/service/manage/caseFusion/move',
+  caseFusionDel = '/service/manage/caseFusion/del',
+  getNotAuthScene = '/service/manage/case/getNotAuthScene',
+}
+
+/**
+ * @description: Get sample list value
+ */
+
+export const caseOverviewList = (params: PageParams) =>
+  defHttp.post<Result>({
+    url: Api.caseOverviewList,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+export const caseOverviewRename = (params) =>
+  defHttp.post<Result>({
+    url: Api.caseOverviewRename,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const caseOverviewCopy = (params) =>
+  defHttp.post<Result>({
+    url: Api.caseOverviewCopy,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const caseOverviewDel = (params) =>
+  defHttp.post<Result>({
+    url: Api.caseOverviewDel,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const caseTabulationList = (params: PageParams) =>
+  defHttp.post<Result>({
+    url: Api.caseTabulationList,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+export const caseTabulationRename = (params) =>
+  defHttp.post<Result>({
+    url: Api.caseTabulationRename,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const caseTabulationCopy = (params) =>
+  defHttp.post<Result>({
+    url: Api.caseTabulationCopy,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const caseTabulationDel = (params) =>
+  defHttp.post<Result>({
+    url: Api.caseTabulationDel,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+export const caseFusionAdd = (params) =>
+  defHttp.post<Result>({
+    url: Api.caseFusionAdd,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const caseFusionList = (params: PageParams) =>
+  defHttp.post<Result>({
+    url: Api.caseFusionList,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+export const caseFusionMove = (params) =>
+  defHttp.post<Result>({
+    url: Api.caseFusionMove,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const caseFusionDel = (params) =>
+  defHttp.post<Result>({
+    url: Api.caseFusionDel,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+export const getNotAuthScene = (params) =>
+  defHttp.post<Result>({
+    url: Api.getNotAuthScene,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });

+ 140 - 0
src/api/operate/draw.ts

@@ -0,0 +1,140 @@
+import { defHttp } from '/@/utils/http/axios';
+import { PageParams } from './model';
+import { Result } from '/#/axios';
+import { getToken } from '/@/utils/auth';
+
+const token = getToken();
+
+enum Api {
+  caseOverviewAdd = '/fusion/caseOverview/addOrUpdate',
+  caseOverviewList = '/service/manage/caseOverview/list',
+  caseOverviewCopy = '/service/manage/caseOverview/copy',
+  caseOverviewRename = '/service/manage/caseOverview/rename',
+  caseOverviewDel = '/service/manage/caseOverview/del',
+  caseTabulationAdd = '/fusion/caseTabulation/addOrUpdate',
+  caseTabulationList = '/service/manage/caseTabulation/list',
+  caseTabulationCopy = '/service/manage/caseTabulation/copy',
+  caseTabulationRename = '/service/manage/caseTabulation/rename',
+  caseTabulationDel = '/service/manage/caseTabulation/del',
+}
+
+/**
+ * @description: Get sample list value
+ */
+export const caseOverviewAdd = (params) =>
+  defHttp.post<Result>({
+    url: Api.caseOverviewAdd,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const caseOverviewList = (params: PageParams) =>
+  defHttp.post<Result>({
+    url: Api.caseOverviewList,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+export const caseTabulationAdd = (params) =>
+  defHttp.post<Result>({
+    url: Api.caseTabulationAdd,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const caseOverImgList = (params: PageParams) =>
+  defHttp.post<Result>({
+    url: params.tableType ? Api.caseTabulationList : Api.caseOverviewList,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+export const caseOverviewRename = (params) =>
+  defHttp.post<Result>({
+    url: Api.caseOverviewRename,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const caseOverviewCopy = (params) =>
+  defHttp.post<Result>({
+    url: Api.caseOverviewCopy,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const caseOverviewDel = (params) =>
+  defHttp.post<Result>({
+    url: Api.caseOverviewDel,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const caseTabulationList = (params: PageParams) =>
+  defHttp.post<Result>({
+    url: Api.caseTabulationList,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+export const caseTabulationRename = (params) =>
+  defHttp.post<Result>({
+    url: Api.caseTabulationRename,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const caseTabulationCopy = (params) =>
+  defHttp.post<Result>({
+    url: Api.caseTabulationCopy,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const caseTabulationDel = (params) =>
+  defHttp.post<Result>({
+    url: Api.caseTabulationDel,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });

+ 52 - 3
src/api/operate/index.ts

@@ -72,6 +72,7 @@ enum Api {
   getInfoMail = '/service/manage/getInfo',
   updateMail = '/service/manage/update',
   caseaddOrUpdate = '/service/manage/case/addOrUpdate',
+  addFusionIds = '/fusion/case/addFusionIds',
   caseList = '/service/manage/case/list',
   caseSceneList = '/service/manage/case/sceneList',
   caseDel = '/service/manage/case/del',
@@ -93,6 +94,9 @@ enum Api {
   sceneList = '/service/manage/jy/userShare/sceneList',
   getCaseByNum = '/service/manage/case/getCaseByNum',
   getSceneBuildLog = '/service/manage/scene/getSceneBuildLog/',
+  uploadSceneOrig = '/service/manage/scene/uploadSceneOrig',
+  uploadSceneCheck = '/service/manage/scene/uploadSceneCheck',
+  caseFusionList = '/service/manage/caseFusion/list',
 }
 
 /**
@@ -182,6 +186,16 @@ export const caseaddOrUpdateApi = (params: PageParams) =>
       ignoreCancelToken: true,
     },
   });
+export const addFusionIds = (params: PageParams) =>
+  defHttp.post<RentListGetResultModel>({
+    url: Api.addFusionIds,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
 
 export const casePublicApi = (params: PageParams) =>
   defHttp.get<RentListGetResultModel>({
@@ -329,7 +343,7 @@ export const newDelete = (params: PageParams) =>
     },
   });
 
-export const operateSceneList = (params: operateList) =>
+export const operateSceneList = (params) =>
   defHttp.post<Result>({
     url: Api.operateSceneList,
     params: params,
@@ -339,6 +353,18 @@ export const operateSceneList = (params: operateList) =>
       ignoreCancelToken: true,
     },
   });
+export const operateAddSceneList = (params) => {
+  console.log('operateAddSceneList', params);
+  return defHttp.post<Result>({
+    url: params.sceneType == 2 || params.sceneType == 3 ? Api.caseFusionList : Api.operateSceneList,
+    params: { ...params, isShare: params.sceneType == 3 || params.sceneType == 1 ? 1 : 0 },
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+};
 export const overallList = (params: overallList) =>
   defHttp.post<Result>({
     url: Api.overallList,
@@ -593,7 +619,7 @@ export const getByRyId = (params) =>
     },
   });
 // 根据警员ID获取用户列表
-export const getinnerByRyId = (params) =>
+export const getinnerByRyId = (params, isTransformResponse= false) =>
   defHttp.post<Result>(
     {
       url: Api.getinnerByRyId,
@@ -604,7 +630,7 @@ export const getinnerByRyId = (params) =>
       },
     },
     {
-      isTransformResponse: false,
+      isTransformResponse: isTransformResponse,
     },
   );
 
@@ -711,3 +737,26 @@ export const getSceneBuildLog = (num) =>
       ignoreCancelToken: true,
     },
   });
+
+export const uploadSceneOrig = (filePath) =>
+  defHttp.post<Result>({
+    url: Api.uploadSceneOrig,
+    params: {
+      filePath,
+    },
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+export const uploadSceneCheck = (filePath) =>
+  defHttp.post<Result>({
+    url: Api.uploadSceneCheck,
+    params: {
+      filePath,
+    },
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });

+ 8 - 5
src/components/Modal/src/BasicModal.vue

@@ -50,7 +50,7 @@
 </template>
 <script lang="ts">
   import type { ModalProps, ModalMethods } from './typing';
-
+  import { debounce } from 'lodash-es';
   import {
     defineComponent,
     computed,
@@ -202,10 +202,13 @@
           fullScreenRef.value = !!props.defaultFullscreen;
         }
       }
-
-      function handleOk(e: Event) {
-        emit('ok', e);
-      }
+      const handleOk = debounce(
+        (e: Event) => {
+          emit('ok', e);
+        },
+        200,
+        { leading: true, trailing: false },
+      );
 
       function handleHeightChange(height: string) {
         emit('height-change', height);

+ 49 - 0
src/components/Prompt/dialog.vue

@@ -0,0 +1,49 @@
+<template>
+  <Modal
+    v-model:open="open"
+    :title="title"
+    @ok="handleSubmit"
+    :destroyOnClose="true"
+    :width="width || '500px'"
+    okText="确定"
+    cancelText="取消"
+  >
+    <div class="pt-5 pr-3px">
+      <BasicForm @register="register" />
+    </div>
+  </Modal>
+</template>
+
+<script setup lang="ts">
+  import { ref } from 'vue';
+  import { Modal } from 'ant-design-vue';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+
+  const props = defineProps<{
+    title: string;
+    addFormSchemas: FormSchema[];
+    onOK?: Fn;
+    width?: string;
+    labelWidth?: number;
+    layout?: 'horizontal' | 'vertical' | 'inline';
+  }>();
+
+  const open = ref<boolean>(true);
+  console.log('handlegoRename', props);
+  const [register, { validate }] = useForm({
+    schemas: props.addFormSchemas,
+    showActionButtonGroup: false,
+    labelWidth: props.labelWidth || 80,
+    layout: props.layout || 'horizontal',
+  });
+
+  async function handleSubmit() {
+    const row = await validate();
+    if (props.onOK) {
+      await props.onOK(row.txt);
+    }
+    open.value = false;
+  }
+</script>
+
+<style scoped></style>

+ 39 - 0
src/components/Prompt/index.ts

@@ -0,0 +1,39 @@
+import { createVNode, VNode, defineComponent, h, render, reactive } from 'vue';
+import { PromptProps, genFormSchemas } from './state';
+import Dialog from './dialog.vue';
+
+export function createPrompt(props: PromptProps) {
+  let vm: Nullable<VNode> = null;
+  const data = reactive({
+    ...props,
+    addFormSchemas: genFormSchemas({
+      label: props.label,
+      required: props.required,
+      inputType: props.inputType,
+      defaultValue: props.defaultValue,
+    }),
+  });
+  const DialogWrap = defineComponent({
+    render() {
+      return h(Dialog, { ...data } as any);
+    },
+  });
+
+  vm = createVNode(DialogWrap);
+  console.log('handlegoRename', data, vm);
+  render(vm, document.createElement('div'));
+
+  function close() {
+    if (vm?.el && vm.el.parentNode) {
+      vm.el.parentNode.removeChild(vm.el);
+    }
+  }
+
+  return {
+    vm,
+    close,
+    get $el() {
+      return vm?.el as HTMLElement;
+    },
+  };
+}

+ 69 - 0
src/components/Prompt/state.ts

@@ -0,0 +1,69 @@
+import { FormSchema } from '/@/components/Form';
+
+type InputType = 'InputTextArea' | 'InputNumber' | 'Input';
+export interface PromptProps {
+  title: string;
+  label?: string;
+  required?: boolean;
+  onOK?: Fn;
+  inputType?: InputType;
+  labelWidth?: number;
+  width?: string;
+  layout?: 'horizontal' | 'vertical' | 'inline';
+  defaultValue?: string | number;
+}
+
+interface genFormSchemasProps {
+  label?: string;
+  required?: boolean;
+  inputType?: InputType;
+  defaultValue?: string | number;
+}
+
+const inputTypeMap: {
+  [key in InputType]: {
+    colProps: { span: number; offset?: number };
+    componentProps: FormSchema['componentProps'];
+  };
+} = {
+  InputTextArea: {
+    colProps: { span: 23 },
+    componentProps: {
+      placeholder: '请输入内容',
+      autoSize: { minRows: 2, maxRows: 6 },
+      maxlength: 255,
+      showCount: true,
+    },
+  },
+  InputNumber: {
+    colProps: { span: 20, offset: 2 },
+    componentProps: {
+      placeholder: '请输入数字',
+      min: 0,
+    },
+  },
+  Input: {
+    colProps: { span: 20, offset: 2 },
+    componentProps: {
+      placeholder: '请输入内容',
+      min: 0,
+    },
+  },
+};
+
+export function genFormSchemas({
+  label = '备注信息',
+  required = true,
+  inputType = 'InputTextArea',
+  defaultValue = '',
+}: genFormSchemasProps) {
+  const formSchema: FormSchema = {
+    field: 'txt',
+    component: inputType,
+    label,
+    defaultValue,
+    required: Boolean(required),
+    ...inputTypeMap[inputType],
+  };
+  return [formSchema];
+}

+ 6 - 5
src/components/Upload/src/UploadModal.vue

@@ -81,7 +81,7 @@
       //   是否正在上传
       const isUploadingRef = ref(false);
       const fileListRef = ref<FileItem[]>([]);
-      const { accept, helpText, maxNumber, maxSize } = toRefs(props);
+      const { accept, helpText, maxNumber, maxSize, sizeUnit } = toRefs(props);
 
       const { t } = useI18n();
       const [register, { closeModal }] = useModalInner();
@@ -91,6 +91,7 @@
         helpTextRef: helpText,
         maxNumberRef: maxNumber,
         maxSizeRef: maxSize,
+        sizeUnitRef: sizeUnit,
       });
 
       const { createMessage } = useMessage();
@@ -125,17 +126,17 @@
       // 上传前校验
       function beforeUpload(file: File) {
         const { size, name } = file;
-        const { maxSize, accept } = props;
+        const { maxSize, accept, sizeUnit } = props;
         const type = name.split('.').pop() || '';
         console.log('beforeUpload', type, name);
         if (accept && accept.length > 0 && !accept.includes(type.toLowerCase())) {
           createMessage.error(t('component.upload.accept', [accept.join(',')]));
           return false;
         }
-        console.log('file', type, props);
+        let newMaxSize = sizeUnit == 'GB'? (maxSize*1024) : sizeUnit == 'KB'? (maxSize/1024) : maxSize
         // 设置最大值,则判断
-        if (maxSize && file.size / 1024 / 1024 >= maxSize) {
-          createMessage.error(t('component.upload.maxSizeMultiple', [maxSize]));
+        if (maxSize && file.size / 1024 / 1024 >= newMaxSize) {
+          createMessage.error(t('component.upload.maxSizeMultiple', {number: maxSize, unit: sizeUnit || 'MB'}));
           return false;
         }
 

+ 14 - 7
src/components/Upload/src/data.tsx

@@ -2,7 +2,8 @@ import type { BasicColumn, ActionItem } from '/@/components/Table';
 import { FileItem, PreviewFileItem, UploadResultStatus } from './typing';
 import {
   // checkImgType,
-  isImgTypeByName,validateBase64
+  isImgTypeByName,
+  validateBase64,
 } from './helper';
 import { Progress, Tag } from 'ant-design-vue';
 import TableAction from '/@/components/Table/src/components/TableAction.vue';
@@ -52,7 +53,13 @@ export function createTableColumns(): BasicColumn[] {
       title: t('component.upload.fileSize'),
       width: 100,
       customRender: ({ text = 0 }) => {
-        return text && (text / 1024).toFixed(2) + 'KB';
+        const kb = text && (text / 1024).toFixed(2);
+        if (kb > 1024 * 1024) {
+          return (kb / (1024 * 1024)).toFixed(2) + 'GB';
+        } else if (kb > 1024) {
+          return (kb / 1024).toFixed(2) + 'MB';
+        }
+        return kb + 'KB';
       },
     },
     // {
@@ -110,10 +117,10 @@ export function createPreviewColumns(): BasicColumn[] {
       title: t('component.upload.legend'),
       width: 100,
       customRender: ({ record }) => {
-        console.log('record',record)
+        console.log('record', record);
         const { url } = (record as PreviewFileItem) || {};
-        if(validateBase64(url)){
-          return <ThumbUrl fileUrl={url} />
+        if (validateBase64(url)) {
+          return <ThumbUrl fileUrl={url} />;
         }
         return isImgTypeByName(url) && <ThumbUrl fileUrl={url} />;
       },
@@ -139,7 +146,7 @@ export function createPreviewActionColumn({
     dataIndex: 'action',
     fixed: false,
     customRender: ({ record }) => {
-      console.log('record',record)
+      console.log('record', record);
       const actions: ActionItem[] = [
         {
           label: t('component.upload.del'),
@@ -148,7 +155,7 @@ export function createPreviewActionColumn({
         },
         {
           label: t('component.upload.download'),
-          ifShow:false,
+          ifShow: false,
           onClick: handleDownload.bind(null, record),
         },
       ];

+ 6 - 0
src/components/Upload/src/props.ts

@@ -1,5 +1,6 @@
 import type { PropType } from 'vue';
 import { FileBasicColumn } from './typing';
+import { string } from 'vue-types';
 
 export const basicProps = {
   helpText: {
@@ -11,6 +12,11 @@ export const basicProps = {
     type: Number as PropType<number>,
     default: 2,
   },
+  // 文件最大多少MB
+  sizeUnit: {
+    type: String,
+    default: 'MB',
+  },
   // 最大数量的文件,Infinity不限制
   maxNumber: {
     type: Number as PropType<number>,

+ 5 - 1
src/components/Upload/src/useUpload.ts

@@ -6,11 +6,13 @@ export function useUploadType({
   helpTextRef,
   maxNumberRef,
   maxSizeRef,
+  sizeUnitRef,
 }: {
   acceptRef: Ref<string[]>;
   helpTextRef: Ref<string>;
   maxNumberRef: Ref<number>;
   maxSizeRef: Ref<number>;
+  sizeUnitRef: String;
 }) {
   // 文件类型限制
   const getAccept = computed(() => {
@@ -46,9 +48,11 @@ export function useUploadType({
     }
 
     const maxSize = unref(maxSizeRef);
+    const unit = unref(sizeUnitRef);
     if (maxSize) {
-      helpTexts.push(t('component.upload.maxSize', [maxSize]));
+      helpTexts.push(t('component.upload.maxSize', { number: maxSize, unit: unit || 'MB' }));
     }
+    console.log('maxSizeMultiple', maxSize, unit, 'helpTexts', helpTexts);
 
     const maxNumber = unref(maxNumberRef);
     if (maxNumber && maxNumber !== Infinity) {

+ 9 - 0
src/design/public.less

@@ -50,3 +50,12 @@
     opacity: 75%;
   }
 }
+// .ant-table-cell-ellipsis:empty:after {
+//       content: "-";
+// }
+.ant-table-cell:empty:after {
+      content: "-";
+}
+.ant-table-cell-fix-right:empty:after {
+      content: "";
+}

+ 1 - 1
src/layouts/default/tabs/index.vue

@@ -18,7 +18,7 @@
         </TabPane>
       </template>
 
-      <template #tabBarExtraContent v-if="getShowRedo || getShowQuick">
+      <template #rightExtra v-if="getShowRedo || getShowQuick">
         <TabRedo v-if="getShowRedo" />
         <TabContent isExtra :tabItem="$route" v-if="getShowQuick" />
         <FoldButton v-if="getShowFold" />

+ 1 - 1
src/locales/lang/en/component.ts

@@ -104,7 +104,7 @@ export default {
     accept: 'Support {0} format',
     acceptUpload: 'Only upload files in {0} format',
     maxSize: 'A single file does not exceed {0}MB ',
-    maxSizeMultiple: 'Only upload files up to {0}MB!',
+    maxSizeMultiple: 'Only upload files up to {number}{unit}!',
     maxNumber: 'Only upload up to {0} files',
 
     legend: 'Legend',

+ 2 - 2
src/locales/lang/zh-CN/component.ts

@@ -106,8 +106,8 @@ export default {
 
     accept: '支持{0}格式',
     acceptUpload: '只能上传{0}格式文件',
-    maxSize: '单个文件不超过{0}MB',
-    maxSizeMultiple: '只能上传不超过{0}MB的文件!',
+    maxSize: '单个文件不超过{number}{unit}',
+    maxSizeMultiple: '只能上传不超过{number}{unit}的文件!',
     maxNumber: '最多只能上传{0}个文件',
 
     legend: '略缩图',

+ 8 - 0
src/settings/siteSetting.ts

@@ -6,3 +6,11 @@ export const DOC_URL = 'https://vvbin.cn/doc-next/';
 
 // site url
 export const SITE_URL = 'https://vvbin.cn/next/';
+
+// sider preset color
+export const SCENE_TYPE: string[] = ['现勘三号', '四维看看', '现勘一号', '现勘二号', '现勘补拍仪'];
+// 更改相机名称:
+// 现勘一号:四维深时
+// 现勘二号:四维深光
+// 现勘三号:四维看见
+// 现勘补拍仪:圆周率

+ 45 - 31
src/utils/file/download.ts

@@ -1,45 +1,55 @@
 import { openWindow } from '..';
 import { dataURLtoBlob, urlToBase64 } from './base64Conver';
-import * as XLSX from 'xlsx' // Vue3 版本
-import fs from 'file-saver'
+import * as XLSX from 'xlsx'; // Vue3 版本
+import fs from 'file-saver';
 /**
  * Download online pictures
  * @param data
  * @param filename
  */
- export function exportElsxFile(json, fields, filename = '表格.xlsx') {
-  json.forEach(item => {
-      for (let i in item) {
-          if (fields.hasOwnProperty(i)) {
-              item[fields[i]] = item[i];
-          }
-          delete item[i]; //删除原先的对象属性
+export function exportElsxFile(json, fields, filename = '表格.xlsx') {
+  json.forEach((item) => {
+    for (const i in item) {
+      if (fields.hasOwnProperty(i)) {
+        item[fields[i]] = item[i];
       }
-  })
+      delete item[i]; //删除原先的对象属性
+    }
+  });
 
-  let sheetName = filename //excel的文件名称
-  let wb = XLSX.utils.book_new()  //工作簿对象包含一SheetNames数组,以及一个表对象映射表名称到表对象。XLSX.utils.book_new实用函数创建一个新的工作簿对象。
-  let ws = XLSX.utils.json_to_sheet(json, { header: Object.values(fields) }) //将JS对象数组转换为工作表。
-  wb.SheetNames.push(sheetName)
-  wb.Sheets[sheetName] = ws
-  const defaultCellStyle = { font: { name: "Verdana", sz: 13, color: "FF00FF88" }, fill: { fgColor: { rgb: "FFFFAA00" } } };//设置表格的样式
-  let wopts = { bookType: 'xlsx', bookSST: false, type: 'binary', cellStyles: true, defaultCellStyle: defaultCellStyle, showGridLines: false }  //写入的样式
-  let wbout = XLSX.write(wb, wopts)
-  let blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' })
-  fs.saveAs(blob, filename + '.xlsx')
+  const sheetName = filename; //excel的文件名称
+  const wb = XLSX.utils.book_new(); //工作簿对象包含一SheetNames数组,以及一个表对象映射表名称到表对象。XLSX.utils.book_new实用函数创建一个新的工作簿对象。
+  const ws = XLSX.utils.json_to_sheet(json, { header: Object.values(fields) }); //将JS对象数组转换为工作表。
+  wb.SheetNames.push(sheetName);
+  wb.Sheets[sheetName] = ws;
+  const defaultCellStyle = {
+    font: { name: 'Verdana', sz: 13, color: 'FF00FF88' },
+    fill: { fgColor: { rgb: 'FFFFAA00' } },
+  }; //设置表格的样式
+  const wopts = {
+    bookType: 'xlsx',
+    bookSST: false,
+    type: 'binary',
+    cellStyles: true,
+    defaultCellStyle: defaultCellStyle,
+    showGridLines: false,
+  }; //写入的样式
+  const wbout = XLSX.write(wb, wopts);
+  const blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' });
+  fs.saveAs(blob, filename + '.xlsx');
 }
-const s2ab = s => {
+const s2ab = (s) => {
   if (typeof ArrayBuffer !== 'undefined') {
-      var buf = new ArrayBuffer(s.length)
-      var view = new Uint8Array(buf)
-      for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff
-      return buf
+    var buf = new ArrayBuffer(s.length);
+    const view = new Uint8Array(buf);
+    for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
+    return buf;
   } else {
-      var buf = new Array(s.length);
-      for (var i = 0; i != s.length; ++i) buf[i] = s.charCodeAt(i) & 0xFF;
-      return buf;
+    var buf = new Array(s.length);
+    for (var i = 0; i != s.length; ++i) buf[i] = s.charCodeAt(i) & 0xff;
+    return buf;
   }
-}
+};
 
 /**
  * Download online pictures
@@ -95,6 +105,10 @@ export function downloadByData(data: BlobPart, filename: string, mime?: string,
  * Download file according to file address
  * @param {*} sUrl
  */
+function getExtension(name) {
+  if (!name) return;
+  return name.substring(name.lastIndexOf('.'));
+}
 export function downloadByUrl({
   url,
   target = '_blank',
@@ -115,9 +129,9 @@ export function downloadByUrl({
     const link = document.createElement('a');
     link.href = url;
     link.target = target;
-
+    const newfileName = fileName + getExtension(url);
     if (link.download !== undefined) {
-      link.download = fileName || url.substring(url.lastIndexOf('/') + 1, url.length);
+      link.download = fileName ? newfileName : url.substring(url.lastIndexOf('/') + 1, url.length);
     }
 
     if (document.createEvent) {

+ 122 - 122
src/views/case/addCaseModal.vue

@@ -1,5 +1,6 @@
 <template>
   <BasicModal
+    class="resultListTab"
     v-bind="$attrs"
     @register="register"
     title="新增案件"
@@ -13,14 +14,36 @@
       <div class="mx-5 BasicForm flex">
         <span style="line-height: 32px; margin-right: 10px">案件名称</span>
         <div class="input">
-          <a-input style="width: 600px" maxlength="100" showCount v-model:value="fileFlow.caseTitle" placeholder="请输入" />
+          <a-input
+            style="width: 600px"
+            maxlength="100"
+            showCount
+            v-model:value="fileFlow.caseTitle"
+            placeholder="请输入"
+          />
         </div>
         <!-- <a-button type="primary" @click="handleAdd"> 新增</a-button> -->
       </div>
-      <BasicTable @register="registerTable">
+      <BasicTable class="zdyform" @register="registerTable">
+        <template #tableTitle>
+          <a-tabs class="resultListTab" v-model:activeKey="sceneType" @change="changeTable">
+            <Tabs.TabPane :key="0" tab="实景三维" />
+            <Tabs.TabPane :key="1" tab="共享实景三维" />
+            <Tabs.TabPane :key="2" tab="多元融合" />
+            <Tabs.TabPane :key="3" tab="共享多元融合" />
+            <!-- <Tabs.TabPane :key="3" tab="多元融合共享" /> -->
+          </a-tabs>
+        </template>
         <template #href="{ record }">
           <a
-            v-if="record.status == 1 || (record.status == -2 && record.payStatus == 1)"
+            v-if="record.fusionTitle"
+            target="_blank"
+            :title="record.fusionTitle"
+            :href="`/code/index.html?caseId=${record.fusionId}#/show`"
+            >{{ record.fusionTitle || record.title }}</a
+          >
+          <a
+            v-else-if="record.status == 1 || (record.status == -2 && record.payStatus == 1)"
             target="_blank"
             :title="record.sceneName"
             :href="record.webSite"
@@ -39,7 +62,9 @@
   import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
   import { useMessage } from '/@/hooks/web/useMessage';
   import { sceneMove } from '/@/api/operate';
+  import { sceneColumns, diversityColumns } from './data';
   import { useI18n } from '/@/hooks/web/useI18n';
+  import { Tabs } from 'ant-design-vue';
   import { getByKey, addOrUpdate, del } from '/@/api/media';
   import {
     BasicTable,
@@ -49,10 +74,10 @@
     TableImg,
     FormProps,
   } from '/@/components/Table';
-  import { caseaddOrUpdateApi, operateSceneList } from '/@/api/operate';
+  import { caseaddOrUpdateApi, operateAddSceneList } from '/@/api/operate';
   const { t } = useI18n();
   export default defineComponent({
-    components: { BasicModal, BasicTable, TableAction },
+    components: { BasicModal, BasicTable, TableAction, [Tabs.name]: Tabs },
     props: {
       userData: { type: Object },
     },
@@ -60,67 +85,14 @@
     setup(props, { emit }) {
       const modelRef = ref({});
       const loading = ref(false);
+      const sceneType = ref(0);
       const fileFlow = reactive({
         caseTitle: '',
         file: null,
         dylist: [],
         mslist: [],
+        fusionIds: [],
       });
-      const columns: BasicColumn[] = [
-        {
-          title: '场景标题',
-          dataIndex: 'sceneName',
-          ellipsis: true,
-          slots: { customRender: 'href' },
-          resizable: true,
-          minWidth: 150,
-          width: 150,
-        },
-        {
-          title: '场景码',
-          dataIndex: 'num',
-          ellipsis: true,
-          width: 180,
-        },
-        {
-          title: '计算完成时间',
-          dataIndex: 'algorithmTime',
-          width: 180,
-        },
-        {
-          title: '场景大小',
-          dataIndex: 'sceneSize',
-          width: 80,
-          customRender: ({ record }) => {
-            return record.sceneSize && record.sceneSize != 0
-              ? h('span', { class: 'sceneSize' }, Math.ceil(record.sceneSize / 1024 / 1024) + 'M')
-              : '-';
-          },
-        },
-        {
-          title: '状态',
-          dataIndex: 'status',
-          width: 80,
-          customRender: ({ record }) => {
-            let str;
-            switch (record.status - 0) {
-              case 0:
-                str = '计算中';
-                break;
-              case 1:
-                str = '计算成功';
-                break;
-              case -2:
-                str = '计算成功';
-                break;
-              case -1:
-                str = '计算失败';
-                break;
-            }
-            return record.payStatus == -2 ? '封存' : str;
-          },
-        },
-      ];
       const searchForm: Partial<FormProps> = {
         labelWidth: 60,
         autoSubmitOnEnter: true,
@@ -139,85 +111,75 @@
               xxl: 7,
             },
           },
-          // {
-          //   field: 'isObj',
-          //   label: '场景类型',
-          //   component: 'Select',
-          //   labelWidth: 80,
-          //   // labelWidth: 50,
-          //   defaultValue: '1',
-          //   componentProps: {
-          //     allowClear: false,
-          //     options: [
-          //       {
-          //         label: '点云场景',
-          //         value: '0',
-          //         key: '0',
-          //       },
-          //       {
-          //         label: 'Mesh 场景',
-          //         value: '1',
-          //         key: '1',
-          //       },
-          //     ],
-          //     onChange: (value) => {
-          //       reload({
-          //         searchInfo: { isObj: value },
-          //       }).then(() => {
-          //         setSelectedRowKeys(value == 0 ? fileFlow.dylist : fileFlow.mslist);
-          //       });
-          //     },
-          //   },
-          //   colProps: {
-          //     xl: 7,
-          //     xxl: 7,
-          //   },
-          // },
         ],
       };
       const { createMessage, createConfirm } = useMessage();
-      const [registerTable, { reload, getForm, setSelectedRowKeys }] = useTable({
-        api: operateSceneList,
-        title: ``,
-        showTableSetting: false,
-        rowSelection: { type: 'checkbox',getCheckboxProps: getRowSelection, onChange: onSelectChange },
-        // titleHelpMessage: ['已启用expandRowByClick', '已启用stopButtonPropagation'],
-        columns: columns,
-        searchInfo: { isObj: '1' },
-        useSearchForm: true,
-        formConfig: searchForm,
-        showIndexColumn: false,
-        rowKey: 'num',
-        fetchSetting: {
-          pageField: 'pageNum',
-          sizeField: 'pageSize',
-          listField: 'list',
-          totalField: 'total',
-        },
-        canResize: true,
-      });
+      const [registerTable, { reload, getForm, setSelectedRowKeys, setPagination, setColumns }] =
+        useTable({
+          api: operateAddSceneList,
+          title: ``,
+          showTableSetting: false,
+          rowSelection: {
+            type: 'checkbox',
+            getCheckboxProps: getRowSelection,
+            onChange: onSelectChange,
+          },
+          // titleHelpMessage: ['已启用expandRowByClick', '已启用stopButtonPropagation'],
+          columns: sceneColumns,
+          searchInfo: { isObj: '1', sceneType: sceneType },
+          useSearchForm: true,
+          formConfig: searchForm,
+          immediate: false,
+          showIndexColumn: false,
+          rowKey: 'num',
+          beforeFetch: (T) => {
+            T.fusionTitle = T.sceneName;
+            return T;
+          },
+          afterFetch: listAfterFetch,
+          fetchSetting: {
+            pageField: 'pageNum',
+            sizeField: 'pageSize',
+            listField: 'list',
+            totalField: 'total',
+          },
+          canResize: true,
+        });
       onMounted(() => {});
       let addListFunc = () => {};
       const [register, { closeModal }] = useModalInner((data) => {
         console.log(data);
         getForm().resetFields();
-        reload()
+        reload();
         data && onDataReceive(data);
       });
       function getRowSelection(record) {
         return {
-        disabled: record.inCase || !(record.status == 1 || record.status == -2), // Column configuration not to be checked
-        name: record.name,}
-       }
+          disabled: !(record.fusionId || record.status == 1 || record.status == -2 ), // Column configuration not to be checked
+          name: record.name,
+        };
+      }
       function onSelectChange(selectedRowKeys: any, selectedRows: any) {
-        fileFlow.dylist = [];
-        fileFlow.mslist = selectedRowKeys;
+        console.log('selectedRowKeys changed: ', selectedRowKeys, selectedRows, sceneType.value);
+        let fusionIds = [], dylist = [], mslist = [];
+        selectedRows.map(ele => {
+          if(ele.fusionId){
+            fusionIds.push(ele.fusionId);
+          }else{
+            mslist.push(ele.num)
+          }
+        })
+        fileFlow.fusionIds = fusionIds;
+        fileFlow.dylist = dylist;
+        fileFlow.mslist = mslist;
       }
       function onDataReceive(data) {
+        sceneType.value = 0;
         fileFlow.caseTitle = '';
         modelRef.value = data;
         fileFlow.dylist = [];
         fileFlow.mslist = [];
+        fileFlow.fusionIds = [];
         fileFlow.caseTitle = '';
         setSelectedRowKeys([]);
       }
@@ -236,8 +198,11 @@
         });
       }
       const handleSubmit = async () => {
-        if(!fileFlow.caseTitle?.trim()){
-          return createMessage.warning('请输入案件名称')
+        if (!fileFlow.caseTitle?.trim()) {
+          return createMessage.warning('请输入案件名称');
+        }
+        if (fileFlow.mslist.length == 0 && fileFlow.fusionIds.length == 0) {
+          return createMessage.warning('至少选择一个场景或者多元融合');
         }
         try {
           loading.value = true;
@@ -252,6 +217,10 @@
                 type: 1,
                 numList: fileFlow.mslist,
               },
+              {
+                type: 2,
+                numList: fileFlow.fusionIds,
+              },
             ],
           };
           console.log('res', apiData);
@@ -259,6 +228,7 @@
           console.log('res', res);
           closeModal();
           createMessage.success('新增案件成功。');
+          sceneType.value = 0;
           emit('update');
           loading.value = false;
         } catch (error) {
@@ -270,6 +240,21 @@
         // console.log(v);
         // v && props.userData && nextTick(() => onDataReceive(props.userData));
       }
+      function changeTable(params) {
+        console.log(params, 'changeTable', sceneType.value);
+        setColumns(sceneType.value == 2 || sceneType.value == 3 ? diversityColumns : sceneColumns);
+        setPagination({ current: 1 });
+        reload();
+      }
+      function listAfterFetch(list) {
+        console.log(list, 'changeTable', sceneType.value);
+        return list.map(ele => {
+          if(!ele.num){
+            ele.num = ele.fusionId;
+          }
+          return ele;
+        });
+      }
       async function handleDelete(record: Recordable) {
         console.log('handleDelete', record);
         createConfirm({
@@ -291,6 +276,8 @@
         registerTable,
         model: modelRef,
         fileFlow,
+        sceneType,
+        changeTable,
         handleVisibleChange,
         handleSubmit,
         addListFunc,
@@ -301,3 +288,16 @@
     },
   });
 </script>
+
+<style lang="less">
+  .resultListTab {
+    .ant-tabs-nav {
+      margin: 0;
+    }
+  }
+  .zdyform {
+    .vben-basic-form {
+      margin: 0;
+    }
+  }
+</style>

+ 227 - 0
src/views/case/addResultModal.vue

@@ -0,0 +1,227 @@
+<template>
+  <div>
+    <BasicModal
+      v-bind="$attrs"
+      @register="register"
+      title="查询权限"
+      okText="查询"
+      @cancel="resetFields"
+      min-height="220px"
+      @ok="handleSubmit"
+    >
+      <div class="pt-2px pr-3px">
+        <div class="text" style="padding: 0 20px 20px 20px"
+          >案件不支持新增权限。您可以搜索指定人员名称查询是否用于有权限,若无可联系场景管理员开通。</div
+        >
+        <BasicForm @register="registerForm">
+          <template #text="{ model, field }">
+            {{ model[field] }}
+          </template>
+        </BasicForm>
+        <div class="text" style="padding: 0 20px"
+          >只要用户拥有至少一个场景的编辑权限,则拥有案件的编辑权限</div
+        >
+        <div class="text" style="padding: 0 20px"
+          >只要用户拥有至少一个场景的查看权限,则拥有案件的查看权限。</div
+        >
+      </div>
+    </BasicModal>
+    <resultListModal @register="registerModal" />
+  </div>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, onMounted, reactive } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { getinnerByRyId, userShareAdd } from '/@/api/operate';
+  import resultListModal from './resultListModal.vue';
+  import { useModal } from '/@/components/Modal';
+  import { getNotAuthScene } from '/@/api/operate/case';
+
+  const { t } = useI18n();
+  export default defineComponent({
+    components: { BasicModal, BasicForm, resultListModal },
+    props: {
+      userData: { type: Object },
+    },
+    emits: ['ok'],
+    setup(_, { emit }) {
+      const modelRef = ref(false);
+      const fileFlow = reactive({
+        file: null,
+      });
+      const { createMessage } = useMessage();
+      const [registerModal, { openModal }] = useModal();
+      const optionsName = ref([]);
+      const schemas: FormSchema[] = [
+        {
+          field: 'caseId',
+          component: 'Input',
+          show: false,
+          label: 'caseId',
+          defaultValue: '111',
+          required: false,
+        },
+        {
+          field: 'ryId',
+          component: 'Input',
+          show: false,
+          label: 'id',
+        },
+        {
+          field: 'ryNo',
+          component: 'Input',
+          label: '人员编号',
+          required: true,
+          rules: [
+            {
+              required: true,
+              // @ts-ignore
+              validator: async (rule, value) => {
+                let myData = await getFieldsValue();
+                if (!value) {
+                  return Promise.reject('请输入人员编号');
+                }
+                let res = await getinnerByRyId({ ryNo: value });
+                console.log('value', value, res);
+                if (res && !res.data) {
+                  return Promise.reject('人员编号不存在');
+                }
+                Promise.resolve();
+                let ryNickName = res && res.data && res.data.ryNickName;
+                if (myData.ryNickName != ryNickName || !myData.ryNickName) {
+                  setFieldsValue({
+                    ryNickName: res && res.data ? res.data.ryNickName : '',
+                    id: res && res.data ? res.data.id : '',
+                    ryId: res && res.data ? res.data.ryId : '',
+                  });
+                }
+              },
+              trigger: 'blur',
+            },
+          ],
+          colProps: {
+            span: 20,
+          },
+        },
+        // {
+        //   field: 'ryNo',
+        //   component: 'AutoComplete',
+        //   label: '人员编号',
+        //   required: true,
+        //   componentProps: {
+        //     filterOption: onFilterOption,
+        //     onSearch: onSearch,
+        //     onChange: (data) => {
+        //       setTimeout(() => {
+        //         const item = optionsName.value && optionsName.value.find((ele) => ele.ryNo == data);
+        //         setFieldsValue({
+        //           ryNickName: item && item.ryNickName ? item.ryNickName : '',
+        //           id: item && item.id ? item.id : '',
+        //         });
+        //       }, 100);
+        //     },
+        //   },
+        //   colProps: {
+        //     span: 20,
+        //   },
+        // },
+        {
+          field: 'ryNickName',
+          component: 'Input',
+          label: '姓名',
+          // rules: [
+          //   {
+          //     required: true,
+          //     // @ts-ignore
+          //     validator: async (rule, value) => {
+          //       if (!value) {
+          //         return Promise.reject('请输入正确的人员编号');
+          //       }
+          //       return Promise.resolve();
+          //     },
+          //     trigger: 'change',
+          //   },
+          // ],
+          colProps: {
+            span: 20,
+          },
+          componentProps: {
+            disabled: true,
+          },
+        },
+      ];
+      const [
+        registerForm,
+        { validate, resetFields, setFieldsValue, getFieldsValue, updateSchema },
+      ] = useForm({
+        labelWidth: 110,
+        schemas,
+        showActionButtonGroup: false,
+        actionColOptions: {
+          span: 24,
+        },
+      });
+
+      onMounted(() => {});
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner(async (data) => {
+        console.log('useModalInner', data);
+        setFieldsValue({caseId: data.caseId})
+      });
+      function onFilterOption(inputText: string, option) {
+        console.log('option', inputText, option.value);
+        if (option.value) {
+          return option.value.indexOf(inputText) >= 0;
+        }
+        // return option.value.indexOf(inputText.toUpperCase()) >= 0;
+      }
+      async function onSearch(searchText) {
+        const res = await getinnerByRyId({ ryNo: searchText });
+        console.log('res', res.data);
+        if (!res.data) return;
+        optionsName.value = res.data || {};
+        updateSchema({
+          field: 'ryNo',
+          componentProps: {
+            options: [optionsName.value],
+          },
+        });
+      }
+      const handleSubmit = async () => {
+        const params = await validate();
+        try {
+          let data = await getNotAuthScene({ ...params, authType: 0, sourceType: 'scene' },true) || [];
+          console.log('not passing', data);
+          let isChecke = data.some((item) => item.list && item.list.length);
+          console.log('not passing', data, isChecke);
+          if ( !isChecke ) {
+            closeModal();
+            resetFields();
+            emit('ok');
+            createMessage.success('此用户拥有所有场景或者多元融合的查看、编辑权限');
+          } else {
+            openModal(true, {...params, name: params.ryNickName});
+          }
+        } catch (error) {
+          console.log('not passing', error);
+        }
+      };
+
+      return {
+        register,
+        schemas,
+        registerForm,
+        modelRef,
+        fileFlow,
+        handleSubmit,
+        addListFunc,
+        registerModal,
+        resetFields,
+        t,
+      };
+    },
+  });
+</script>

+ 104 - 0
src/views/case/data.tsx

@@ -0,0 +1,104 @@
+import { BasicColumn } from '/@/components/Table/src/types/table';
+import { Time } from '/@/components/Time';
+import { h } from 'vue';
+import { Badge } from 'ant-design-vue';
+
+export const sceneColumns: BasicColumn[] = [
+  {
+    title: '场景标题',
+    dataIndex: 'sceneName',
+    ellipsis: true,
+    slots: { customRender: 'href' },
+    resizable: true,
+    minWidth: 150,
+    width: 150,
+  },
+  {
+    title: '场景码',
+    dataIndex: 'num',
+    ellipsis: true,
+    width: 180,
+  },
+  {
+    title: '计算完成时间',
+    dataIndex: 'algorithmTime',
+    width: 180,
+  },
+  {
+    title: '场景大小',
+    dataIndex: 'sceneSize',
+    width: 80,
+    customRender: ({ record }) => {
+      return record.sceneSize && record.sceneSize != 0
+        ? h('span', { class: 'sceneSize' }, Math.ceil(record.sceneSize / 1024 / 1024) + 'M')
+        : '-';
+    },
+  },
+  {
+    title: '状态',
+    dataIndex: 'status',
+    width: 80,
+    customRender: ({ record }) => {
+      let str;
+      switch (record.status - 0) {
+        case 0:
+          str = '计算中';
+          break;
+        case 1:
+          str = '计算成功';
+          break;
+        case -2:
+          str = '计算成功';
+          break;
+        case -1:
+          str = '计算失败';
+          break;
+      }
+      return record.payStatus == -2 ? '封存' : str;
+    },
+  },
+];
+
+export const diversityColumns: BasicColumn[] = [
+  {
+    title: '标题',
+    dataIndex: 'sceneName',
+    ellipsis: true,
+    slots: { customRender: 'href' },
+    resizable: true,
+    minWidth: 150,
+    width: 300,
+  },
+  // {
+  //   title: '所属案件',
+  //   dataIndex: 'caseTitle',
+  //   slots: { customRender: 'caseTitle' },
+  //   ellipsis: true,
+  //   width: 140,
+  // },
+  {
+    title: '人员编号',
+    dataIndex: 'ryNo',
+    ellipsis: true,
+    width: 140,
+  },
+  // {
+  //   title: '姓名',
+  //   dataIndex: 'ryNickName',
+  //   ellipsis: true,
+  //   width: 140,
+  // },
+  {
+    title: '创建时间',
+    dataIndex: 'createTime',
+    width: 180,
+    customRender: ({ record }) => {
+      return record.createTime
+        ? h(Time, {
+            value: record.createTime,
+            mode: 'datetime',
+          })
+        : '-';
+    },
+  },
+];

+ 31 - 24
src/views/case/list.vue

@@ -5,8 +5,8 @@
         <a-tabs v-model:activeKey="tableType" @change="changeTable">
           <Tabs.TabPane :key="0" tab="案件管理" :disabled="loading" />
           <Tabs.TabPane :key="1" tab="案件共享" :disabled="loading" />
-        </a-tabs
-      ></template>
+        </a-tabs>
+      </template>
       <div class="desc-wrap-BasicTable">
         <BasicTable @register="registerTable">
           <template #toolbar>
@@ -18,7 +18,7 @@
               v-if="record.caseTitle"
               target="_blank"
               :title="record.caseTitle"
-              :href="`/code/index.html?caseId=${record.caseId}#/show`"
+              :href="`/mix3d/?show=true#/abstract/${record.caseId}`"
               >{{ record.caseTitle }}</a
             >
             <span v-else>-</span>
@@ -29,35 +29,25 @@
               :actions="[
                 {
                   label: '编辑',
-                  disabled: tableType == 1 && !record.isEdit,
-                  ifShow: getTypeCheckPerm('case-edit'),
+                  //disabled: !record.isEdit,
+                  ifShow: (tableType == 1 && record.isEdit || tableType == 0) && getTypeCheckPerm('case-edit'),
                   onClick: handlegotoEdit.bind(null, record),
                 },
                 {
                   label: '权限',
-                  disabled: tableType == 1 && !record.isAuth,
-                  ifShow: getTypeCheckPerm('case-powers'),
+                  ifShow: (record.isAuth && tableType == 0) && getTypeCheckPerm('case-powers'),
                   onClick: handlePowers.bind(null, record),
                 },
-                {
-                  label: '下载',
-                  ifShow: getTypeCheckPerm('case-download') && !record.isOpen,
-                  //  getTypeCheckPerm('scenes-download') &&
-                  //  tableType != 3 &&
-                  //  (record.userName == userInfo.userName ||
-                  //    userInfo.roleId == 1 ||
-                  //    userInfo.roleId == 45 ||
-                  //    userInfo.roleId == 48),
-                  // disabled: !(record.status == 1 || (record.status == -2 && record.payStatus == 1)),
-                  //icon: 'carbon:download',
-                  disabled:  tableType == 1,
-                  onClick: createConfirmDownload.bind(null, record),
-                },
+                //{
+                //  label: '下载',
+                //  ifShow: getTypeCheckPerm('case-download') && !record.isOpen,
+                //  disabled:  tableType == 0,
+                //  onClick: createConfirmDownload.bind(null, record),
+                //},
                 {
                   label: '删除',
-                  ifShow: getTypeCheckPerm('case-delete') && !record.isOpen,
+                  ifShow: tableType == 0 && getTypeCheckPerm('case-delete') && !record.isOpen,
                   //icon: 'ic:outline-delete-outline',
-                  disabled: tableType == 1,
                   color: 'error',
                   onClick: handleDelete.bind(null, record),
                 },
@@ -78,6 +68,7 @@
       />
       <MoveModal @register="registerMoveModal" />
       <AddModal @register="registerAddModal"  @update="reload"/>
+      <AddResultModal @register="registerResultModal"  @update="reload"/>
       <PowersModal @register="registerPowersModal" />
     </PageWrapper>
   </div>
@@ -97,6 +88,7 @@
   } from '/@/components/Table';
   import { PageWrapper } from '/@/components/Page';
   import AddModal from './addCaseModal.vue'
+  import AddResultModal from './addResultModal.vue'
   import DownLoadModal from './DownLoadModal.vue';
   import MoveModal from '/@/views/productOperation/modal/MoveModal.vue';
   import PowersModal from '/@/views/productOperation/modal/PowersModal.vue';
@@ -138,6 +130,7 @@
       [Descriptions.name]: Descriptions,
       [Descriptions.Item.name]: Descriptions.Item,
       QrCode,
+      AddResultModal,
       AddModal,
       // Tabs,
       [Tabs.name]: Tabs,
@@ -175,6 +168,14 @@
           width: 100,
         },
         {
+          title: '勘验号',
+          dataIndex: 'knumber',
+          ellipsis: true,
+          slots: { customRender: 'href' },
+          resizable: true,
+          width: 100,
+        },
+        {
           title: '创建时间',
           dataIndex: 'createTime',
           width: 230,
@@ -313,6 +314,7 @@
         downloadOption.value = {};
       }
       const [registerAddModal, { openModal: openAddModal }] = useModal();
+      const [registerResultModal, { openModal: openAddResultModal }] = useModal();
       const [registerDownModal, { openModal: openDownModal }] = useModal();
       const [registerMoveModal, { openModal: openMoveModal }] = useModal();
       const [registerPowersModal, { openModal: openPowersModal }] = useModal();
@@ -508,10 +510,14 @@
         // }
       }
       function handlePowers(record: Recordable) {
-        openPowersModal(true, {
+        openAddResultModal(true, {
           ...record,
           tableType: tableType.value,
         });
+        // openPowersModal(true, {
+        //   ...record,
+        //   tableType: tableType.value,
+        // });
       }
       onMounted(() => {
       });
@@ -531,6 +537,7 @@
         registerDownModal,
         registerMoveModal,
         registerAddModal,
+        registerResultModal,
         afterClose,
         timer,
         canDownload,

+ 223 - 0
src/views/case/resultListModal.vue

@@ -0,0 +1,223 @@
+<template>
+  <BasicModal
+    class="resultListTab"
+    v-bind="$attrs"
+    @register="register"
+    :showCancelBtn="false"
+    :title="fileFlow.name + '查询结果'"
+    okText="我知道了"
+    @visible-change="handleVisibleChange"
+    :confirmLoading="loading"
+    width="700px"
+    min-height="50"
+    @ok="handleSubmit"
+  >
+    <div class="pt-2px pr-3px">
+      <div class="text"
+        >查询到 {{ fileFlow.name }}
+        <!-- <span style="color: #0960bd">{{ fileFlow.name }}</span> -->
+        无以下场景权限,请联系管理员开通</div
+      >
+      <BasicTable class="zdyform" @register="registerTable">
+        <template #tableTitle>
+          <a-tabs v-model:activeKey="authType" @change="changeTable">
+          <Tabs.TabPane :key="0" tab="场景查看权限" :disabled="loading" />
+          <Tabs.TabPane :key="1" tab="场景编辑权限" :disabled="loading" />
+          <Tabs.TabPane :key="2" tab="多元融合查看权限" :disabled="loading" />
+          <Tabs.TabPane :key="3" tab="多元融合编辑权限" :disabled="loading" />
+        </a-tabs>
+          <!-- <a-tabs class="resultListTab" v-model:activeKey="authType" @change="changeTable">
+            <Tabs.TabPane :key="0" tab="查看权限" />
+            <Tabs.TabPane :key="1" tab="编辑权限" />
+          </a-tabs> -->
+        </template>
+        <template #href="{ record }">
+          <a v-if="record.title" target="_blank" :title="record.title" :href="record.webSite">{{
+            record.title
+          }}</a>
+          <span v-else>-</span>
+        </template>
+        <template #href1="{ record }">
+          <a v-if="record.title" target="_blank" :title="record.title" :href="`/code/index.html?caseId=${record.id}#/show`">{{
+            record.title
+          }}</a>
+          <span v-else>-</span>
+        </template>
+      </BasicTable>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, nextTick, onMounted, reactive, ref } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicTable, useTable } from '/@/components/Table';
+  import { Tabs } from 'ant-design-vue';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { InvoiceRegister } from '/@/api/order';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { uploadApi } from '/@/api/product/index';
+  import { ResultEnum } from '/@/enums/httpEnum';
+  import { caseListApi } from '/@/api/operate';
+  import { getNotAuthScene } from '/@/api/operate/case';
+  const { t } = useI18n();
+  export default defineComponent({
+    components: { BasicModal, BasicTable, [Tabs.name]: Tabs },
+    props: {
+      userData: { type: Object },
+    },
+    emits: ['update', 'register'],
+    setup(props, { emit }) {
+      const fileFlow = reactive({
+        file: null,
+        name: '',
+        list: [],
+        type: 2, //2-普通发票,3-专用发票
+      });
+      const caseId = ref<number>(0); //0查看 、1编辑
+      const ryId = ref<string>(''); //0查看 、1编辑
+      const authType = ref<number>(0); //0查看 、1编辑
+      const sourceType = ref<string>('scene'); //0查看 、1编辑
+      const columns = [
+        {
+          title: '场景标题',
+          dataIndex: 'sceneName',
+          ellipsis: true,
+          slots: { customRender: 'href' },
+          resizable: true,
+          minWidth: 150,
+          width: 250,
+        },
+        {
+          title: '姓名',
+          dataIndex: 'ryNickName',
+          ellipsis: true,
+        },
+      ];
+      const columns1 = [
+        {
+          title: '标题',
+          dataIndex: 'sceneName',
+          ellipsis: true,
+          slots: { customRender: 'href1' },
+          resizable: true,
+          minWidth: 150,
+          width: 250,
+        },
+        {
+          title: '姓名',
+          dataIndex: 'ryNickName',
+          ellipsis: true,
+        },
+      ];
+      const [registerTable, { reload, setTableData, setColumns }] = useTable({
+        title: ``,
+        // titleHelpMessage: ['已启用expandRowByClick', '已启用stopButtonPropagation'],
+        columns: columns,
+        searchInfo: { authType: authType.value == 2?0:authType.value == 3?1:authType, caseId: caseId, ryId: ryId, sourceType },
+        useSearchForm: false,
+        showIndexColumn: false,
+        showTableSetting: true,
+        pagination: false,
+        //beforeFetch: (T) => {
+        //  loading.value = true;
+        //  return T;
+        //},
+        //afterFetch: (T) => {
+        //  loading.value = false;
+        //  return T;
+        //},
+        rowKey: 'caseId',
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'pageSize',
+          listField: 'list',
+          totalField: 'total',
+        },
+        canResize: true,
+      });
+      const okText = ref('确定');
+      const loading = ref(false);
+      const { createMessage } = useMessage();
+
+      onMounted(() => {});
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner((data) => {
+        data && onDataReceive(data);
+      });
+      function onDataReceive(data) {
+        caseId.value = data.caseId || data.id;
+        fileFlow.name = data.ryNo;
+        ryId.value = data.ryId;
+        getList()
+      }
+      const handleSubmit = async () => {
+        loading.value = true;
+        try {
+          // const params = await validate();
+          // const apiData = params;
+          // console.log('res', apiData, params);
+          // await InvoiceRegister(apiData);
+          closeModal();
+          authType.value = 0
+          changeTable()
+          // createMessage.success(t('common.optSuccess'));
+          emit('update');
+          loading.value = false;
+        } catch (error) {
+          loading.value = false;
+          console.log('not passing', error);
+        }
+      };
+      const getList = async () => {
+        fileFlow.list = await getNotAuthScene({caseId: caseId.value, ryId: ryId.value})
+          console.log('not passing', fileFlow.list, authType.value);
+        let { list } = fileFlow.list[authType.value];
+          console.log('not passing', list);
+        setTableData(list)
+      }
+      function changeTable() {
+        console.log('changeTable', authType);
+        if (authType.value == 1 || authType.value == 0) {
+          sourceType.value = 'scene';
+        } else {
+          sourceType.value = 'fusion';
+        }
+        setColumns(sourceType.value == 'scene'?columns:columns1);
+        let { list } = fileFlow.list[authType.value];
+        console.log('setTableData', list);
+        setTableData(list || [])
+        // reload();
+      }
+      function handleVisibleChange(v) {
+        v && props.userData && nextTick(() => onDataReceive(props.userData));
+      }
+      return {
+        register,
+        registerTable,
+        fileFlow,
+        handleVisibleChange,
+        handleSubmit,
+        addListFunc,
+        reload,
+        okText,
+        authType,
+        loading,
+        changeTable,
+        t,
+      };
+    },
+  });
+</script>
+
+<style lang="less">
+  .resultListTab {
+    .ant-tabs-nav {
+      margin: 0;
+    }
+  }
+  .zdyform {
+    .vben-basic-form {
+      margin: 0;
+    }
+  }
+</style>

+ 6 - 5
src/views/device/index.vue

@@ -60,6 +60,7 @@
   import batchOutflowModal from './OutflowModal.vue';
   import detailModal from './detailsMoadl.vue';
   import batchPutModal from './batchPutModal.vue';
+  import { SCENE_TYPE } from '/@/settings/siteSetting';
   import PutModal from './putModal.vue';
   import { useModal } from '/@/components/Modal';
   import { useRouter } from 'vue-router';
@@ -111,11 +112,11 @@
           customRender: ({ record }) => {
             let typeObj = {
               '0': '旧双目相机',
-              '1': '四维看看',
-              '2': '四维看看lite',
-              '9': '四维看见',
-              '10': '四维深时',
-              '11': '四维深光',
+              '1': SCENE_TYPE[1],
+              '2': SCENE_TYPE[1],
+              '9': SCENE_TYPE[0],
+              '10': SCENE_TYPE[2],
+              '11': SCENE_TYPE[3],
             };
             return typeObj[record.type];
           }

+ 78 - 0
src/views/diversity/DownLoadModal.vue

@@ -0,0 +1,78 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    title="系统正在为您打包数据"
+    :minHeight="0"
+    @visible-change="handleVisibleChange"
+    @cancel="hundleCancel"
+    @ok="handleSubmit"
+  >
+    <div class="pt-2px pr-3px">
+      <div class="warp">
+        <p>正在打包场景离线数据{{ downloadPercent }}</p>
+        <span>{{ modelRef.sceneName }}.zip</span>
+        <Progress :percent="downloadOption.percent" />
+        <p>* 打包完成后将关闭弹窗自动下载。</p>
+      </div>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, nextTick, onMounted, reactive } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { Progress } from 'ant-design-vue';
+  const { t } = useI18n();
+
+  export default defineComponent({
+    components: { BasicModal, Progress },
+    props: {
+      userData: { type: Object },
+      downloadOption: { type: Object },
+    },
+    emits: ['update', 'register', 'cancelDownload'],
+    setup(props, { emit }) {
+      const modelRef = ref({});
+
+      const { createMessage } = useMessage();
+
+      onMounted(() => {});
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner((data) => {
+        // data && onDataReceive(data);
+        modelRef.value = data;
+      });
+
+      const handleSubmit = async () => {
+        console.log(props.downloadOption);
+        if (props.downloadOption.url) {
+          window.open(props.downloadOption.url);
+        }
+      };
+      const hundleCancel = async () => {
+        emit('cancelDownload');
+      };
+
+      return {
+        register,
+        modelRef,
+        handleSubmit,
+        hundleCancel,
+        addListFunc,
+        t,
+      };
+    },
+  });
+</script>
+<style lang="less" scoped>
+  .pt-2px {
+  }
+  .warp {
+    display: flex;
+    align-items: flex-start;
+    justify-content: flex-start;
+    flex-flow: column;
+  }
+</style>

+ 147 - 0
src/views/diversity/MoveModal.vue

@@ -0,0 +1,147 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    title="迁移多元融合"
+    @visible-change="handleVisibleChange"
+    @cancel="resetFields"
+    @ok="handleSubmit"
+    :min-height="0"
+  >
+    <div class="pt-2px pr-3px">
+      <BasicForm @register="registerForm" :model="model">
+        <template #text="{ model, field }">
+          {{ model[field] }}
+        </template>
+      </BasicForm>
+      <span>注意:迁移后权限配置将被清空,如需保留,请复制后再做迁移</span>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, nextTick, onMounted, reactive } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { caseFusionMove } from '/@/api/operate/case';
+  import { useI18n } from '/@/hooks/web/useI18n';
+
+  const { t } = useI18n();
+  export default defineComponent({
+    components: { BasicModal, BasicForm },
+    props: {
+      userData: { type: Object },
+    },
+    emits: ['update', 'register'],
+    setup(props, { emit }) {
+      const modelRef = ref({});
+      const fileFlow = reactive({
+        file: null,
+      });
+      const { createMessage } = useMessage();
+      const schemas: FormSchema[] = [
+        {
+          field: 'fusionId',
+          component: 'Input',
+          show: false,
+          label: 'id',
+          required: false,
+        },
+        {
+          field: 'fusionTitle',
+          component: 'Input',
+          // defaultValue: '场景标题',
+          label: '标题',
+          slot: 'text',
+          colProps: {
+            span: 24,
+          },
+          // required: true,
+        },
+        {
+          field: 'ryNo',
+          component: 'Input',
+          label: '迁移至',
+
+          required: true,
+          colProps: {
+            span: 16,
+          },
+          rules: [
+            {
+              required: true,
+              // @ts-ignore
+              validator: async (rule, value) => {
+                if (!value) {
+                  return Promise.reject('请输入人员编号');
+                }
+                // if (/.*[\u4e00-\u9fa5]+.*$/.test(value)) {
+                //   /* eslint-disable-next-line */
+                //   return Promise.reject('不支持中文字符');
+                // }
+                return Promise.resolve();
+              },
+              trigger: 'change',
+            },
+          ],
+          componentProps: {
+            placeholder: '请输入人员编号',
+            maxLength: 15,
+            onChange: (data) => {
+              console.log('data', data);
+            },
+          },
+        },
+      ];
+      const [registerForm, { validate, resetFields, setFieldsValue }] = useForm({
+        labelWidth: 120,
+        schemas,
+        showActionButtonGroup: false,
+        actionColOptions: {
+          span: 24,
+        },
+      });
+      onMounted(() => {});
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner((data) => {
+        console.log(data);
+        data && onDataReceive({...data, ryNo: ''});
+      });
+
+      function onDataReceive(data) {
+        modelRef.value = data;
+        resetFields();
+        setFieldsValue(data);
+      }
+      const handleSubmit = async () => {
+        try {
+          const params = await validate();
+          const res = await caseFusionMove(params);
+          console.log('res', res);
+          closeModal();
+          resetFields();
+          createMessage.success('迁移成功。');
+          emit('update');
+        } catch (error) {
+          console.log('not passing', error);
+        }
+      };
+      function handleVisibleChange(v) {
+        // console.log(v);
+        // v && props.userData && nextTick(() => onDataReceive(props.userData));
+      }
+      return {
+        register,
+        schemas,
+        registerForm,
+        model: modelRef,
+        fileFlow,
+        handleVisibleChange,
+        handleSubmit,
+        addListFunc,
+        resetFields,
+        t,
+      };
+    },
+  });
+</script>

+ 315 - 0
src/views/diversity/addCaseModal.vue

@@ -0,0 +1,315 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    title="新增案件"
+    @visible-change="handleVisibleChange"
+    @ok="handleSubmit"
+    :confirmLoading="loading"
+    :width="900"
+    :min-height="0"
+  >
+    <div class="pt-2px pr-3px">
+      <div class="mx-5 BasicForm flex">
+        <span style="line-height: 32px; margin-right: 10px">案件名称</span>
+        <div class="input">
+          <a-input
+            style="width: 600px"
+            maxlength="100"
+            showCount
+            v-model:value="fileFlow.caseTitle"
+            placeholder="请输入"
+          />
+        </div>
+        <!-- <a-button type="primary" @click="handleAdd"> 新增</a-button> -->
+      </div>
+      <BasicTable @register="registerTable">
+
+        <template #href="{ record }">
+          <a
+            v-if="record.status == 1 || (record.status == -2 && record.payStatus == 1)"
+            target="_blank"
+            :title="record.sceneName"
+            :href="record.webSite"
+            >{{ record.sceneName }}</a
+          >
+          <span v-else-if="record.sceneName">{{ record.sceneName }}</span>
+          <span v-else>-</span>
+        </template>
+      </BasicTable>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, nextTick, onMounted, reactive, h } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { sceneMove } from '/@/api/operate';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { getByKey, addOrUpdate, del } from '/@/api/media';
+  import {
+    BasicTable,
+    useTable,
+    TableAction,
+    BasicColumn,
+    TableImg,
+    FormProps,
+  } from '/@/components/Table';
+  import { caseaddOrUpdateApi, operateSceneList } from '/@/api/operate';
+  const { t } = useI18n();
+  export default defineComponent({
+    components: { BasicModal, BasicTable, TableAction },
+    props: {
+      userData: { type: Object },
+    },
+    emits: ['update', 'register'],
+    setup(props, { emit }) {
+      const modelRef = ref({});
+      const loading = ref(false);
+      const fileFlow = reactive({
+        caseTitle: '',
+        file: null,
+        dylist: [],
+        mslist: [],
+      });
+      const columns: BasicColumn[] = [
+        {
+          title: '场景标题',
+          dataIndex: 'sceneName',
+          ellipsis: true,
+          slots: { customRender: 'href' },
+          resizable: true,
+          minWidth: 150,
+          width: 150,
+        },
+        {
+          title: '场景码',
+          dataIndex: 'num',
+          ellipsis: true,
+          width: 180,
+        },
+        {
+          title: '计算完成时间',
+          dataIndex: 'algorithmTime',
+          width: 180,
+        },
+        {
+          title: '场景大小',
+          dataIndex: 'sceneSize',
+          width: 80,
+          customRender: ({ record }) => {
+            return record.sceneSize && record.sceneSize != 0
+              ? h('span', { class: 'sceneSize' }, Math.ceil(record.sceneSize / 1024 / 1024) + 'M')
+              : '-';
+          },
+        },
+        {
+          title: '状态',
+          dataIndex: 'status',
+          width: 80,
+          customRender: ({ record }) => {
+            let str;
+            switch (record.status - 0) {
+              case 0:
+                str = '计算中';
+                break;
+              case 1:
+                str = '计算成功';
+                break;
+              case -2:
+                str = '计算成功';
+                break;
+              case -1:
+                str = '计算失败';
+                break;
+            }
+            return record.payStatus == -2 ? '封存' : str;
+          },
+        },
+      ];
+      const searchForm: Partial<FormProps> = {
+        labelWidth: 60,
+        autoSubmitOnEnter: true,
+        autoAdvancedLine: 1,
+        schemas: [
+          {
+            field: 'sceneName',
+            label: '名称',
+            component: 'Input',
+            componentProps: {
+              maxLength: 100,
+              placeholder: ' 请名称搜索',
+            },
+            colProps: {
+              xl: 7,
+              xxl: 7,
+            },
+          },
+          // {
+          //   field: 'isObj',
+          //   label: '场景类型',
+          //   component: 'Select',
+          //   labelWidth: 80,
+          //   // labelWidth: 50,
+          //   defaultValue: '1',
+          //   componentProps: {
+          //     allowClear: false,
+          //     options: [
+          //       {
+          //         label: '点云场景',
+          //         value: '0',
+          //         key: '0',
+          //       },
+          //       {
+          //         label: 'Mesh 场景',
+          //         value: '1',
+          //         key: '1',
+          //       },
+          //     ],
+          //     onChange: (value) => {
+          //       reload({
+          //         searchInfo: { isObj: value },
+          //       }).then(() => {
+          //         setSelectedRowKeys(value == 0 ? fileFlow.dylist : fileFlow.mslist);
+          //       });
+          //     },
+          //   },
+          //   colProps: {
+          //     xl: 7,
+          //     xxl: 7,
+          //   },
+          // },
+        ],
+      };
+      const { createMessage, createConfirm } = useMessage();
+      const [registerTable, { reload, getForm, setSelectedRowKeys }] = useTable({
+        api: operateSceneList,
+        title: ``,
+        showTableSetting: false,
+        rowSelection: {
+          type: 'checkbox',
+          getCheckboxProps: getRowSelection,
+          onChange: onSelectChange,
+        },
+        // titleHelpMessage: ['已启用expandRowByClick', '已启用stopButtonPropagation'],
+        columns: columns,
+        searchInfo: { isObj: '1' },
+        useSearchForm: true,
+        formConfig: searchForm,
+        showIndexColumn: false,
+        rowKey: 'num',
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'pageSize',
+          listField: 'list',
+          totalField: 'total',
+        },
+        canResize: true,
+      });
+      onMounted(() => {});
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner((data) => {
+        console.log(data);
+        getForm().resetFields();
+        reload();
+        data && onDataReceive(data);
+      });
+      function getRowSelection(record) {
+        return {
+          disabled: record.inCase || !(record.status == 1 || record.status == -2), // Column configuration not to be checked
+          name: record.name,
+        };
+      }
+      function onSelectChange(selectedRowKeys: any, selectedRows: any) {
+        fileFlow.dylist = [];
+        fileFlow.mslist = selectedRowKeys;
+      }
+      function onDataReceive(data) {
+        fileFlow.caseTitle = '';
+        modelRef.value = data;
+        fileFlow.dylist = [];
+        fileFlow.mslist = [];
+        fileFlow.caseTitle = '';
+        setSelectedRowKeys([]);
+      }
+      function handleAdd() {
+        console.log('handleAdd', fileFlow.dictName);
+        let params = {
+          dictName: fileFlow.dictName.trim(),
+        };
+        if (!fileFlow.dictName.trim()) {
+          return createMessage.warning('请输入名称');
+        }
+        addOrUpdate(params).then((res) => {
+          createMessage.success('添加成功');
+          fileFlow.dictName = '';
+          reload();
+        });
+      }
+      const handleSubmit = async () => {
+        if (!fileFlow.caseTitle?.trim()) {
+          return createMessage.warning('请输入案件名称');
+        }
+        try {
+          loading.value = true;
+          const apiData = {
+            caseTitle: fileFlow.caseTitle?.trim(),
+            sceneNumParam: [
+              {
+                type: 0,
+                numList: fileFlow.dylist,
+              },
+              {
+                type: 1,
+                numList: fileFlow.mslist,
+              },
+            ],
+          };
+          console.log('res', apiData);
+          const res = await caseaddOrUpdateApi(apiData);
+          console.log('res', res);
+          closeModal();
+          createMessage.success('新增案件成功。');
+          emit('update');
+          loading.value = false;
+        } catch (error) {
+          loading.value = false;
+          console.log('not passing', error);
+        }
+      };
+      function handleVisibleChange(v) {
+        // console.log(v);
+        // v && props.userData && nextTick(() => onDataReceive(props.userData));
+      }
+      async function handleDelete(record: Recordable) {
+        console.log('handleDelete', record);
+        createConfirm({
+          title: '删除',
+          content: '确定要删除吗?',
+          onOk: async () => {
+            del({ id: record.id }).then(() => {
+              createMessage.success({
+                content: '删除成功',
+              });
+              reload();
+            });
+          },
+        });
+      }
+      return {
+        register,
+        handleAdd,
+        registerTable,
+        model: modelRef,
+        fileFlow,
+        handleVisibleChange,
+        handleSubmit,
+        addListFunc,
+        handleDelete,
+        t,
+        loading,
+      };
+    },
+  });
+</script>

+ 508 - 0
src/views/diversity/list.vue

@@ -0,0 +1,508 @@
+<template>
+  <div class="scren">
+    <PageWrapper contentBackground>
+      <template #footer>
+        <a-tabs v-model:activeKey="tableType" @change="changeTable">
+          <Tabs.TabPane :key="0" tab="多元融合" :disabled="loading" />
+          <Tabs.TabPane :key="1" tab="共享多元融合" :disabled="loading" />
+        </a-tabs
+      ></template>
+      <div class="desc-wrap-BasicTable">
+        <BasicTable @register="registerTable" :columns="columnsFun">
+          <template #toolbar>
+            <a-button type="primary"  @click="handleAdd" v-if="getCheckPerm('diversity-Add') && tableType == 0"> 新增</a-button>
+          </template>
+
+          <template #href="{ record }">
+            <a
+              v-if="record.fusionTitle"
+              target="_blank"
+              :title="record.fusionTitle"
+              :href="`/code/index.html?caseId=${record.fusionId}#/show`"
+              >{{ record.fusionTitle }}</a
+            >
+            <span v-else>-</span>
+          </template>
+          <template #action="{ record }">
+            <TableAction
+              stopButtonPropagation
+              :actions="[
+                {
+                  label: '迁移',
+                  ifShow: getTypeCheckPerm('diversity-move') && tableType == 0,
+                  onClick: handleMove.bind(null, record),
+                },
+                {
+                  label: '编辑',
+                  ifShow: getTypeCheckPerm('diversity-edit'),
+                  disabled: !record.editAuth,
+                  onClick: handlegotoEdit.bind(null, record),
+                },
+                {
+                  label: '权限',
+                  disabled: !record.isAuth,
+                  ifShow: getTypeCheckPerm('diversity-powers'),
+                  onClick: handlePowers.bind(null, record),
+                },
+                //{
+                //  label: '下载',
+                //  ifShow: getTypeCheckPerm('diversity-download') && !record.isOpen,
+                //  disabled:  tableType == 1,
+                //  onClick: createConfirmDownload.bind(null, record),
+                //},
+                {
+                  label: '删除',
+                  ifShow: getTypeCheckPerm('diversity-delete') && !record.isOpen && tableType == 0,
+                  disabled: !record.editAuth,
+                  color: 'error',
+                  onClick: handleDelete.bind(null, record),
+                },
+              ]"
+            />
+          </template>
+        </BasicTable>
+      </div>
+      <DownLoadModal
+        :downloadOption="downloadOption"
+        @cancel="afterClose"
+        @register="registerDownModal"
+        @update="reload"
+        cancelText="取消下载"
+        okText="下载"
+        @cancelDownload="cancelDownload"
+        :okButtonProps="{ disabled: canDownload }"
+      />
+      <MoveModal @register="registerMoveModal" @update="reload" />
+      <AddModal @register="registerAddModal" @update="reload" />
+      <PowersModal @register="registerPowersModal" />
+    </PageWrapper>
+  </div>
+</template>
+<script lang="ts">
+  import { defineComponent, h, computed, ref, onMounted } from 'vue';
+  import {
+    BasicTable,
+    useTable,
+    TableAction,
+    BasicColumn,
+    FormProps,
+  } from '/@/components/Table';
+  import { PageWrapper } from '/@/components/Page';
+  import AddModal from './addCaseModal.vue'
+  import DownLoadModal from './DownLoadModal.vue';
+  import MoveModal from './MoveModal.vue';
+  import PowersModal from '/@/views/productOperation/modal/PowersModal.vue';
+  import { Time } from '/@/components/Time';
+  import { Descriptions, Tabs } from 'ant-design-vue';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { useModal } from '/@/components/Modal';
+  import {
+    caseFusionList,
+    caseFusionAdd,
+    caseFusionDel,
+  } from '/@/api/operate/case';
+  import { message } from 'ant-design-vue';
+  import { usePermissionStore } from '/@/store/modules/permission';
+  import { useUserStore } from '/@/store/modules/user';
+  export default defineComponent({
+    components: {
+      DownLoadModal,
+      MoveModal,
+      PowersModal,
+      BasicTable,
+      TableAction,
+      PageWrapper,
+      [Descriptions.name]: Descriptions,
+      [Descriptions.Item.name]: Descriptions.Item,
+      AddModal,
+      // Tabs,
+      [Tabs.name]: Tabs,
+      // [Tabs.TabPane?.name]: Tabs.TabPane,
+    },
+    setup() {
+      const { t } = useI18n();
+      const { createMessage, createConfirm } = useMessage();
+      const userStore = useUserStore();
+      const userInfo = computed(() => userStore.getUserInfo);
+      const permissionStore = usePermissionStore();
+      const { getCheckPerm } = permissionStore;
+      const loading = ref(false);
+      const tableType = ref<number>(0); //0看看 、1看见、2深时
+      const columns = () => [
+        {
+          title: '标题',
+          dataIndex: 'sceneName',
+          fixed: 'left',
+          ellipsis: true,
+          slots: { customRender: 'href' },
+          // resizable: true,
+          width: 300,
+        },
+        // {
+        //   title: '所属案件',
+        //   dataIndex: 'caseTitle',
+        //   slots: { customRender: 'caseTitle' },
+        //   ellipsis: true,
+        //   width: 140,
+        // },
+        {
+          title: '人员编号',
+          dataIndex: 'ryNo',
+          ellipsis: true,
+          width: 140,
+        },
+        {
+          title: '姓名',
+          dataIndex: 'ryNickName',
+          ellipsis: true,
+          width: 140,
+        },
+        {
+          title: '创建时间',
+          dataIndex: 'createTime',
+          width: 150,
+          customRender: ({ record }) => {
+            return (
+              record.createTime &&
+              h(Time, {
+                value: record.createTime,
+                mode: 'datetime',
+              })
+            );
+          },
+        },
+        {
+          title: '操作',
+          dataIndex: 'action',
+          slots: { customRender: 'action' },
+          ifShow: true,
+          fixed: 'right',
+          flag: 'ACTION',
+          width: 230,
+        },
+      ];
+      const searchForm: Partial<FormProps> = {
+        labelWidth: 100,
+        autoSubmitOnEnter: true,
+        autoAdvancedLine: 1,
+        schemas: [
+          {
+            field: 'fusionTitle',
+            label: '多元融合名称',
+            component: 'Input',
+            componentProps: {
+              maxLength: 100,
+            },
+            colProps: {
+              xl: 7,
+              xxl: 7,
+            },
+          },
+        ],
+      };
+      function cancelDownload() {
+        downloadOption.value = {};
+      }
+      const [registerAddModal, { openModal: openAddModal }] = useModal();
+      const [registerDownModal, { openModal: openDownModal }] = useModal();
+      const [registerMoveModal, { openModal: openMoveModal }] = useModal();
+      const [registerPowersModal, { openModal: openPowersModal }] = useModal();
+      const [registerTable, { reload, setPagination, getColumns, setColumns }] = useTable({
+        api: caseFusionList,
+        title: `多元融合列表`,
+        // titleHelpMessage: ['已启用expandRowByClick', '已启用stopButtonPropagation'],
+        searchInfo: { isShare: tableType },
+        useSearchForm: true,
+        formConfig: searchForm,
+        showIndexColumn: false,
+        showTableSetting: true,
+        beforeFetch: (T) => {
+          loading.value = true;
+          return T;
+        },
+        afterFetch: (T) => {
+          loading.value = false;
+          return T;
+        },
+        rowKey: 'fusionId',
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'pageSize',
+          listField: 'list',
+          totalField: 'total',
+        },
+        canResize: true,
+      });
+      function changeTable(val: number) {
+        tableType.value = val;
+        setColumns(columns())
+        setPagination({ current: 1 });
+        reload();
+      }
+      async function handleAdd() {
+        console.log('addPowes', getColumns(), columns());
+        let res = await caseFusionAdd({});
+        console.log('handleAdd', res);
+        handlegotoEdit(res)
+      }
+      async function handleCopy(record: Recordable) {
+        createConfirm({
+          title: '复制场景',
+          content: '确定要复制场景吗?',
+          onOk: async () => {
+            sceneCopy({ num: record.num }).then(() => {
+              message.success({
+                content: '复制成功',
+              });
+              reload();
+            });
+          },
+        });
+      }
+      async function handleDelete(record: Recordable) {
+        createConfirm({
+          title: '删除',
+          content: '确定要删除吗?',
+          onOk: async () => {
+          caseFusionDel({ fusionId: record.fusionId }).then(() => {
+          message.success({
+            content: '删除成功',
+          });
+
+          reload();
+        });
+          },
+        });
+      }
+      async function handleMove(record: Recordable) {
+        openMoveModal(true, record);
+        // sceneMove({ snCode: record.snCode, num: record.num })
+        //   .then(() => {
+        //     message.success({
+        //       content: '迁移成功',
+        //     });
+        //   })
+        //   .catch(() => {
+        //     message.success({
+        //       content: '迁移失败',
+        //     });
+        //   });
+      }
+      let timer: null = ref(null);
+      const downloadOption = ref<Object>({});
+      const canDownload = ref<boolean>(true);
+      function createConfirmDownload(record: Recordable) {
+        createConfirm({
+          title: '提示',
+          okText: '继续',
+          content: '多元融合资源过大会导致离线包下载失败,请尽可能缩小多元融合资源后再下载。',
+          onOk: async () => {
+            handleDownload(record)
+          },
+        });
+      }
+
+      function handleDownload(record: Recordable) {
+        console.log('handleDownload', record, canDownload.value);
+        canDownload.value = true;
+        let isObj = tableType.value == 5 || tableType.value == 7 ? 1 : 0;
+        caseCheckDown({ caseId: record.caseId }).then((res) => {
+          console.log(res);
+          if (res.downloadStatus != 3) {
+            // 未下载过,需要打包
+            caseDown({ caseId: record.caseId }).then((res) => {
+              console.log(res);
+              openDownModal(true, {
+                ...record,
+              });
+              if (res.downloadStatus == 1) {
+                if (timer.value) {
+                  afterClose();
+                }
+                timer.value = setInterval(() => {
+                  caseProcess({ caseId: record.caseId, }).then((res) => {
+                    if (res.status == '1003') {
+                      createMessage.error('下载失败');
+                      afterClose();
+                      return;
+                    }
+                    if (res.percent >= 100) {
+                      canDownload.value = false;
+                      afterClose();
+                    }
+                    downloadOption.value = res;
+                    console.log(res);
+                  });
+                }, 1000);
+              }
+            });
+          } else {
+            canDownload.value = false;
+            window.open(res.downloadUrl);
+          }
+        });
+      }
+      async function handleGenerate(record: Recordable) {
+        console.log('record', record);
+        let data = await sceneDetail({ id: record.id });
+        console.log('data', data);
+        let { buildObjStatus } = data;
+        let toastText =
+          buildObjStatus == 2
+            ? 'Mesh场景正在计算中,请耐心等待'
+            : buildObjStatus == 1
+            ? '重新生成Mesh场景将覆盖现有场景信息,计算过程中Mesh场景无法打开,确定要重新生成吗?'
+            : '生成obj需要较长时间,请耐心等待';
+        // if (data.code === 200) {
+        createConfirm({
+          iconType: 'warning',
+          title: () => h('span', '生成 obj'),
+          content: () => h('span', toastText),
+          onOk: async () => {
+            if (buildObjStatus !== 2) {
+              await buildSceneObj({ id: record.id, sceneNum: record.num });
+            }
+            createMessage.success(t('common.optSuccess'));
+            reload();
+          },
+        });
+        // } else {
+        //   createMessage.error(t(`apiCode.errCode${data.code}`));
+        // }
+      }
+      function afterClose() {
+        clearInterval(timer.value);
+        timer.value = null;
+      }
+      function handleReset(record: Recordable) {
+        console.log('handleReset', record);
+        rebuildScene({ num: record.num }).then(() => {
+          message.success({
+            content: '操作成功',
+          });
+          reload();
+        });
+      }
+      function getTypeCheckPerm(val) {
+        let myType = tableType.value;
+        return getCheckPerm(val) || getCheckPerm(`${val}-${myType}`);
+      }
+      function handlegotoEdit(record) {
+        // window.open(`/mix3d/#/home/${record.caseId}`);
+        let url = `/code/index.html?caseId=${record.fusionId}#/fuseEdit/merge`;
+        window.open(url);
+      }
+      function handlePowers(record: Recordable) {
+        console.log('handlePowers', record);
+        openPowersModal(true, {
+          ...record,
+          sourceType: 'fusion',
+          caseId: undefined,
+          tableType: tableType.value,
+        });
+        setTimeout(() => {
+          setColumns(columns())
+        }, 2000)
+      }
+      onMounted(() => {
+        setColumns(columns())
+      });
+      return {
+        registerTable,
+        registerPowersModal,
+        handleDelete,
+        handleCopy,
+        handleMove,
+        handleDownload,
+        handleReset,
+        tableType,
+        loading,
+        changeTable,
+        t,
+        openDownModal,
+        registerDownModal,
+        registerMoveModal,
+        registerAddModal,
+        afterClose,
+        timer,
+        canDownload,
+        downloadOption,
+        cancelDownload,
+        handleGenerate,
+        getTypeCheckPerm,
+        handlegotoEdit,
+        handlePowers,
+        userInfo,
+        columnsFun: columns(),
+        handleAdd,
+        reload,
+        getCheckPerm,
+        createConfirmDownload,
+      };
+    },
+  });
+</script>
+<style lang="less" scoped>
+  .scren {
+    .noScene {
+      position: absolute;
+      top: calc(50% - 126px);
+      width: 100%;
+      text-align: center;
+      &-content {
+        font-size: 14px;
+        color: rgba(0, 0, 0, 0.85);
+        line-height: 22px;
+        font-style: normal;
+        text-transform: none;
+        .codelist {
+          margin-top: 36px;
+          width: 424px;
+          height: auto;
+          display: flex;
+          justify-content: space-between;
+          margin: 0 auto;
+          .codediv {
+            font-weight: 400;
+            font-size: 17px;
+            color: rgba(0, 0, 0, 0.85);
+            line-height: 22px;
+            height: auto;
+            padding: 24px;
+            background: #fff;
+            text-align: center;
+            .codetext {
+              margin-top: 10px;
+            }
+          }
+        }
+      }
+    }
+    :deep(.ant-table-cell-content){
+      display: block !important;
+    }
+  }
+  // .tableHeader {
+  //   height: 50px;
+  //   display: flex;
+  //   align-items: center;
+
+  //   .item {
+  //     font-size: 14px;
+  //     color: #666;
+  //     margin-right: 10px;
+  //     cursor: pointer;
+  //     &.active {
+  //       font-weight: bold;
+  //       color: #222;
+  //     }
+  //   }
+  // }
+  .desc-wrap-BasicTable {
+    background-color: #f0f2f5;
+    .vben-basic-table-form-container {
+      padding: 0;
+    }
+  }
+</style>

+ 78 - 0
src/views/draw/DownLoadModal.vue

@@ -0,0 +1,78 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    title="系统正在为您打包数据"
+    :minHeight="0"
+    @visible-change="handleVisibleChange"
+    @cancel="hundleCancel"
+    @ok="handleSubmit"
+  >
+    <div class="pt-2px pr-3px">
+      <div class="warp">
+        <p>正在打包场景离线数据{{ downloadPercent }}</p>
+        <span>{{ modelRef.sceneName }}.zip</span>
+        <Progress :percent="downloadOption.percent" />
+        <p>* 打包完成后将关闭弹窗自动下载。</p>
+      </div>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, nextTick, onMounted, reactive } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { Progress } from 'ant-design-vue';
+  const { t } = useI18n();
+
+  export default defineComponent({
+    components: { BasicModal, Progress },
+    props: {
+      userData: { type: Object },
+      downloadOption: { type: Object },
+    },
+    emits: ['update', 'register', 'cancelDownload'],
+    setup(props, { emit }) {
+      const modelRef = ref({});
+
+      const { createMessage } = useMessage();
+
+      onMounted(() => {});
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner((data) => {
+        // data && onDataReceive(data);
+        modelRef.value = data;
+      });
+
+      const handleSubmit = async () => {
+        console.log(props.downloadOption);
+        if (props.downloadOption.url) {
+          window.open(props.downloadOption.url);
+        }
+      };
+      const hundleCancel = async () => {
+        emit('cancelDownload');
+      };
+
+      return {
+        register,
+        modelRef,
+        handleSubmit,
+        hundleCancel,
+        addListFunc,
+        t,
+      };
+    },
+  });
+</script>
+<style lang="less" scoped>
+  .pt-2px {
+  }
+  .warp {
+    display: flex;
+    align-items: flex-start;
+    justify-content: flex-start;
+    flex-flow: column;
+  }
+</style>

+ 303 - 0
src/views/draw/addCaseModal.vue

@@ -0,0 +1,303 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    title="新增案件"
+    @visible-change="handleVisibleChange"
+    @ok="handleSubmit"
+    :confirmLoading="loading"
+    :width="900"
+    :min-height="0"
+  >
+    <div class="pt-2px pr-3px">
+      <div class="mx-5 BasicForm flex">
+        <span style="line-height: 32px; margin-right: 10px">案件名称</span>
+        <div class="input">
+          <a-input style="width: 600px" maxlength="100" showCount v-model:value="fileFlow.caseTitle" placeholder="请输入" />
+        </div>
+        <!-- <a-button type="primary" @click="handleAdd"> 新增</a-button> -->
+      </div>
+      <BasicTable @register="registerTable">
+        <template #href="{ record }">
+          <a
+            v-if="record.status == 1 || (record.status == -2 && record.payStatus == 1)"
+            target="_blank"
+            :title="record.sceneName"
+            :href="record.webSite"
+            >{{ record.sceneName }}</a
+          >
+          <span v-else-if="record.sceneName">{{ record.sceneName }}</span>
+          <span v-else>-</span>
+        </template>
+      </BasicTable>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, nextTick, onMounted, reactive, h } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { sceneMove } from '/@/api/operate';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { getByKey, addOrUpdate, del } from '/@/api/media';
+  import {
+    BasicTable,
+    useTable,
+    TableAction,
+    BasicColumn,
+    TableImg,
+    FormProps,
+  } from '/@/components/Table';
+  import { caseaddOrUpdateApi, operateSceneList } from '/@/api/operate';
+  const { t } = useI18n();
+  export default defineComponent({
+    components: { BasicModal, BasicTable, TableAction },
+    props: {
+      userData: { type: Object },
+    },
+    emits: ['update', 'register'],
+    setup(props, { emit }) {
+      const modelRef = ref({});
+      const loading = ref(false);
+      const fileFlow = reactive({
+        caseTitle: '',
+        file: null,
+        dylist: [],
+        mslist: [],
+      });
+      const columns: BasicColumn[] = [
+        {
+          title: '场景标题',
+          dataIndex: 'sceneName',
+          ellipsis: true,
+          slots: { customRender: 'href' },
+          resizable: true,
+          minWidth: 150,
+          width: 150,
+        },
+        {
+          title: '场景码',
+          dataIndex: 'num',
+          ellipsis: true,
+          width: 180,
+        },
+        {
+          title: '计算完成时间',
+          dataIndex: 'algorithmTime',
+          width: 180,
+        },
+        {
+          title: '场景大小',
+          dataIndex: 'sceneSize',
+          width: 80,
+          customRender: ({ record }) => {
+            return record.sceneSize && record.sceneSize != 0
+              ? h('span', { class: 'sceneSize' }, Math.ceil(record.sceneSize / 1024 / 1024) + 'M')
+              : '-';
+          },
+        },
+        {
+          title: '状态',
+          dataIndex: 'status',
+          width: 80,
+          customRender: ({ record }) => {
+            let str;
+            switch (record.status - 0) {
+              case 0:
+                str = '计算中';
+                break;
+              case 1:
+                str = '计算成功';
+                break;
+              case -2:
+                str = '计算成功';
+                break;
+              case -1:
+                str = '计算失败';
+                break;
+            }
+            return record.payStatus == -2 ? '封存' : str;
+          },
+        },
+      ];
+      const searchForm: Partial<FormProps> = {
+        labelWidth: 60,
+        autoSubmitOnEnter: true,
+        autoAdvancedLine: 1,
+        schemas: [
+          {
+            field: 'sceneName',
+            label: '名称',
+            component: 'Input',
+            componentProps: {
+              maxLength: 100,
+              placeholder: ' 请名称搜索',
+            },
+            colProps: {
+              xl: 7,
+              xxl: 7,
+            },
+          },
+          // {
+          //   field: 'isObj',
+          //   label: '场景类型',
+          //   component: 'Select',
+          //   labelWidth: 80,
+          //   // labelWidth: 50,
+          //   defaultValue: '1',
+          //   componentProps: {
+          //     allowClear: false,
+          //     options: [
+          //       {
+          //         label: '点云场景',
+          //         value: '0',
+          //         key: '0',
+          //       },
+          //       {
+          //         label: 'Mesh 场景',
+          //         value: '1',
+          //         key: '1',
+          //       },
+          //     ],
+          //     onChange: (value) => {
+          //       reload({
+          //         searchInfo: { isObj: value },
+          //       }).then(() => {
+          //         setSelectedRowKeys(value == 0 ? fileFlow.dylist : fileFlow.mslist);
+          //       });
+          //     },
+          //   },
+          //   colProps: {
+          //     xl: 7,
+          //     xxl: 7,
+          //   },
+          // },
+        ],
+      };
+      const { createMessage, createConfirm } = useMessage();
+      const [registerTable, { reload, getForm, setSelectedRowKeys }] = useTable({
+        api: operateSceneList,
+        title: ``,
+        showTableSetting: false,
+        rowSelection: { type: 'checkbox',getCheckboxProps: getRowSelection, onChange: onSelectChange },
+        // titleHelpMessage: ['已启用expandRowByClick', '已启用stopButtonPropagation'],
+        columns: columns,
+        searchInfo: { isObj: '1' },
+        useSearchForm: true,
+        formConfig: searchForm,
+        showIndexColumn: false,
+        rowKey: 'num',
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'pageSize',
+          listField: 'list',
+          totalField: 'total',
+        },
+        canResize: true,
+      });
+      onMounted(() => {});
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner((data) => {
+        console.log(data);
+        getForm().resetFields();
+        reload()
+        data && onDataReceive(data);
+      });
+      function getRowSelection(record) {
+        return {
+        disabled: record.inCase || !(record.status == 1 || record.status == -2), // Column configuration not to be checked
+        name: record.name,}
+       }
+      function onSelectChange(selectedRowKeys: any, selectedRows: any) {
+        fileFlow.dylist = [];
+        fileFlow.mslist = selectedRowKeys;
+      }
+      function onDataReceive(data) {
+        fileFlow.caseTitle = '';
+        modelRef.value = data;
+        fileFlow.dylist = [];
+        fileFlow.mslist = [];
+        fileFlow.caseTitle = '';
+        setSelectedRowKeys([]);
+      }
+      function handleAdd() {
+        console.log('handleAdd', fileFlow.dictName);
+        let params = {
+          dictName: fileFlow.dictName.trim(),
+        };
+        if (!fileFlow.dictName.trim()) {
+          return createMessage.warning('请输入名称');
+        }
+        addOrUpdate(params).then((res) => {
+          createMessage.success('添加成功');
+          fileFlow.dictName = '';
+          reload();
+        });
+      }
+      const handleSubmit = async () => {
+        if(!fileFlow.caseTitle?.trim()){
+          return createMessage.warning('请输入案件名称')
+        }
+        try {
+          loading.value = true;
+          const apiData = {
+            caseTitle: fileFlow.caseTitle?.trim(),
+            sceneNumParam: [
+              {
+                type: 0,
+                numList: fileFlow.dylist,
+              },
+              {
+                type: 1,
+                numList: fileFlow.mslist,
+              },
+            ],
+          };
+          console.log('res', apiData);
+          const res = await caseaddOrUpdateApi(apiData);
+          console.log('res', res);
+          closeModal();
+          createMessage.success('新增案件成功。');
+          emit('update');
+          loading.value = false;
+        } catch (error) {
+          loading.value = false;
+          console.log('not passing', error);
+        }
+      };
+      function handleVisibleChange(v) {
+        // console.log(v);
+        // v && props.userData && nextTick(() => onDataReceive(props.userData));
+      }
+      async function handleDelete(record: Recordable) {
+        console.log('handleDelete', record);
+        createConfirm({
+          title: '删除',
+          content: '确定要删除吗?',
+          onOk: async () => {
+            del({ id: record.id }).then(() => {
+              createMessage.success({
+                content: '删除成功',
+              });
+              reload();
+            });
+          },
+        });
+      }
+      return {
+        register,
+        handleAdd,
+        registerTable,
+        model: modelRef,
+        fileFlow,
+        handleVisibleChange,
+        handleSubmit,
+        addListFunc,
+        handleDelete,
+        t,
+        loading,
+      };
+    },
+  });
+</script>

+ 603 - 0
src/views/draw/list.vue

@@ -0,0 +1,603 @@
+<template>
+  <div class="scren">
+    <PageWrapper contentBackground>
+      <template #footer>
+        <a-tabs v-model:activeKey="tableType" @change="changeTable">
+          <Tabs.TabPane :key="0" tab="方位图" :disabled="loading" />
+          <Tabs.TabPane :key="1" tab="平面图" :disabled="loading" /> </a-tabs
+      ></template>
+      <div class="desc-wrap-BasicTable">
+        <BasicTable v-show="tableType" @register="registerTable">
+          <template #toolbar>
+            <a-button
+              type="primary"
+              v-if="getTypeCheckPerm('overview-add')"
+              @click="handleAdd('overview')"
+            >
+              新增</a-button
+            >
+          </template>
+
+          <template #href="{ record }">
+            <!-- <a
+              v-if="!!record.listCover || record.mapUrl"
+              target="_blank"
+              :title="record.title"
+              :href="!!record.listCover || record.mapUrl"
+              >{{ record.title || '-' }}</a
+            > -->
+            <span>{{ record.title || '-' }}</span>
+          </template>
+          <template #action="{ record }">
+            <TableAction
+              stopButtonPropagation
+              :actions="[
+                {
+                  label: '复制',
+                  ifShow: getTypeCheckPerm('overview-copy') && !!record.listCover,
+                  onClick: handleCopy.bind(null, record),
+                },
+                {
+                  label: '重命名',
+                  ifShow: getTypeCheckPerm('overview-rename') && !!record.listCover,
+                  onClick: handlegoRename.bind(null, record),
+                },
+                {
+                  label: '编辑',
+                  ifShow: getTypeCheckPerm('overview-edit'),
+                  onClick: handlegotoEdit.bind(null, record),
+                },
+                {
+                  label: '下载',
+                  ifShow: getTypeCheckPerm('overview-download') && !!record.listCover,
+                  onClick: createConfirmDownload.bind(null, record),
+                },
+                {
+                  label: '删除',
+                  ifShow: getTypeCheckPerm('overview-delete'),
+                  color: 'error',
+                  onClick: handleDelete.bind(null, record),
+                },
+              ]"
+            />
+          </template>
+        </BasicTable>
+        <BasicTable v-show="!tableType" @register="registerTable1">
+          <template #toolbar>
+            <a-button
+              type="primary"
+              v-if="getTypeCheckPerm('tabulation-add')"
+              @click="handleAdd('tabulation')"
+            >
+              新增</a-button
+            >
+          </template>
+
+          <template #href="{ record }">
+            <!-- <a
+              v-if="!!record.listCover || record.mapUrl"
+              target="_blank"
+              :title="record.title"
+              :href="!!record.listCover || record.mapUrl"
+              >{{ record.title || '-' }}</a
+            > -->
+            <span>{{ record.title || '-' }}</span>
+          </template>
+          <template #action="{ record }">
+            <TableAction
+              stopButtonPropagation
+              :actions="[
+                {
+                  label: '复制',
+                  ifShow: getTypeCheckPerm('tabulation-copy') && !!record.listCover,
+
+                  onClick: handleCopy.bind(null, record),
+                },
+                {
+                  label: '重命名',
+                  ifShow: getTypeCheckPerm('tabulation-rename') && !!record.listCover,
+                  onClick: handlegoRename.bind(null, record),
+                },
+                {
+                  label: '编辑',
+                  ifShow: getTypeCheckPerm('tabulation-edit'),
+                  onClick: handlegotoEdit.bind(null, record),
+                },
+                {
+                  label: '下载',
+                  ifShow: getTypeCheckPerm('tabulation-download') && !!record.listCover,
+                  onClick: createConfirmDownload.bind(null, record),
+                },
+                {
+                  label: '删除',
+                  ifShow: getTypeCheckPerm('tabulation-delete'),
+                  color: 'error',
+                  onClick: handleDelete.bind(null, record),
+                },
+              ]"
+            />
+          </template>
+        </BasicTable>
+      </div>
+      <DownLoadModal
+        :downloadOption="downloadOption"
+        @cancel="afterClose"
+        @register="registerDownModal"
+        @update="reload"
+        cancelText="取消下载"
+        okText="下载"
+        @cancelDownload="cancelDownload"
+        :okButtonProps="{ disabled: canDownload }"
+      />
+      <MoveModal @register="registerMoveModal" />
+      <AddModal @register="registerAddModal" @update="reload" />
+      <AddRenameModal :tableType="tableType" @register="registerRenameModal" @update="reload" />
+      <PowersModal @register="registerPowersModal" />
+    </PageWrapper>
+  </div>
+</template>
+<script lang="ts">
+  import { defineComponent, h, computed, ref, onMounted } from 'vue';
+  import { BasicTable, useTable, TableAction, BasicColumn, FormProps } from '/@/components/Table';
+  import { PageWrapper } from '/@/components/Page';
+  import AddModal from './addCaseModal.vue';
+  import AddRenameModal from './reName.vue';
+  import DownLoadModal from './DownLoadModal.vue';
+  import MoveModal from '/@/views/productOperation/modal/MoveModal.vue';
+  import PowersModal from '/@/views/productOperation/modal/PowersModal.vue';
+  import { Time } from '/@/components/Time';
+  import { Descriptions, Tabs } from 'ant-design-vue';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { downloadByUrl } from '/@/utils/file/download';
+  import { useModal } from '/@/components/Modal';
+  import {
+    caseOverviewList,
+    caseOverviewDel,
+    caseTabulationList,
+    caseTabulationCopy,
+    caseOverviewCopy,
+    caseTabulationDel,
+  } from '/@/api/operate/case';
+  import { caseOverviewAdd, caseTabulationAdd } from '/@/api/operate/draw.ts';
+  import { message } from 'ant-design-vue';
+  import { usePermissionStore } from '/@/store/modules/permission';
+  import { useUserStore } from '/@/store/modules/user';
+  export default defineComponent({
+    components: {
+      DownLoadModal,
+      MoveModal,
+      PowersModal,
+      BasicTable,
+      TableAction,
+      PageWrapper,
+      [Descriptions.name]: Descriptions,
+      [Descriptions.Item.name]: Descriptions.Item,
+      AddModal,
+      AddRenameModal,
+      // Tabs,
+      [Tabs.name]: Tabs,
+      // [Tabs.TabPane?.name]: Tabs.TabPane,
+    },
+    setup() {
+      const { t } = useI18n();
+      const { createMessage, createConfirm } = useMessage();
+      const userStore = useUserStore();
+      const userInfo = computed(() => userStore.getUserInfo);
+      const permissionStore = usePermissionStore();
+      const { getCheckPerm } = permissionStore;
+      const loading = ref(false);
+      const tableType = ref<number>(0); //0看看 、1看见、2深时
+      const columns: BasicColumn[] = [
+        {
+          title: '标题',
+          dataIndex: 'title',
+          ellipsis: true,
+          resizable: true,
+          minWidth: 150,
+          width: 300,
+        },
+        {
+          title: '来源',
+          dataIndex: 'resource',
+          ellipsis: true,
+          width: 100,
+          customRender: ({ record }) => {
+            return record.isCopy ? '复制' : record.resource || '-';
+          },
+        },
+        {
+          title: '创建时间',
+          dataIndex: 'createTime',
+          width: 230,
+          customRender: ({ record }) => {
+            return (
+              record.createTime &&
+              h(Time, {
+                value: record.createTime,
+                mode: 'datetime',
+              })
+            );
+          },
+        },
+        {
+          title: '操作',
+          dataIndex: 'action',
+          slots: { customRender: 'action' },
+          ifShow: true,
+          fixed: 'right',
+          flag: 'ACTION',
+          width: 250,
+        },
+      ];
+      const searchForm: Partial<FormProps> = {
+        labelWidth: 100,
+        autoSubmitOnEnter: true,
+        autoAdvancedLine: 1,
+        schemas: [
+          {
+            field: 'title',
+            label: '名称',
+            component: 'Input',
+            componentProps: {
+              maxLength: 100,
+            },
+            colProps: {
+              xl: 7,
+              xxl: 7,
+            },
+          },
+        ],
+      };
+      function cancelDownload() {
+        downloadOption.value = {};
+      }
+      const [registerAddModal, { openModal: openAddModal }] = useModal();
+      const [registerDownModal, { openModal: openDownModal }] = useModal();
+      const [registerMoveModal, { openModal: openMoveModal }] = useModal();
+      const [registerRenameModal, { openModal: openRenameModal }] = useModal();
+      const [registerPowersModal, { openModal: openPowersModal }] = useModal();
+      const [registerTable, { reload: reload1 }] = useTable({
+        api: caseOverviewList,
+        title: ``,
+        // titleHelpMessage: ['已启用expandRowByClick', '已启用stopButtonPropagation'],
+        columns: columns,
+        searchInfo: { isShare: tableType },
+        useSearchForm: true,
+        formConfig: searchForm,
+        showIndexColumn: false,
+        showTableSetting: true,
+        beforeFetch: (T) => {
+          loading.value = true;
+          return T;
+        },
+        afterFetch: (T) => {
+          loading.value = false;
+          return T;
+        },
+        rowKey: 'id',
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'pageSize',
+          listField: 'list',
+          totalField: 'total',
+        },
+        canResize: true,
+      });
+      const [registerTable1, { reload: reload2 }] = useTable({
+        api: caseTabulationList,
+        title: ``,
+        // titleHelpMessage: ['已启用expandRowByClick', '已启用stopButtonPropagation'],
+        columns: columns,
+        searchInfo: { isShare: tableType },
+        useSearchForm: true,
+        formConfig: searchForm,
+        showIndexColumn: false,
+        showTableSetting: true,
+        beforeFetch: (T) => {
+          loading.value = true;
+          return T;
+        },
+        afterFetch: (T) => {
+          loading.value = false;
+          return T;
+        },
+        rowKey: 'id',
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'pageSize',
+          listField: 'list',
+          totalField: 'total',
+        },
+        canResize: true,
+      });
+      function changeTable(val: number) {
+        tableType.value = val;
+        reload();
+      }
+      function handlegoRename(record) {
+        openRenameModal(
+          true,
+          tableType.value
+            ? { overviewId: record.id, newTitle: record.title }
+            : { tabulationId: record.id, newTitle: record.title },
+        );
+
+        // createPrompt({
+        //   title: '请输入邮箱',
+        //   required: true,
+        //   label: '邮箱',
+        //   defaultValue: '默认邮箱',
+        //   onOK: async (email: string) => {
+        //     message.success('填写的邮箱地址为' + email);
+        //   },
+        //   inputType: 'Input',
+        // });
+      }
+
+      async function handleAdd(type) {
+        // openAddModal(true, {});
+        if (type == 'overview') {
+          let record = await caseOverviewAdd({ type: 0 });
+          // handlegotoEdit(record);
+          // window.open(`/draw/#/overview`);
+          // window.open(`/draw/#/overview?caseId=${caseId.value}`);
+        } else {
+          // window.open(`/draw/#/tabulation?caseId=${caseId.value}&tabulationId=${res.id}`);
+          let record = await caseTabulationAdd({ type: 1 });
+          // handlegotoEdit(record);
+          // window.open(`/draw/#/tabulation`);
+        }
+        reload();
+        // router.push({ path: '/scene/add' });
+      }
+      function reload() {
+        reload1();
+        reload2();
+      }
+
+      async function handleCopy(record: Recordable) {
+        let url = tableType.value == 1 ? caseOverviewCopy : caseTabulationCopy;
+        let param =
+          tableType.value == 1
+            ? { overviewIds: [record.id], isCopy: 1 }
+            : {
+                tabulationIds: [record.id],
+                isCopy: 1,
+              };
+        createConfirm({
+          title: '复制',
+          content: '确定要复制吗?',
+          onOk: async () => {
+            url(param).then(() => {
+              message.success({
+                content: '复制成功',
+              });
+              reload();
+            });
+          },
+        });
+      }
+      async function handleDelete(record: Recordable) {
+        let url = tableType.value == 1 ? caseOverviewDel : caseTabulationDel;
+        let param =
+          tableType.value == 1
+            ? { overviewId: record.id }
+            : {
+                tabulationId: record.id,
+              };
+        createConfirm({
+          title: '删除',
+          content: '确定要删除吗?',
+          onOk: async () => {
+            url(param).then(() => {
+              message.success({
+                content: '删除成功',
+              });
+
+              reload();
+            });
+          },
+        });
+      }
+      async function handleMove(record: Recordable) {
+        openMoveModal(true, {
+          ...record,
+        });
+        // sceneMove({ snCode: record.snCode, num: record.num })
+        //   .then(() => {
+        //     message.success({
+        //       content: '迁移成功',
+        //     });
+        //   })
+        //   .catch(() => {
+        //     message.success({
+        //       content: '迁移失败',
+        //     });
+        //   });
+      }
+      let timer: null = ref(null);
+      const downloadOption = ref<Object>({});
+      const canDownload = ref<boolean>(true);
+      function createConfirmDownload(record: Recordable) {
+        handleDownload(record);
+        // createConfirm({
+        //   title: '提示',
+        //   okText: '继续',
+        //   content: '是否确定下载。',
+        //   onOk: async () => {
+        //   },
+        // });
+      }
+
+      function handleDownload(record: Recordable) {
+        console.log('handleDownload', record, record.listCover || record.mapUrl);
+        downloadByUrl({
+          url: record.listCover || record.mapUrl,
+          target: '_blank',
+          fileName: record.title,
+        });
+      }
+      function getExtension(name) {
+        if (!name) return;
+        return name.substring(name.lastIndexOf('.'));
+      }
+      function handleEdit(record: Recordable) {
+        window.open(record.thumbEdit + '&&token=' + token.value);
+      }
+      async function handleGenerate(record: Recordable) {
+        console.log('record', record);
+        let data = await sceneDetail({ id: record.id });
+        console.log('data', data);
+        let { buildObjStatus } = data;
+        let toastText =
+          buildObjStatus == 2
+            ? 'Mesh场景正在计算中,请耐心等待'
+            : buildObjStatus == 1
+            ? '重新生成Mesh场景将覆盖现有场景信息,计算过程中Mesh场景无法打开,确定要重新生成吗?'
+            : '生成obj需要较长时间,请耐心等待';
+        // if (data.code === 200) {
+        createConfirm({
+          iconType: 'warning',
+          title: () => h('span', '生成 obj'),
+          content: () => h('span', toastText),
+          onOk: async () => {
+            if (buildObjStatus !== 2) {
+              await buildSceneObj({ id: record.id, sceneNum: record.num });
+            }
+            createMessage.success(t('common.optSuccess'));
+            reload();
+          },
+        });
+        // } else {
+        //   createMessage.error(t(`apiCode.errCode${data.code}`));
+        // }
+      }
+      function afterClose() {
+        clearInterval(timer.value);
+        timer.value = null;
+      }
+      function handleReset(record: Recordable) {
+        console.log('handleReset', record);
+        rebuildScene({ num: record.num }).then(() => {
+          message.success({
+            content: '操作成功',
+          });
+          reload();
+        });
+      }
+      function getTypeCheckPerm(val) {
+        let myType = tableType.value;
+        return getCheckPerm(val) || getCheckPerm(`${val}-${myType}`);
+      }
+      function handlegotoEdit(record) {
+        if (!tableType.value) {
+          window.open(`/draw/#/tabulation?tabulationId=${record.id}`);
+        } else {
+          window.open(`/draw/#/overview?overviewId=${record.id}`);
+        }
+      }
+      function handlePowers(record: Recordable) {
+        openPowersModal(true, {
+          ...record,
+          tableType: tableType.value,
+        });
+      }
+      onMounted(() => {});
+      return {
+        registerTable,
+        registerTable1,
+        registerPowersModal,
+        handleDelete,
+        handleCopy,
+        handleMove,
+        handleDownload,
+        handleReset,
+        tableType,
+        loading,
+        changeTable,
+        t,
+        openDownModal,
+        registerRenameModal,
+        registerDownModal,
+        registerMoveModal,
+        registerAddModal,
+        afterClose,
+        timer,
+        canDownload,
+        downloadOption,
+        cancelDownload,
+        handleGenerate,
+        getTypeCheckPerm,
+        handlegotoEdit,
+        handlePowers,
+        userInfo,
+        handleAdd,
+        reload,
+        getCheckPerm,
+        handlegoRename,
+        createConfirmDownload,
+      };
+    },
+  });
+</script>
+<style lang="less" scoped>
+  .scren {
+    .noScene {
+      position: absolute;
+      top: calc(50% - 126px);
+      width: 100%;
+      text-align: center;
+      &-content {
+        font-size: 14px;
+        color: rgba(0, 0, 0, 0.85);
+        line-height: 22px;
+        font-style: normal;
+        text-transform: none;
+        .codelist {
+          margin-top: 36px;
+          width: 424px;
+          height: auto;
+          display: flex;
+          justify-content: space-between;
+          margin: 0 auto;
+          .codediv {
+            font-weight: 400;
+            font-size: 17px;
+            color: rgba(0, 0, 0, 0.85);
+            line-height: 22px;
+            height: auto;
+            padding: 24px;
+            background: #fff;
+            text-align: center;
+            .codetext {
+              margin-top: 10px;
+            }
+          }
+        }
+      }
+    }
+  }
+  // .tableHeader {
+  //   height: 50px;
+  //   display: flex;
+  //   align-items: center;
+
+  //   .item {
+  //     font-size: 14px;
+  //     color: #666;
+  //     margin-right: 10px;
+  //     cursor: pointer;
+  //     &.active {
+  //       font-weight: bold;
+  //       color: #222;
+  //     }
+  //   }
+  // }
+  .desc-wrap-BasicTable {
+    background-color: #f0f2f5;
+    .vben-basic-table-form-container {
+      padding: 0;
+    }
+  }
+</style>

+ 125 - 0
src/views/draw/reName.vue

@@ -0,0 +1,125 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    title="重命名"
+    :okText="okText"
+    @visible-change="handleVisibleChange"
+    @cancel="resetFields"
+    :confirmLoading="loading"
+    min-height="50"
+    @ok="handleSubmit"
+  >
+    <div class="pt-2px pr-3px">
+      <BasicForm @register="registerForm">
+        <template #text="{ model, field }"> {{ model[field] }}{{ fileFlow.type }} </template>
+      </BasicForm>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, nextTick, onMounted, reactive, ref } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { InvoiceRegister } from '/@/api/order';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { uploadApi } from '/@/api/product/index';
+  import { ResultEnum } from '/@/enums/httpEnum';
+  import { caseOverviewRename, caseTabulationRename } from '/@/api/operate/case';
+  const { t } = useI18n();
+  export default defineComponent({
+    components: { BasicModal, BasicForm },
+    props: {
+      tableType: { type: Number, default: 0 },
+    },
+    emits: ['update', 'register'],
+    setup(props, { emit }) {
+      const fileFlow = reactive({
+        file: null,
+        type: 2, //2-普通发票,3-专用发票
+      });
+      const okText = ref('确定');
+      const loading = ref(false);
+      const { createMessage } = useMessage();
+      const schemas: FormSchema[] = [
+        {
+          field: 'overviewId',
+          component: 'Input',
+          show: false,
+          label: 'overviewId',
+        },
+        {
+          field: 'tabulationId',
+          component: 'Input',
+          show: false,
+          label: 'tabulationId',
+        },
+        {
+          field: 'newTitle',
+          component: 'Input',
+          label: '名称',
+          componentProps: {
+            maxlength: 100,
+            showCount: true,
+          },
+          required: true,
+          colProps: {
+            span: 22,
+          },
+        },
+      ];
+
+      const [registerForm, { validate, resetFields, setFieldsValue }] = useForm({
+        labelWidth: 120,
+        schemas: schemas,
+        showActionButtonGroup: false,
+        actionColOptions: {
+          span: 24,
+        },
+      });
+      onMounted(() => {});
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner((data) => {
+        data && onDataReceive(data);
+      });
+      function onDataReceive(data) {
+        resetFields();
+        setFieldsValue(data);
+      }
+      const handleSubmit = async () => {
+        loading.value = true;
+        try {
+          let url = props.tableType === 1 ? caseOverviewRename : caseTabulationRename;
+          const params = await validate();
+          const apiData = params;
+          console.log('res', apiData, params);
+          await url(apiData);
+          closeModal();
+          resetFields();
+          createMessage.success(t('common.optSuccess'));
+          emit('update');
+          loading.value = false;
+        } catch (error) {
+          loading.value = false;
+          console.log('not passing', error);
+        }
+      };
+      function handleVisibleChange(v) {
+        // v && props.userData && nextTick(() => onDataReceive(props.userData));
+      }
+      return {
+        register,
+        registerForm,
+        fileFlow,
+        handleVisibleChange,
+        handleSubmit,
+        addListFunc,
+        resetFields,
+        okText,
+        loading,
+        t,
+      };
+    },
+  });
+</script>

+ 9 - 0
src/views/mediaLibrary/list.vue

@@ -137,6 +137,11 @@
           width: 180,
         },
         {
+          title: '勘验号',
+          dataIndex: 'kno',
+          width: 80,
+        },
+        {
           title: '上传时间',
           dataIndex: 'createTime',
           width: 180,
@@ -224,6 +229,10 @@
               style: { maxWidth: '250px' },
               api: getByKey,
               immediate: false,
+              filterOption: (inputText: string, option) => {
+                return option?.label.indexOf(inputText) >= 0
+              },
+              showSearch: true,
               labelField: 'dictName',
               valueField: 'id',
               params: {

+ 1 - 1
src/views/mediaLibrary/modal/grouping.vue

@@ -18,7 +18,7 @@
       <BasicTable style="padding: 0" @register="registerTable">
         <template #action="{ record }">
           <TableAction
-            v-if="!record.isShare && record.useType != 'animation'"
+            v-if="!record.isShare && record.useType != 'animation' && record.useType != 'trace_evidence'"
             stopButtonPropagation
             :actions="[
               {

+ 4 - 0
src/views/mediaLibrary/modal/uploadModal.vue

@@ -108,6 +108,10 @@
             style: 'width: 350px',
             labelField: 'dictName',
             listHeight: 150,
+            filterOption: (inputText: string, option) => {
+              return option?.label.indexOf(inputText) >= 0
+            },
+            showSearch: true,
             valueField: 'id',
             params: {
               type: 1,

+ 78 - 0
src/views/planImg/DownLoadModal.vue

@@ -0,0 +1,78 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    title="系统正在为您打包数据"
+    :minHeight="0"
+    @visible-change="handleVisibleChange"
+    @cancel="hundleCancel"
+    @ok="handleSubmit"
+  >
+    <div class="pt-2px pr-3px">
+      <div class="warp">
+        <p>正在打包场景离线数据{{ downloadPercent }}</p>
+        <span>{{ modelRef.sceneName }}.zip</span>
+        <Progress :percent="downloadOption.percent" />
+        <p>* 打包完成后将关闭弹窗自动下载。</p>
+      </div>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, nextTick, onMounted, reactive } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { Progress } from 'ant-design-vue';
+  const { t } = useI18n();
+
+  export default defineComponent({
+    components: { BasicModal, Progress },
+    props: {
+      userData: { type: Object },
+      downloadOption: { type: Object },
+    },
+    emits: ['update', 'register', 'cancelDownload'],
+    setup(props, { emit }) {
+      const modelRef = ref({});
+
+      const { createMessage } = useMessage();
+
+      onMounted(() => {});
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner((data) => {
+        // data && onDataReceive(data);
+        modelRef.value = data;
+      });
+
+      const handleSubmit = async () => {
+        console.log(props.downloadOption);
+        if (props.downloadOption.url) {
+          window.open(props.downloadOption.url);
+        }
+      };
+      const hundleCancel = async () => {
+        emit('cancelDownload');
+      };
+
+      return {
+        register,
+        modelRef,
+        handleSubmit,
+        hundleCancel,
+        addListFunc,
+        t,
+      };
+    },
+  });
+</script>
+<style lang="less" scoped>
+  .pt-2px {
+  }
+  .warp {
+    display: flex;
+    align-items: flex-start;
+    justify-content: flex-start;
+    flex-flow: column;
+  }
+</style>

+ 157 - 0
src/views/planImg/addCaseModal.vue

@@ -0,0 +1,157 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    :title="title"
+    @visible-change="handleVisibleChange"
+    @ok="handleSubmit"
+    :confirmLoading="loading"
+    :width="420"
+    :min-height="0"
+  >
+    <div class="pt-2px pr-3px">
+      <div class="mx-5 BasicForm flex">
+        <div class="input">
+          <a-input
+            style="width: 350px"
+            maxlength="100"
+            showCount
+            allowClear
+            v-model:value="fileFlow.title"
+            placeholder="请输入"
+          />
+        </div>
+        <!-- <a-button type="primary" @click="handleAdd"> 新增</a-button> -->
+      </div>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, nextTick, onMounted, reactive, h } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { sceneMove } from '/@/api/operate';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { getByKey, addOrUpdate, del } from '/@/api/media';
+  import {
+    BasicTable,
+    useTable,
+    TableAction,
+    BasicColumn,
+    TableImg,
+    FormProps,
+  } from '/@/components/Table';
+  import { caseaddOrUpdateApi, operateSceneList } from '/@/api/operate';
+  const { t } = useI18n();
+  export default defineComponent({
+    components: { BasicModal, BasicTable, TableAction },
+    props: {
+      userData: { type: Object },
+    },
+    emits: ['update', 'register'],
+    setup(props, { emit }) {
+      const modelRef = ref({});
+      const loading = ref(false);
+      const title = ref('重命名');
+      const fileFlow = reactive({
+        title: '',
+        caseTitle: '',
+        file: null,
+        dylist: [],
+        mslist: [],
+      });
+      const { createMessage, createConfirm } = useMessage();
+      onMounted(() => {});
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner((data) => {
+        data && onDataReceive(data);
+      });
+      function onDataReceive(data) {
+        fileFlow.caseTitle = '';
+        title.value = data.caseTitle?'重命名':'名称';
+        modelRef.value = data;
+        fileFlow.dylist = [];
+        fileFlow.mslist = [];
+        fileFlow.title = data.caseTitle;
+        fileFlow.caseTitle = '';
+      }
+      function handleAdd() {
+        console.log('handleAdd', fileFlow.dictName);
+        let params = {
+          dictName: fileFlow.dictName.trim(),
+        };
+        if (!fileFlow.dictName.trim()) {
+          return createMessage.warning('请输入名称');
+        }
+        addOrUpdate(params).then((res) => {
+          createMessage.success('添加成功');
+          fileFlow.dictName = '';
+        });
+      }
+      const handleSubmit = async () => {
+        if (!fileFlow.caseTitle?.trim()) {
+          return createMessage.warning('请输入案件名称');
+        }
+        try {
+          loading.value = true;
+          const apiData = {
+            caseTitle: fileFlow.caseTitle?.trim(),
+            sceneNumParam: [
+              {
+                type: 0,
+                numList: fileFlow.dylist,
+              },
+              {
+                type: 1,
+                numList: fileFlow.mslist,
+              },
+            ],
+          };
+          console.log('res', apiData);
+          const res = await caseaddOrUpdateApi(apiData);
+          console.log('res', res);
+          closeModal();
+          createMessage.success('新增案件成功。');
+          emit('update');
+          loading.value = false;
+        } catch (error) {
+          loading.value = false;
+          console.log('not passing', error);
+        }
+      };
+      function handleVisibleChange(v) {
+        // console.log(v);
+        // v && props.userData && nextTick(() => onDataReceive(props.userData));
+      }
+      async function handleDelete(record: Recordable) {
+        console.log('handleDelete', record);
+        createConfirm({
+          title: '删除',
+          content: '确定要删除吗?',
+          onOk: async () => {
+            del({ id: record.id }).then(() => {
+              createMessage.success({
+                content: '删除成功',
+              });
+              reload();
+            });
+          },
+        });
+      }
+      return {
+        register,
+        handleAdd,
+        model: modelRef,
+        fileFlow,
+        handleVisibleChange,
+        handleSubmit,
+        addListFunc,
+        handleDelete,
+        t,
+        title,
+        loading,
+      };
+    },
+  });
+</script>

+ 511 - 0
src/views/planImg/list.vue

@@ -0,0 +1,511 @@
+<template>
+  <div class="scren">
+    <PageWrapper contentBackground>
+      <template #footer>
+        <a-tabs v-model:activeKey="tableType" @change="changeTable">
+          <Tabs.TabPane :key="0" tab="户型图" :disabled="loading" />
+          <Tabs.TabPane :key="1" tab="方位图" :disabled="loading" /> </a-tabs
+      ></template>
+      <div class="desc-wrap-BasicTable">
+        <BasicTable @register="registerTable">
+          <template #toolbar>
+            <a-button type="primary" @click="handleAdd"> 新增</a-button>
+          </template>
+
+          <template #href="{ record }">
+            <a
+              v-if="record.title"
+              target="_blank"
+              :title="record.title"
+              :href="`/code/index.html?caseId=${record.fusionId}#/show`"
+              >{{ record.title }}</a
+            >
+            <span v-else>-</span>
+          </template>
+          <template #action="{ record }">
+            <TableAction
+              stopButtonPropagation
+              :actions="[
+                {
+                  label: '重命名',
+                  ifShow: getTypeCheckPerm('case-powers'),
+                  onClick: handleRename.bind(null, record),
+                },
+                {
+                  label: '编辑',
+                  disabled: tableType == 1 && !record.isEdit,
+                  ifShow: getTypeCheckPerm('case-edit'),
+                  onClick: handlegotoEdit.bind(null, record),
+                },
+                {
+                  label: '下载',
+                  ifShow: getTypeCheckPerm('case-download') && !record.isOpen,
+                  disabled: tableType == 1,
+                  onClick: createConfirmDownload.bind(null, record),
+                },
+                {
+                  label: '删除',
+                  ifShow: getTypeCheckPerm('case-delete') && !record.isOpen,
+                  //icon: 'ic:outline-delete-outline',
+                  disabled: tableType == 1,
+                  color: 'error',
+                  onClick: handleDelete.bind(null, record),
+                },
+              ]"
+            />
+          </template>
+        </BasicTable>
+      </div>
+      <DownLoadModal
+        :downloadOption="downloadOption"
+        @cancel="afterClose"
+        @register="registerDownModal"
+        @update="reload"
+        cancelText="取消下载"
+        okText="下载"
+        @cancelDownload="cancelDownload"
+        :okButtonProps="{ disabled: canDownload }"
+      />
+      <MoveModal @register="registerMoveModal" />
+      <AddModal @register="registerAddModal" @update="reload" />
+      <PowersModal @register="registerPowersModal" />
+    </PageWrapper>
+  </div>
+</template>
+<script lang="ts">
+  import { defineComponent, h, computed, toRefs, ref, onMounted } from 'vue';
+  import Icon from '/@/components/Icon/index';
+  import dayjs from 'dayjs';
+  import { QrCode } from '/@/components/Qrcode/index';
+  import {
+    BasicTable,
+    useTable,
+    TableAction,
+    BasicColumn,
+    TableImg,
+    FormProps,
+  } from '/@/components/Table';
+  import { PageWrapper } from '/@/components/Page';
+  import AddModal from './addCaseModal.vue';
+  import DownLoadModal from './DownLoadModal.vue';
+  import MoveModal from '/@/views/productOperation/modal/MoveModal.vue';
+  import PowersModal from '/@/views/productOperation/modal/PowersModal.vue';
+  import { Time } from '/@/components/Time';
+  import { Descriptions, Tabs, Progress } from 'ant-design-vue';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { useModal } from '/@/components/Modal';
+  import {
+    caseCheckDown,
+    sceneCopy,
+    rebuildScene,
+    buildSceneObj,
+    sceneDetail,
+    caseDelApi,
+    caseListApi,
+    caseProcess,
+    caseDown,
+  } from '/@/api/operate';
+  import { caseOverImgList } from '/@/api/operate/draw';
+  import { message } from 'ant-design-vue';
+  import { usePermissionStore } from '/@/store/modules/permission';
+  import { useUserStore } from '/@/store/modules/user';
+  import { func } from 'vue-types';
+  export default defineComponent({
+    components: {
+      DownLoadModal,
+      MoveModal,
+      PowersModal,
+      BasicTable,
+      TableAction,
+      PageWrapper,
+      [Descriptions.name]: Descriptions,
+      [Descriptions.Item.name]: Descriptions.Item,
+      QrCode,
+      AddModal,
+      // Tabs,
+      [Tabs.name]: Tabs,
+      // [Tabs.TabPane?.name]: Tabs.TabPane,
+    },
+    setup() {
+      const { t } = useI18n();
+      const { createMessage, createConfirm } = useMessage();
+      const userStore = useUserStore();
+      const userInfo = computed(() => userStore.getUserInfo);
+      const permissionStore = usePermissionStore();
+      const { getCheckPerm } = permissionStore;
+      const loading = ref(false);
+      const tableType = ref<number>(0); //0看看 、1看见、2深时
+      const columns: BasicColumn[] = [
+        {
+          title: '标题',
+          dataIndex: 'sceneName',
+          ellipsis: true,
+          slots: { customRender: 'href' },
+          resizable: true,
+          minWidth: 150,
+          width: 300,
+        },
+        {
+          title: '来源',
+          dataIndex: 'resource',
+          ellipsis: true,
+          width: 100,
+        },
+        {
+          title: '创建时间',
+          dataIndex: 'createTime',
+          width: 230,
+          customRender: ({ record }) => {
+            return (
+              record.createTime &&
+              h(Time, {
+                value: record.createTime,
+                mode: 'datetime',
+              })
+            );
+          },
+        },
+        {
+          title: '操作',
+          dataIndex: 'action',
+          slots: { customRender: 'action' },
+          ifShow: true,
+          fixed: 'right',
+          flag: 'ACTION',
+          width: 200,
+        },
+      ];
+      const searchForm: Partial<FormProps> = {
+        labelWidth: 100,
+        autoSubmitOnEnter: true,
+        autoAdvancedLine: 1,
+        schemas: [
+          {
+            field: 'caseTitle',
+            label: '平面图名称',
+            component: 'Input',
+            componentProps: {
+              maxLength: 100,
+            },
+            colProps: {
+              xl: 7,
+              xxl: 7,
+            },
+          },
+          {
+            field: 'title',
+            label: '场景名称',
+            component: 'Input',
+            componentProps: {
+              maxLength: 100,
+            },
+            colProps: {
+              xl: 7,
+              xxl: 7,
+            },
+          },
+        ],
+      };
+      function cancelDownload() {
+        downloadOption.value = {};
+      }
+      const [registerAddModal, { openModal: openAddModal }] = useModal();
+      const [registerDownModal, { openModal: openDownModal }] = useModal();
+      const [registerMoveModal, { openModal: openMoveModal }] = useModal();
+      const [registerPowersModal, { openModal: openPowersModal }] = useModal();
+      const [registerTable, { reload, setColumns }] = useTable({
+        api: caseOverImgList,
+        title: ``,
+        // titleHelpMessage: ['已启用expandRowByClick', '已启用stopButtonPropagation'],
+        columns: columns,
+        searchInfo: { tableType: tableType },
+        useSearchForm: true,
+        formConfig: searchForm,
+        showIndexColumn: false,
+        showTableSetting: true,
+        beforeFetch: (T) => {
+          loading.value = true;
+          return T;
+        },
+        afterFetch: (T) => {
+          loading.value = false;
+          return T;
+        },
+        rowKey: 'caseId',
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'pageSize',
+          listField: 'list',
+          totalField: 'total',
+        },
+        canResize: true,
+      });
+      function changeTable(val: number) {
+        tableType.value = val;
+        reload();
+      }
+      function handleAdd() {
+        openAddModal(true, {
+          title: tableType.value == 0 ? '户型图' : '方位图',
+        });
+        // router.push({ path: '/scene/add' });
+      }
+      async function handleCopy(record: Recordable) {
+        createConfirm({
+          title: '复制场景',
+          content: '确定要复制场景吗?',
+          onOk: async () => {
+            sceneCopy({ num: record.num }).then(() => {
+              message.success({
+                content: '复制成功',
+              });
+              reload();
+            });
+          },
+        });
+      }
+      async function handleDelete(record: Recordable) {
+        createConfirm({
+          title: '删除',
+          content: '确定要删除吗?',
+          onOk: async () => {
+            caseDelApi({ caseId: record.caseId }).then(() => {
+              message.success({
+                content: '删除成功',
+              });
+
+              reload();
+            });
+          },
+        });
+      }
+      async function handleMove(record: Recordable) {
+        openMoveModal(true, {
+          ...record,
+        });
+        // sceneMove({ snCode: record.snCode, num: record.num })
+        //   .then(() => {
+        //     message.success({
+        //       content: '迁移成功',
+        //     });
+        //   })
+        //   .catch(() => {
+        //     message.success({
+        //       content: '迁移失败',
+        //     });
+        //   });
+      }
+      let timer: null = ref(null);
+      const downloadOption = ref<Object>({});
+      const canDownload = ref<boolean>(true);
+      function createConfirmDownload(record: Recordable) {
+        createConfirm({
+          title: '提示',
+          okText: '继续',
+          content: '案件资源过大会导致离线包下载失败,请尽可能缩小案件资源后再下载。',
+          onOk: async () => {
+            handleDownload(record);
+          },
+        });
+      }
+
+      function handleDownload(record: Recordable) {
+        console.log('handleDownload', record, canDownload.value);
+        canDownload.value = true;
+        let isObj = tableType.value == 5 || tableType.value == 7 ? 1 : 0;
+        caseCheckDown({ caseId: record.caseId }).then((res) => {
+          console.log(res);
+          if (res.downloadStatus != 3) {
+            // 未下载过,需要打包
+            caseDown({ caseId: record.caseId }).then((res) => {
+              console.log(res);
+              openDownModal(true, {
+                ...record,
+              });
+              if (res.downloadStatus == 1) {
+                if (timer.value) {
+                  afterClose();
+                }
+                timer.value = setInterval(() => {
+                  caseProcess({ caseId: record.caseId }).then((res) => {
+                    if (res.status == '1003') {
+                      createMessage.error('下载失败');
+                      afterClose();
+                      return;
+                    }
+                    if (res.percent >= 100) {
+                      canDownload.value = false;
+                      afterClose();
+                    }
+                    downloadOption.value = res;
+                    console.log(res);
+                  });
+                }, 1000);
+              }
+            });
+          } else {
+            canDownload.value = false;
+            window.open(res.downloadUrl);
+          }
+        });
+      }
+      function handleEdit(record: Recordable) {
+        window.open(record.thumbEdit + '&&token=' + token.value);
+      }
+      async function handleGenerate(record: Recordable) {
+        console.log('record', record);
+        let data = await sceneDetail({ id: record.id });
+        console.log('data', data);
+        let { buildObjStatus } = data;
+        let toastText =
+          buildObjStatus == 2
+            ? 'Mesh场景正在计算中,请耐心等待'
+            : buildObjStatus == 1
+            ? '重新生成Mesh场景将覆盖现有场景信息,计算过程中Mesh场景无法打开,确定要重新生成吗?'
+            : '生成obj需要较长时间,请耐心等待';
+        // if (data.code === 200) {
+        createConfirm({
+          iconType: 'warning',
+          title: () => h('span', '生成 obj'),
+          content: () => h('span', toastText),
+          onOk: async () => {
+            if (buildObjStatus !== 2) {
+              await buildSceneObj({ id: record.id, sceneNum: record.num });
+            }
+            createMessage.success(t('common.optSuccess'));
+            reload();
+          },
+        });
+        // } else {
+        //   createMessage.error(t(`apiCode.errCode${data.code}`));
+        // }
+      }
+      function afterClose() {
+        clearInterval(timer.value);
+        timer.value = null;
+      }
+      function handleReset(record: Recordable) {
+        console.log('handleReset', record);
+        rebuildScene({ num: record.num }).then(() => {
+          message.success({
+            content: '操作成功',
+          });
+          reload();
+        });
+      }
+      function getTypeCheckPerm(val) {
+        let myType = tableType.value;
+        return getCheckPerm(val) || getCheckPerm(`${val}-${myType}`);
+      }
+      function handlegotoEdit(record) {
+        window.open(`/mix3d/#/home/${record.caseId}`);
+        // let url = record.webSite.replace('smg', 'epg');
+        // if (!record.editAuthTime || (record.editAuthTime && dayjs() < dayjs(record.editAuthTime))) {
+        //   window.open(url);
+        // } else {
+        //   createMessage.error('编辑权限已过期');
+        // }
+      }
+      function handleRename(record) {
+        openAddModal(true, record);
+        // openPowersModal(true, {
+        //   ...record,
+        //   tableType: tableType.value,
+        // });
+      }
+      onMounted(() => {});
+      return {
+        registerTable,
+        registerPowersModal,
+        handleDelete,
+        handleCopy,
+        handleMove,
+        handleDownload,
+        handleReset,
+        tableType,
+        loading,
+        changeTable,
+        t,
+        openDownModal,
+        registerDownModal,
+        registerMoveModal,
+        registerAddModal,
+        afterClose,
+        timer,
+        canDownload,
+        downloadOption,
+        cancelDownload,
+        handleGenerate,
+        getTypeCheckPerm,
+        handlegotoEdit,
+        handleRename,
+        userInfo,
+        handleAdd,
+        reload,
+        getCheckPerm,
+        createConfirmDownload,
+      };
+    },
+  });
+</script>
+<style lang="less" scoped>
+  .scren {
+    .noScene {
+      position: absolute;
+      top: calc(50% - 126px);
+      width: 100%;
+      text-align: center;
+      &-content {
+        font-size: 14px;
+        color: rgba(0, 0, 0, 0.85);
+        line-height: 22px;
+        font-style: normal;
+        text-transform: none;
+        .codelist {
+          margin-top: 36px;
+          width: 424px;
+          height: auto;
+          display: flex;
+          justify-content: space-between;
+          margin: 0 auto;
+          .codediv {
+            font-weight: 400;
+            font-size: 17px;
+            color: rgba(0, 0, 0, 0.85);
+            line-height: 22px;
+            height: auto;
+            padding: 24px;
+            background: #fff;
+            text-align: center;
+            .codetext {
+              margin-top: 10px;
+            }
+          }
+        }
+      }
+    }
+  }
+  // .tableHeader {
+  //   height: 50px;
+  //   display: flex;
+  //   align-items: center;
+
+  //   .item {
+  //     font-size: 14px;
+  //     color: #666;
+  //     margin-right: 10px;
+  //     cursor: pointer;
+  //     &.active {
+  //       font-weight: bold;
+  //       color: #222;
+  //     }
+  //   }
+  // }
+  .desc-wrap-BasicTable {
+    background-color: #f0f2f5;
+    .vben-basic-table-form-container {
+      padding: 0;
+    }
+  }
+</style>

+ 140 - 64
src/views/productOperation/cameraScene.vue

@@ -47,12 +47,13 @@
       <div class="desc-wrap-BasicTable">
         <BasicTable @register="registerTable">
           <template #toolbar>
+            <a-button type="primary" v-if="tableType == 0 && getCheckPerm('scenes-upload')" @click="handleUpload"> 上传</a-button>
             <!-- <a-button type="primary" @click="exportExcel"> 导出1</a-button> -->
           </template>
 
           <template #href="{ record }">
             <a
-              v-if="record.status == 1 || (record.status == -2 && record.payStatus == 1)"
+              v-if="record.status == 1 || record.status == 6 || (record.status == -2 && record.payStatus == 1)"
               target="_blank"
               :title="record.sceneName"
               :href="record.webSite"
@@ -89,7 +90,7 @@
                 {
                   label: '编辑',
                   disabled: !(record.status == 1 || record.status == -2),
-                  ifShow: getTypeCheckPerm('scenes-edit') && tableType != 3 && record.editAuth,
+                  ifShow: getTypeCheckPerm('scenes-edit') && record.editAuth,
                   onClick: handlegotoEdit.bind(null, record),
                 },
                 {
@@ -125,7 +126,7 @@
                 },
                 {
                   label: '重算',
-                  disabled: record.status == 0 || (record.status == -2 && record.payStatus != 1),
+                  disabled: record.status == 0 || record.status == 6 || (record.status == -2 && record.payStatus != 1),
                   ifShow:
                     getTypeCheckPerm('scenes-recalculate') &&
                     tableType != 1 &&
@@ -195,13 +196,15 @@
         @cancelDownload="cancelDownload"
         :okButtonProps="{ disabled: canDownload }"
       />
-      <MoveModal @register="registerMoveModal" />
-      <PowersModal @register="registerPowersModal" />
-      <caseListModal @register="registerCaseListModal" />
+      <MoveModal @register="registerMoveModal" @update="reload" />
+      <PowersModal @register="registerPowersModal" @update="reload" />
+      <uplodaModal @register="registerUplodaModal" @update="reload" />
+      <caseListModal @register="registerCaseListModal" @update="reload" />
     </PageWrapper>
   </div>
 </template>
 <script lang="ts">
+  import { jyPlatformlist, sceneGroupCount } from '/@/api/jyUserPlatform/index'; //roleLIstApi
   import { defineComponent, h, computed, toRefs, ref, onMounted } from 'vue';
   import Icon from '/@/components/Icon/index';
   import dayjs from 'dayjs';
@@ -214,16 +217,18 @@
     TableImg,
     FormProps,
   } from '/@/components/Table';
-  import { ExclamationCircleOutlined  } from '@ant-design/icons-vue';
+  import { ExclamationCircleOutlined, ToTopOutlined } from '@ant-design/icons-vue';
   import { PageWrapper } from '/@/components/Page';
   import DownLoadModal from './modal/DownLoadModal.vue';
   import MoveModal from './modal/MoveModal.vue';
+  import uplodaModal from './modal/uploadModal.vue';
   import PowersModal from './modal/PowersModal.vue';
   import caseListModal from './modal/caseListModal.vue';
   import { Time } from '/@/components/Time';
   import { Descriptions, Tabs, Progress, Tooltip } from 'ant-design-vue';
   import { useI18n } from '/@/hooks/web/useI18n';
   import { useMessage } from '/@/hooks/web/useMessage';
+  import { SCENE_TYPE } from '/@/settings/siteSetting';
   import { useModal } from '/@/components/Modal';
   import {
     operateSceneList,
@@ -252,8 +257,10 @@
       PowersModal,
       caseListModal,
       BasicTable,
+      uplodaModal,
       TableAction,
       PageWrapper,
+      ToTopOutlined,
       [Descriptions.name]: Descriptions,
       [Descriptions.Item.name]: Descriptions.Item,
       QrCode,
@@ -340,25 +347,34 @@
             let str;
             switch (record.type) {
               case 0:
-                str = '四维看看/Mesh';
+                str = SCENE_TYPE[1];
                 break;
               case 1:
-                str = '四维看见/Mesh';
+                str = SCENE_TYPE[0];
                 break;
               case 2:
-                str = '四维深时/点云';
+                str = SCENE_TYPE[2];
                 break;
               case 5:
-                str = '四维深时/Mesh';
+                str = SCENE_TYPE[4];
                 break;
               case 6:
-                str = '四维深光/点云';
+                str = SCENE_TYPE[3];
                 break;
               case 7:
-                str = '四维深光/Mesh';
+                str = SCENE_TYPE[3];
                 break;
               case 8:
-                str = '圆周率/Mesh';
+                str = SCENE_TYPE[4];
+                break;
+              case 9:
+                str = SCENE_TYPE[0];
+                break;
+              case 10:
+                str = SCENE_TYPE[2];
+                break;
+              case 11:
+                str = SCENE_TYPE[3];
                 break;
             }
             return str;
@@ -410,6 +426,20 @@
           },
         },
         {
+          title: '计算时长',
+          dataIndex: 'amountdf',
+          width: 180,
+          customRender: ({ record }) => {
+            let startBuildTime = record.startBuildTime;
+            if(!record.algorithmTime || !startBuildTime) return '-'
+            let seconds =  dayjs(record.algorithmTime).diff(dayjs(startBuildTime), 'seconds')
+            if(record.statusString == '计算中'){
+              seconds =  dayjs().diff(dayjs(startBuildTime), 'seconds')
+            }
+            return convertSeconds(seconds);
+          },
+        },
+        {
           title: 'SN码',
           dataIndex: 'snCode',
           defaultHidden: true,
@@ -480,53 +510,61 @@
           {
             field: 'type',
             label: '相机类型',
-            component: 'Select',
-            // defaultValue: '7',
+            component: 'ApiSelect',
             componentProps: {
-              // allowClear: false,
-              options: [
-                {
-                  label: '四维看看/Mesh',
-                  value: '0',
-                  key: '0',
-                },
-                {
-                  label: '四维看见/Mesh',
-                  value: '1',
-                  key: '1',
-                },
-                // {
-                //   label: '四维深时/点云',
-                //   value: '2',
-                //   key: '2',
-                // },
-                {
-                  label: '四维深时/Mesh',
-                  value: '5',
-                  key: '5',
-                },
-                // {
-                //   label: '四维深光/点云',
-                //   value: '6',
-                //   key: '6',
-                // },
-                {
-                  label: '四维深光/Mesh',
-                  value: '7',
-                  key: '7',
-                },
-                {
-                  label: '圆周率/Mesh',
-                  value: '8',
-                  key: '8',
-                },
-              ],
+              style: { maxWidth: '250px', placeholder: '全部' },
+              placeholder: '全部',
+              api: sceneGroupCount,
+              immediate: false,
+              resultField: 'list',
+              labelField: 'name',
+              valueField: 'id',
+              params: { type: 'camera' },
             },
             colProps: {
               xl: 6,
               xxl: 6,
             },
           },
+          // {
+          //   field: 'type',
+          //   label: '相机类型',
+          //   component: 'Select',
+          //   // defaultValue: '7',
+          //   componentProps: {
+          //     options: [
+          //       {
+          //         label: SCENE_TYPE[1],
+          //         value: '0',
+          //         key: '0',
+          //       },
+          //       {
+          //         label: SCENE_TYPE[0],
+          //         value: '1',
+          //         key: '1',
+          //       },
+          //       {
+          //         label: SCENE_TYPE[2],
+          //         value: '5',
+          //         key: '5',
+          //       },
+          //       {
+          //         label: SCENE_TYPE[3],
+          //         value: '7',
+          //         key: '7',
+          //       },
+          //       {
+          //         label: SCENE_TYPE[4],
+          //         value: '8',
+          //         key: '8',
+          //       },
+          //     ],
+          //   },
+          //   colProps: {
+          //     xl: 6,
+          //     xxl: 6,
+          //   },
+          // },
           {
             field: 'num',
             label: '场景码',
@@ -551,16 +589,39 @@
               xxl: 5,
             },
           },
+          {
+            field: 'platform',
+            label: '平台',
+            component: 'ApiSelect',
+            ifShow: false,
+            componentProps: {
+              style: { maxWidth: '250px', placeholder: '全部' },
+              placeholder: '全部',
+              api: sceneGroupCount,
+              immediate: false,
+              resultField: 'list',
+              labelField: 'name',
+              valueField: 'id',
+            },
+            colProps: {
+              xl: 18,
+              xxl: 18,
+            },
+          },
         ],
       };
       function cancelDownload() {
         downloadOption.value = {};
       }
+      function handleUpload(){
+        openUplodaModal(true, {});
+      }
       const [registerDownModal, { openModal: openDownModal, closeModal }] = useModal();
       const [registerMoveModal, { openModal: openMoveModal }] = useModal();
+      const [registerUplodaModal, { openModal: openUplodaModal }] = useModal();
       const [registerPowersModal, { openModal: openPowersModal }] = useModal();
       const [registerCaseListModal, { openModal: openCaseListModal }] = useModal();
-      const [registerTable, { reload }] = useTable({
+      const [registerTable, { reload, getForm }] = useTable({
         api: operateSceneList,
         title: `场景列表`,
         // titleHelpMessage: ['已启用expandRowByClick', '已启用stopButtonPropagation'],
@@ -589,6 +650,7 @@
       });
       function changeTable(val: string) {
         tableType.value = val;
+        getForm().updateSchema({ field: 'platform', ifShow: val == '1' });
         reload();
       }
       async function handleCopy(record: Recordable) {
@@ -621,6 +683,14 @@
         //   },
         // });
       }
+      function convertSeconds(seconds) {
+        if(seconds == 'NaN') return
+      var days =seconds>(3600*24)? Math.floor(seconds / (3600*24)):0;
+      var hours = seconds>3600?Math.floor((seconds % (3600*24)) / 3600):0;
+      var minutes = Math.floor((seconds % 3600) / 60);
+      var remainingSeconds = seconds % 60;
+      return  `${ days && (days + '天')||''} ${hours && (hours + '小时')||''} ${minutes ||'0'}分钟 ${remainingSeconds||'0'}秒`
+    }
       async function handleMove(record: Recordable) {
         openMoveModal(true, {
           ...record,
@@ -643,8 +713,9 @@
       function handleDownload(record: Recordable) {
         console.log('handleDownload', record, canDownload.value);
         canDownload.value = true;
-        let isObj = record.type == 5 || record.type == 7 ? 1 : 0;
-        let params = { num: record.num, isObj };
+        // todo: bug修复
+        // let isObj = record.type == 5 || record.type == 7 ? 1 : 0;
+        let params = { num: record.num, isObj: 1 };
         checkDownLoad(params).then(async (res) => {
           let sceneDownloadRes = res;
           if (res.downloadStatus != 3) {
@@ -754,17 +825,18 @@
         }
       }
       async function handlePowers(record: Recordable) {
-        let res = await getCaseByNum({ num: record.num });
-        if (res && res.length) {
-          openCaseListModal(true, {
-            list: res,
-          });
-        } else {
+        let res = await getCaseByNum({ num: record.num, authType: 0,  });
+        // if (res && res.length) {
+        //   openCaseListModal(true, {
+        //     list: res,
+        //   });
+        // } else {
           openPowersModal(true, {
             ...record,
+            sourceType: 'scene',
             tableType: tableType.value,
           });
-        }
+        // }
       }
       onMounted(async () => {
         let list = await sceneCount();
@@ -801,8 +873,10 @@
         openDownModal,
         registerDownModal,
         registerMoveModal,
+        registerUplodaModal,
         afterClose,
         timer,
+        reload,
         canDownload,
         downloadOption,
         cancelDownload,
@@ -814,6 +888,8 @@
         qrCodeUrl,
         getStatus,
         hanleDowm,
+        handleUpload,
+        getCheckPerm,
       };
     },
   });

+ 25 - 25
src/views/productOperation/modal/PowersModal.vue

@@ -2,20 +2,20 @@
   <BasicModal
     v-bind="$attrs"
     @register="register"
-    :title="caseId?'设置权限':'设置场景权限'"
+    :title="(caseId||fusionId)?'设置权限':'设置场景权限'"
     @cancel="resetFields"
     @ok="handleSubmit"
     :width="1100"
     :min-height="0"
   >
     <div class="pt-2px pr-3px">
-      <div style="margin-left: 17px">提示:若添加的用户已有部分场景权限,新的权限覆盖原有的权限。</div>
+      <div style="margin-left: 17px">提示:若添加的用户已有部分{{fusionId?'':'场景'}}权限,新的权限覆盖原有的权限。</div>
       <BasicForm @register="registerForm" :model="model">
         <template #text="{ model, field }">
           {{ model[field] }}
         </template>
       </BasicForm>
-      <BasicTable class="powesrTable" @register="registerTable">
+      <BasicTable class="powesrTable" ref="tableRef" @register="registerTables">
         <template #toolbar>
           <a-button type="primary" v-if="getCheckPerm('scenes-powers-add')" @click="addPowes">
             新增
@@ -75,15 +75,19 @@
     emits: ['update', 'register'],
     setup(props, { emit }) {
       const modelRef = ref({});
+      const tableRef = ref(null);
+
       const numRef = ref(null);
       const caseId = ref(null);
+      const fusionId = ref(null);
+      const sourceType = ref(null);
       const type = ref(0);
       const fileFlow = reactive({
         showList: true,
       });
       const [registerryNoModal, { openModal: openryNoModal }] = useModal();
       const [registerDetail, { openModal: openDetaileModal }] = useModal();
-      const columns: BasicColumn[] = [
+      const columnssss: BasicColumn[] = [
         {
           title: '警员ID',
           dataIndex: 'ryNo',
@@ -148,25 +152,19 @@
       const roleId = computed(() => userStore.getUserInfo?.roleId);
       const { getCheckPerm } = permissionStore;
       const { createMessage, createConfirm } = useMessage();
-      const [registerTable, { reload, getRawDataSource }] = useTable({
+      const [registerTables, { reload, getColumns }] = useTable({
         api: getAuthList,
         title: `已授权列表`,
-        columns: columns,
+        columns: columnssss,
         useSearchForm: false,
         immediate: false,
         searchInfo: {
           num: numRef,
+          sourceType: sourceType,
           caseId: caseId,
           authType: type,
+          fusionId: fusionId,
         },
-        // afterFetch: (T) => {
-        //   let { authType } = getRawDataSource();
-        //   setFieldsValue({
-        //     authType,
-        //   });
-        //   fileFlow.showList = authType ? false : true;
-        //   return T;
-        // },
         showTableSetting: true,
         tableSetting: { fullScreen: true },
         showIndexColumn: false,
@@ -218,27 +216,25 @@
       async function onDataReceive(data) {
         console.log('onDataReceive', data);
         modelRef.value = data;
-        numRef.value = data.num;
+        numRef.value = data.sourceType=='fusion'?data.fusionId: data.num;
+        sourceType.value = data.sourceType;
+        fusionId.value = data.fusionId;
         caseId.value = data.caseId;
         resetFields();
-        const { authType } = await getAuthType({ num: numRef.value, caseId: caseId.value });
+        const { authType } = await getAuthType({ num: numRef.value,  sourceType: sourceType.value });
         fileFlow.showList = authType ? false : true;
         type.value = authType;
         setFieldsValue({
           type: data.sceneName,
           authType,
         });
-        console.log(
-          'roleId',
-          roleId.value,
-          userName.value != data.userName || roleId.value != 1 || roleId.value != 45 || roleId.value != 48,
-        );
         let disabled = !(
           userName.value == data.userName ||
           roleId.value == 1 ||
           roleId.value == 45 ||
           roleId.value == 48
         );
+
         updateSchema({
           field: 'authType',
           componentProps: {
@@ -262,6 +258,7 @@
             caseId: caseId.value,
             ...params,
             lookAuth: params.authType,
+            sourceType: sourceType.value,
           });
           console.log('res', res);
           closeModal();
@@ -273,10 +270,11 @@
         }
       };
       function addPowes() {
-        openDetaileModal(true, { num: modelRef.value.num, caseId: caseId.value, qxType: fileFlow.showList });
+        console.log('addPowes', getColumns(), columnssss);
+        openDetaileModal(true, { num: numRef.value, caseId: caseId.value, qxType: fileFlow.showList, sourceType: sourceType.value });
       }
       function handleRyno(record) {
-        openryNoModal(true, {...record, caseId: caseId.value});
+        openryNoModal(true, {...record, caseId: caseId.value, sourceType: sourceType.value});
       }
       function handleEdit(record: Recordable) {
         openDetaileModal(true, record);
@@ -286,7 +284,7 @@
           title: '删除',
           content: `确定要删除 ${record.ryNickName} 吗?`,
           onOk: async () => {
-            await delAuth({ id: record.id });
+            await delAuth({ id: record.id, num: numRef.value, sourceType: sourceType.value, });
             createMessage.success('删除成功');
             reload();
           },
@@ -306,7 +304,7 @@
         getCheckPerm,
         handleEdit,
         handleDelete,
-        registerTable,
+        registerTables,
         registerDetail,
         registerryNoModal,
         openDetaileModal,
@@ -314,6 +312,8 @@
         reload,
         userName,
         caseId,
+        fusionId,
+        tableRef,
       };
     },
   });

+ 8 - 1
src/views/productOperation/modal/detailModal.vue

@@ -46,6 +46,10 @@
       });
       const { createMessage } = useMessage();
       const title = ref('新增客户');
+      const modelDataRef = ref({
+        num: '',
+        sourceType: '',
+      });
       const optionsName = ref([]);
       const range = (start, end) => {
         const result = [];
@@ -399,7 +403,9 @@
       let addListFunc = () => {};
       const [register, { closeModal }] = useModalInner(async (data) => {
         onSearch('');
-        let checkAuthOther = await checkAuthOtherApi({ num: data.num, caseId: data.caseId, authType: data.qxType ? 0 : 1, });
+        modelDataRef.value.num = data.num;
+        modelDataRef.value.sourceType = data.sourceType;
+        let checkAuthOther = await checkAuthOtherApi({ num: data.num, caseId: data.caseId, authType: data.qxType ? 0 : 1, sourceType: data.sourceType });
         let setData = {
           ...checkAuthOther,
           ...data,
@@ -550,6 +556,7 @@
                 ? 1
                 : 0,
             authType: fileFlow.qxType ? 0 : 1,
+            ...modelDataRef.value,
           });
           closeModal();
           resetFields();

+ 147 - 0
src/views/productOperation/modal/resultListModal.vue

@@ -0,0 +1,147 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    :title="fileFlow.name + '查询结果'"
+    okText="我知道了"
+    @visible-change="handleVisibleChange"
+    @cancel="resetFields"
+    :confirmLoading="loading"
+    min-height="50"
+    @ok="handleSubmit"
+  >
+    <div class="pt-2px pr-3px">
+      <div class="text">查询到 <span style="color: #0960bd">{{fileFlow.name}}</span> 无以下场景权限,请联系管理员开通</div>
+      <a-tabs v-model:activeKey="tableType" @change="changeTable">
+        <a-tab-pane :key="0" tab="查看权限" :disabled="loading" />
+        <a-tab-pane :key="1" tab="编辑权限" :disabled="loading" />
+      </a-tabs>
+      <BasicTable @register="registerTable">
+        <template #href="{ record }">
+          <a
+            v-if="record.caseTitle"
+            target="_blank"
+            :title="record.caseTitle"
+            :href="`/code/index.html?caseId=${record.fusionId}#/show`"
+            >{{ record.caseTitle }}</a
+          >
+          <span v-else>-</span>
+        </template>
+      </BasicTable>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, nextTick, onMounted, reactive, ref } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicTable, useTable } from '/@/components/Table';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { InvoiceRegister } from '/@/api/order';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { uploadApi } from '/@/api/product/index';
+  import { ResultEnum } from '/@/enums/httpEnum';
+  import { caseListApi } from '/@/api/operate';
+  const { t } = useI18n();
+  export default defineComponent({
+    components: { BasicModal, BasicTable },
+    props: {
+      userData: { type: Object },
+    },
+    emits: ['update', 'register'],
+    setup(props, { emit }) {
+      const fileFlow = reactive({
+        file: null,
+        name: '',
+        type: 2, //2-普通发票,3-专用发票
+      });
+      const tableType = ref<number>(0); //0查看 、1编辑
+      const columns = [
+        {
+          title: '标题',
+          dataIndex: 'sceneName',
+          ellipsis: true,
+          slots: { customRender: 'href' },
+          resizable: true,
+          minWidth: 150,
+          width: 300,
+        },
+        {
+          title: '姓名',
+          dataIndex: 'userName',
+          ellipsis: true,
+          width: 100,
+        }]
+      const [registerTable, { reload }] = useTable({
+        api: caseListApi,
+        title: ``,
+        // titleHelpMessage: ['已启用expandRowByClick', '已启用stopButtonPropagation'],
+        columns: columns,
+        searchInfo: { isShare: tableType },
+        useSearchForm: false,
+        showIndexColumn: false,
+        showTableSetting: true,
+        beforeFetch: (T) => {
+          loading.value = true;
+          return T;
+        },
+        afterFetch: (T) => {
+          loading.value = false;
+          return T;
+        },
+        rowKey: 'caseId',
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'pageSize',
+          listField: 'list',
+          totalField: 'total',
+        },               
+        canResize: true,
+      });
+      const okText = ref('确定');
+      const loading = ref(false);
+      const { createMessage } = useMessage();
+
+      onMounted(() => {});
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner((data) => {
+        data && onDataReceive(data);
+      });
+      function onDataReceive(data) {
+        resetFields();
+        setFieldsValue(data);
+      }
+      const handleSubmit = async () => {
+        loading.value = true;
+        try {
+          const params = await validate();
+          const apiData = params;
+          console.log('res', apiData, params);
+          await InvoiceRegister(apiData);
+          closeModal();
+          resetFields();
+          createMessage.success(t('common.optSuccess'));
+          emit('update');
+          loading.value = false;
+        } catch (error) {
+          loading.value = false;
+          console.log('not passing', error);
+        }
+      };
+      function handleVisibleChange(v) {
+        v && props.userData && nextTick(() => onDataReceive(props.userData));
+      }
+      return {
+        register,
+        registerTable,
+        fileFlow,
+        handleVisibleChange,
+        handleSubmit,
+        addListFunc,
+        reload,
+        okText,
+        loading,
+        t,
+      };
+    },
+  });
+</script>

+ 168 - 0
src/views/productOperation/modal/uploadModal.vue

@@ -0,0 +1,168 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    title="原始数据上传"
+    :showCancelBtn="false"
+    @visible-change="handleVisibleChange"
+    @cancel="resetFields"
+    @ok="handleSubmit"
+    :loading="loading"
+    :confirmLoading="loading"
+    :min-height="0"
+  >
+    <div class="pt-2px pr-3px">
+      <BasicForm @register="registerForm" :model="model">
+        <template #text="{ model, field }">
+          {{ model[field] }}
+        </template>
+      </BasicForm>
+      <!-- <span>注意:迁移后该场景的权限配置将被清空,如需保留,请复制后再做迁移</span> -->
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, nextTick, onMounted, reactive, h } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { uploadSceneOrig, uploadSceneCheck } from '/@/api/operate';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { uploadApi } from '/@/api/product/index';
+
+  const { t } = useI18n();
+  export default defineComponent({
+    components: { BasicModal, BasicForm },
+    props: {
+      userData: { type: Object },
+    },
+    emits: ['update', 'register'],
+    setup(props, { emit }) {
+      const modelRef = ref({});
+      const fileFlow = reactive({
+        filePath: null,
+      });
+      const loading = ref(false);
+      const { createMessage, createConfirm } = useMessage();
+      const schemas: FormSchema[] = [
+        {
+          field: 'filePath',
+          component: 'Upload',
+          label: t('routes.product.file'),
+          required: true,
+          rules: [{ required: true, message: t('common.uploadMessge') }],
+          // helpMessage: t('routes.corporation.uploadHelp'),
+          itemProps: {
+            validateTrigger: 'onBlur',
+          },
+          componentProps: {
+            api: uploadApi,
+            maxNumber: 1,
+            sizeUnit: 'GB',
+            maxSize: 5,
+            // accept: ['xls', 'xlsx'],
+            afterFetch: function (data) {
+              fileFlow.filePath = data.file;
+              return data;
+            },
+          },
+
+          colProps: {
+            span: 22,
+          },
+        },
+      ];
+      const [registerForm, { validate, resetFields, setFieldsValue }] = useForm({
+        labelWidth: 120,
+        schemas,
+        showActionButtonGroup: false,
+        actionColOptions: {
+          span: 24,
+        },
+      });
+      onMounted(() => {});
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner((data) => {
+        console.log(data);
+        data && onDataReceive(data);
+      });
+
+      function onDataReceive(data) {
+        modelRef.value = data;
+        resetFields();
+        setFieldsValue({
+          type: data.sceneName,
+        });
+      }
+      const handleSubmit = async () => {
+        try {
+          const params = await validate();
+          let filePath = params.filePath[0];
+          const resCheck = await uploadSceneCheck(filePath);
+          if (resCheck.code == 60042) {
+            return createConfirm({
+              iconType: 'warning',
+              title: '提示',
+              content: () =>
+                h('div', {}, [
+                  h('div', null, `此场景原属于${resCheck.data},继续上传将重新计算并覆盖原场景:`),
+                  h('div', null, `归属权转移至当前账号;`),
+                  h('div', null, `清除原所有者的权限设置;`),
+                  h('div', null, `清空场景内由用户手动添加的空间模型。`),
+                  h('div', null, `确定继续吗?`),
+                ]),
+              onOk: async () => {
+                Submit(filePath)
+              },
+            });
+          }
+          if(resCheck.code == 60043) {
+            return createConfirm({
+              iconType: 'warning',
+              title: '提示',
+              content: `此场景此前已上传过‌,继续上传将重新计算并覆盖原场景,场景内由用户手动添加的空间模型也会清空,确定继续吗?`,
+              onOk: async () => {
+                Submit(filePath)
+              },
+            });
+          }
+          Submit(filePath)
+        } catch (error) {
+          console.log('not passing', error);
+        }
+      };
+      function handleVisibleChange(v) {
+        // console.log(v);
+        // v && props.userData && nextTick(() => onDataReceive(props.userData));
+      }
+      async function Submit(filePath) {
+        loading.value = true;
+        try {
+          const res = await uploadSceneOrig(filePath);
+          loading.value = false;
+          console.log('res', res, filePath);
+          closeModal();
+          resetFields();
+          createMessage.success('上传成功。');
+          emit('update');
+        } catch (error) {
+          loading.value = false;
+        }
+
+      }
+      return {
+        register,
+        schemas,
+        registerForm,
+        model: modelRef,
+        fileFlow,
+        handleVisibleChange,
+        handleSubmit,
+        addListFunc,
+        loading,
+        resetFields,
+        t,
+      };
+    },
+  });
+</script>

+ 209 - 0
src/views/staffShare/addModal.vue

@@ -0,0 +1,209 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    title="新增人员"
+    @cancel="resetFields"
+    @ok="handleSubmit"
+  >
+    <div class="pt-2px pr-3px">
+      <BasicForm @register="registerForm">
+        <template #text="{ model, field }">
+          {{ model[field] }}
+        </template>
+      </BasicForm>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, onMounted, reactive } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { getinnerByRyId, userShareAdd } from '/@/api/operate';
+
+  const { t } = useI18n();
+  export default defineComponent({
+    components: { BasicModal, BasicForm },
+    props: {
+      userData: { type: Object },
+    },
+    emits: ['ok'],
+    setup(_, { emit }) {
+      const modelRef = ref(false);
+      const fileFlow = reactive({
+        file: null,
+      });
+      const { createMessage } = useMessage();
+      const optionsName = ref([]);
+      const schemas: FormSchema[] = [
+        {
+          field: 'id',
+          component: 'Input',
+          show: false,
+          label: 'id',
+          defaultValue: '111',
+          required: false,
+        },
+        {
+          field: 'ryNo',
+          component: 'Input',
+          label: '人员编号',
+          required: true,
+          rules: [
+            {
+              required: true,
+              // @ts-ignore
+              validator: async (rule, value) => {
+                let myData = await getFieldsValue();
+                if (!value) {
+                  return Promise.reject('请输入人员编号');
+                }
+                let res = await getinnerByRyId({ ryNo: value });
+                console.log('value', value, res);
+                if (res && !res.data) {
+                  return Promise.reject('人员编号不存在');
+                }
+                Promise.resolve();
+                let ryNickName = res && res.data && res.data.ryNickName;
+                if(myData.ryNickName != ryNickName || !myData.ryNickName){
+                  setFieldsValue({
+                    ryNickName: res && res.data ? res.data.ryNickName : '',
+                    id: res && res.data ? res.data.id : '',
+                  });
+                }
+              },
+              trigger: 'blur',
+            },
+          ],
+          colProps: {
+            span: 20,
+          },
+        },
+        // {
+        //   field: 'ryNo',
+        //   component: 'AutoComplete',
+        //   label: '人员编号',
+        //   required: true,
+        //   componentProps: {
+        //     filterOption: onFilterOption,
+        //     onSearch: onSearch,
+        //     onChange: (data) => {
+        //       setTimeout(() => {
+        //         const item = optionsName.value && optionsName.value.find((ele) => ele.ryNo == data);
+        //         setFieldsValue({
+        //           ryNickName: item && item.ryNickName ? item.ryNickName : '',
+        //           id: item && item.id ? item.id : '',
+        //         });
+        //       }, 100);
+        //     },
+        //   },
+        //   colProps: {
+        //     span: 20,
+        //   },
+        // },
+        {
+          field: 'ryNickName',
+          component: 'Input',
+          label: '姓名',
+          // rules: [
+          //   {
+          //     required: true,
+          //     // @ts-ignore
+          //     validator: async (rule, value) => {
+          //       if (!value) {
+          //         return Promise.reject('请输入正确的人员编号');
+          //       }
+          //       return Promise.resolve();
+          //     },
+          //     trigger: 'change',
+          //   },
+          // ],
+          colProps: {
+            span: 20,
+          },
+          componentProps: {
+            disabled: true,
+          },
+        },
+        {
+          field: 'isTop',
+          component: 'CheckboxGroup',
+          label: '共享内容',
+          required: true,
+          componentProps: {
+            options: [
+              { label: '场景', value: 1 },
+              { label: '案件', value: 2 },
+            ],
+          },
+          colProps: {
+            span: 20,
+          },
+        },
+      ];
+      const [
+        registerForm,
+        { validate, resetFields, setFieldsValue, getFieldsValue, updateSchema },
+      ] = useForm({
+        labelWidth: 110,
+        schemas,
+        showActionButtonGroup: false,
+        actionColOptions: {
+          span: 24,
+        },
+      });
+
+      onMounted(() => {});
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner(async (data) => {
+        console.log('option', data);
+      });
+      function onFilterOption(inputText: string, option) {
+        console.log('option', inputText, option.value);
+        if (option.value) {
+          return option.value.indexOf(inputText) >= 0;
+        }
+        // return option.value.indexOf(inputText.toUpperCase()) >= 0;
+      }
+      async function onSearch(searchText) {
+        const res = await getinnerByRyId({ ryNo: searchText });
+        console.log('res', res.data);
+        if (!res.data) return;
+        optionsName.value = res.data || {};
+        updateSchema({
+          field: 'ryNo',
+          componentProps: {
+            options: [optionsName.value],
+          },
+        });
+      }
+      const handleSubmit = async () => {
+        const params = await validate();
+        try {
+          console.log('params', params);
+          await userShareAdd(params);
+          closeModal();
+          resetFields();
+          emit('ok');
+          createMessage.success('操作成功');
+        } catch (error) {
+          console.log('not passing', error);
+        }
+      };
+
+      return {
+        register,
+        schemas,
+        registerForm,
+        modelRef,
+        fileFlow,
+        handleSubmit,
+        addListFunc,
+        resetFields,
+        t,
+      };
+    },
+  });
+</script>

+ 29 - 0
src/views/staffShare/data.ts

@@ -0,0 +1,29 @@
+// import { FormSchema } from '/@/components/Form/index';
+import { BasicColumn } from '/@/components/Table/src/types/table';
+
+export const userListSchema: BasicColumn[] = [
+  {
+    title: '姓名',
+    width: 200,
+    dataIndex: 'ryNickName',
+    fixed: 'left',
+  },
+  {
+    title: '人员编号',
+    width: 200,
+    dataIndex: 'ryNo',
+  },
+  {
+    title: '共享内容',
+    width: 200,
+    dataIndex: 'isTop',
+  },
+  {
+    title: '状态',
+    width: 200,
+    dataIndex: 'state',
+    customRender: ({ record }) => {
+      return record.status == 1 ? '正常' : '冻结';
+    },
+  },
+];

+ 121 - 0
src/views/staffShare/giveList.vue

@@ -0,0 +1,121 @@
+<template>
+  <div>
+    <BasicTable @register="registerTimeTable">
+      <template #action="{ record }">
+        <TableAction
+          :actions="[
+            {
+              label: record.sceneCount || '-',
+              onClick: handleCreate.bind(null, record),
+            },
+          ]"
+        />
+      </template>
+    </BasicTable>
+    <sceneListModal @register="register" />
+  </div>
+</template>
+<script lang="ts">
+  import { defineComponent } from 'vue';
+  import { BasicTable, useTable, FormProps, TableAction } from '/@/components/Table';
+  import { userShareList } from '/@/api/account';
+  import { userListSchema } from './data';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { usePermissionStore } from '/@/store/modules/permission';
+  import sceneListModal from './sceneListModal.vue';
+  import { useModal } from '/@/components/Modal';
+
+  export default defineComponent({
+    components: {
+      BasicTable,
+      sceneListModal,
+      TableAction,
+    },
+    setup() {
+      const { t } = useI18n();
+      const permissionStore = usePermissionStore();
+      const [register, { openModal }] = useModal();
+      const { getCheckPerm } = permissionStore;
+      const searchForm: Partial<FormProps> = {
+        labelWidth: 100,
+        schemas: [
+          {
+            field: 'ryNickName',
+            label: '姓名',
+            component: 'Input',
+            componentProps: {
+              maxLength: 100,
+            },
+            colProps: {
+              xl: 6,
+              xxl: 6,
+            },
+          },
+          {
+            field: 'ryNo',
+            label: '人员编号',
+            component: 'Input',
+            componentProps: {
+              maxLength: 100,
+            },
+            colProps: {
+              xl: 8,
+              xxl: 8,
+            },
+          },
+        ],
+      };
+      const [registerTimeTable, { reload }] = useTable({
+        api: userShareList,
+        columns: userListSchema,
+        useSearchForm: true,
+        formConfig: searchForm,
+        showTableSetting: true,
+        showIndexColumn: false,
+        searchInfo: { type: 1 },
+        rowKey: 'id',
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'pageSize',
+          listField: 'list',
+          totalField: 'total',
+        },
+        actionColumn: {
+          width: 100,
+          title: '场景',
+          dataIndex: 'action',
+          slots: { customRender: 'action' },
+        },
+        canResize: true,
+      });
+      function handleCreate(record) {
+        openModal(true, record);
+      }
+      function tabChange(val: string) {
+        console.log('tabChange', val);
+        reload();
+      }
+      function handleOpen(record) {
+        console.log('点击了启用', record);
+      }
+      return {
+        registerTimeTable,
+        handleOpen,
+        tabChange,
+        reload,
+        register,
+        getCheckPerm,
+        handleCreate,
+        t,
+      };
+    },
+  });
+</script>
+<style lang="less" scoped>
+  .desc-wrap-BasicTable {
+    background-color: #f0f2f5;
+    .vben-basic-table-form-container {
+      padding: 0;
+    }
+  }
+</style>

+ 142 - 0
src/views/staffShare/index.vue

@@ -0,0 +1,142 @@
+<template>
+  <div>
+    <BasicTable @register="registerTimeTable">
+      <template #toolbar>
+        <a-button type="primary" @click="handleCreate" v-if="getCheckPerm('sceneShare-add')">
+          新增</a-button
+        >
+      </template>
+      <template #action="{ record }">
+        <TableAction
+          :actions="[
+            {
+              label: '删除',
+              color: 'error',
+              ifShow: getCheckPerm('sceneShare-del'),
+              onClick: handleDlet.bind(null, record),
+            },
+          ]"
+        />
+      </template>
+    </BasicTable>
+    <addModal @register="registerAdd" @ok="reload" />
+  </div>
+</template>
+<script lang="ts">
+  import { defineComponent } from 'vue';
+  import { BasicTable, useTable, FormProps, TableAction } from '/@/components/Table';
+  import { userShareList, userShareDel } from '/@/api/account';
+  import { userListSchema } from './data';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useModal } from '/@/components/Modal';
+  import { usePermissionStore } from '/@/store/modules/permission';
+  import addModal from './addModal.vue';
+  import { useMessage } from '/@/hooks/web/useMessage';
+
+  export default defineComponent({
+    components: {
+      BasicTable,
+      TableAction,
+      addModal,
+    },
+    setup() {
+      const { t } = useI18n();
+      const { createMessage, createConfirm } = useMessage();
+      const permissionStore = usePermissionStore();
+      const [registerAdd, { openModal: openAddModal }] = useModal();
+      const { getCheckPerm } = permissionStore;
+      const searchForm: Partial<FormProps> = {
+        labelWidth: 100,
+        schemas: [
+          {
+            field: 'ryNickName',
+            label: '姓名',
+            component: 'Input',
+            componentProps: {
+              maxLength: 100,
+            },
+            colProps: {
+              xl: 6,
+              xxl: 6,
+            },
+          },
+          {
+            field: 'ryNo',
+            label: '人员编号',
+            component: 'Input',
+            componentProps: {
+              maxLength: 100,
+            },
+            colProps: {
+              xl: 8,
+              xxl: 8,
+            },
+          },
+        ],
+      };
+      const [registerTimeTable, { reload }] = useTable({
+        api: userShareList,
+        columns: userListSchema,
+        useSearchForm: true,
+        formConfig: searchForm,
+        showTableSetting: true,
+        showIndexColumn: false,
+        searchInfo: { type: 0 },
+        rowKey: 'id',
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'pageSize',
+          listField: 'list',
+          totalField: 'total',
+        },
+        actionColumn: {
+          width: 100,
+          title: '操作',
+          dataIndex: 'action',
+          slots: { customRender: 'action' },
+        },
+        canResize: true,
+      });
+      function handleCreate() {
+        openAddModal(true, {});
+      }
+      function tabChange(val: string) {
+        console.log('tabChange', val);
+        reload();
+      }
+      function handleOpen(record) {
+        console.log('点击了启用', record);
+      }
+      async function handleDlet(record) {
+        createConfirm({
+          title: '删除',
+          content: `确定要删除 ${record.ryNo} 吗?`,
+          onOk: async () => {
+            await userShareDel({id: record.id });
+            createMessage.success('操作成功');
+            reload();
+          },
+        });
+      }
+      return {
+        registerTimeTable,
+        registerAdd,
+        handleOpen,
+        tabChange,
+        reload,
+        handleDlet,
+        getCheckPerm,
+        handleCreate,
+        t,
+      };
+    },
+  });
+</script>
+<style lang="less" scoped>
+  .desc-wrap-BasicTable {
+    background-color: #f0f2f5;
+    .vben-basic-table-form-container {
+      padding: 0;
+    }
+  }
+</style>

+ 166 - 0
src/views/staffShare/sceneListModal.vue

@@ -0,0 +1,166 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    title="场景列表"
+    :width="1200"
+    :showOkBtn="false"
+    @ok="handleSubmit"
+  >
+    <div class="pt-3px pr-3px">
+      <div class="table_list">
+        <BasicTable @register="registerSubtable">
+          <template #href="{ record }">
+            <a
+              :title="record.sceneName"
+              v-if="record.webSite"
+              target="_blank"
+              :href="record.webSite"
+              >{{ record.title }}</a
+            >
+            <span v-else-if="record.sceneName">{{ record.sceneName }}</span>
+            <span v-else>-</span>
+          </template>
+        </BasicTable>
+      </div>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, onMounted, ref, h } from 'vue';
+  import { BasicTable, useTable, BasicColumn } from '/@/components/Table';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { Time } from '/@/components/Time';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { sceneList } from '/@/api/operate';
+
+  const { t } = useI18n();
+  export default defineComponent({
+    components: { BasicModal, BasicTable },
+    props: {
+      userData: { type: Object },
+    },
+    emits: ['update'],
+    setup(props, { emit }) {
+      const id = ref(null);
+      const columns: BasicColumn[] = [
+        {
+          title: '场景标题',
+          dataIndex: 'sceneName',
+          ellipsis: true,
+          slots: { customRender: 'href' },
+          width: 150,
+        },
+        {
+          title: '场景码',
+          dataIndex: 'num',
+          ellipsis: true,
+          width: 180,
+        },
+        {
+          title: '拍摄时间',
+          dataIndex: 'createTime',
+          width: 180,
+          customRender: ({ record }) => {
+            return (
+              record.createTime &&
+              h(Time, {
+                value: record.createTime,
+                mode: 'datetime',
+              })
+            );
+          },
+        },
+        {
+          title: '计算完成时间',
+          dataIndex: 'amount',
+          width: 180,
+          customRender: ({ record }) => {
+            return (
+              (record.algorithmTime &&
+                h(Time, {
+                  value: record.algorithmTime,
+                  mode: 'datetime',
+                })) ||
+              '-'
+            );
+          },
+        },
+        {
+          title: '人员编号',
+          dataIndex: 'ryNo',
+          width: 100,
+        },
+        {
+          title: t('routes.staff.userName'),
+          dataIndex: 'ryNickName',
+          width: 100,
+          customRender: ({ record }) => {
+            return record.ryNickName || '-';
+          },
+        },
+        {
+          title: '状态',
+          dataIndex: 'status',
+          width: 80,
+          customRender: ({ record }) => {
+            let str;
+            switch (record.status - 0) {
+              case 0:
+                str = '计算中';
+                break;
+              case 1:
+                str = '计算成功';
+                break;
+              case -2:
+                str = '计算成功';
+                break;
+              case -1:
+                str = '计算失败';
+                break;
+            }
+            return record.payStatus == -2 ? '封存' : str;
+          },
+        },
+      ];
+      const [registerSubtable, { reload }] = useTable({
+        api: sceneList,
+        showIndexColumn: true,
+        columns: columns,
+        searchInfo: { jyUserId: id },
+        rowKey: 'id',
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'pageSize',
+          listField: 'list',
+          totalField: 'total',
+        },
+        canResize: true,
+        bordered: true,
+      });
+
+      onMounted(() => {});
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner((data) => {
+        data && onDataReceive(data);
+      });
+      function onDataReceive(data) {
+        console.log('onDataReceive', data);
+        id.value = data.userId;
+        reload();
+      }
+      const handleSubmit = async () => {
+        closeModal();
+        emit('update');
+      };
+      return {
+        register,
+        handleSubmit,
+        addListFunc,
+        registerSubtable,
+        reload,
+        t,
+      };
+    },
+  });
+</script>

+ 65 - 64
src/views/statistics/components/sceneEchart.vue

@@ -1,7 +1,7 @@
 <template>
-  <Card :title="title||'订单数据统计'">
+  <Card :title="title || '订单数据统计'">
     <template #extra>
-      <condition type="2"  @change="Search" @expor="expor" />
+      <condition type="2" @change="Search" @expor="expor" />
     </template>
     <div ref="chartRef" :style="{ height, width }"></div>
   </Card>
@@ -11,13 +11,14 @@
   import condition from './condition.vue';
   import { Card, DatePicker } from 'ant-design-vue';
   import { ref, Ref, watch, defineEmits } from 'vue';
+  import { SCENE_TYPE } from '/@/settings/siteSetting';
   import { useECharts } from '/@/hooks/web/useECharts';
-  import { exportElsxFile, } from '/@/utils/file/download';
+  import { exportElsxFile } from '/@/utils/file/download';
   const props = defineProps({
-  loading: Boolean,
+    loading: Boolean,
     ...basicProps,
   });
-  const emit = defineEmits(["alertSome"])
+  const emit = defineEmits(['alertSome']);
   const kjList = ref<number[]>([]);
   const kkList = ref<number[]>([]);
   const ssList = ref<number[]>([]);
@@ -26,43 +27,43 @@
   const sgobjList = ref<number[]>([]);
   const yzlList = ref<number[]>([]);
   const yixStringData = ref<string[]>([]);
-  const echartTypr = ref('line')
-  const nameList = ref<string[]>(['四维看见/Mesh','四维看看/Mesh','四维深时/点云','四维深时/Mesh','四维深光/点云','四维深光/Mesh','圆周率/Mesh']);
+  const echartTypr = ref('line');
+  const nameList = ref<string[]>(SCENE_TYPE);
   const maxSize = ref(0);
   const chartRef = ref<HTMLDivElement | null>(null);
-  const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>)
+  const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
 
-  function Search(val){
-    emit('change',val)
+  function Search(val) {
+    emit('change', val);
   }
-  function expor(val){
-    let fileTile = props.title||'订单数据'
-    let fields  = {
-    'time':'日期',
-    'kj': nameList.value[0],
-    'kk': nameList.value[1],
-    'ss':nameList.value[2],
-    'dy':nameList.value[3],
-    'sg':nameList.value[4],
-    'sgdy':nameList.value[5],
-    'yzl':nameList.value[6],
+  function expor(val) {
+    let fileTile = props.title || '订单数据';
+    let fields = {
+      time: '日期',
+      kj: nameList.value[0],
+      kk: nameList.value[1],
+      ss: nameList.value[2],
+      // 'dy':nameList.value[3],
+      sg: nameList.value[3],
+      // 'sgdy':nameList.value[5],
+      yzl: nameList.value[4],
+    };
+    if ('场景趋势分析' == fileTile) {
+      fileTile = `${val && val.value == 0 ? '新增' : '累计'}` + fileTile;
     }
-    if('场景趋势分析' == fileTile){
-      fileTile = `${val && val.value == 0?'新增':'累计'}`+fileTile
-    }
-    let data = yixStringData.value.map((ele,index) => {
+    let data = yixStringData.value.map((ele, index) => {
       return {
-        'time':ele,
-        'kj':kjList.value && kjList.value[index] || 0,
-        'kk':kkList.value && kkList.value[index] || 0,
-        'ss':ssList.value && ssList.value[index] || 0,
-        'dy':ssobjList.value && ssobjList.value[index] || 0,
-        'sg':sgList.value && sgList.value[index] || 0,
-        'sgdy':sgobjList.value && sgobjList.value[index] || 0,
-        'yzl':yzlList.value && yzlList.value[index] || 0,
-      }
-    })
-    exportElsxFile(data,fields,fileTile)
+        time: ele,
+        kj: (kjList.value && kjList.value[index]) || 0,
+        kk: (kkList.value && kkList.value[index]) || 0,
+        ss: (ssList.value && ssList.value[index]) || 0,
+        // 'dy':ssobjList.value && ssobjList.value[index] || 0,
+        sg: (sgList.value && sgList.value[index]) || 0,
+        // 'sgdy':sgobjList.value && sgobjList.value[index] || 0,
+        yzl: (yzlList.value && yzlList.value[index]) || 0,
+      };
+    });
+    exportElsxFile(data, fields, fileTile);
   }
   function handlesetOptions() {
     setOptions({
@@ -112,33 +113,33 @@
           barMaxWidth: 80,
           name: nameList.value[2],
         },
-        {
-          data: ssobjList.value,
-          type: echartTypr.value,
-          itemStyle: { color: '#d58b55' },
-          barMaxWidth: 80,
-          name: nameList.value[3],
-        },
+        // {
+        //   data: ssobjList.value,
+        //   type: echartTypr.value,
+        //   itemStyle: { color: '#d58b55' },
+        //   barMaxWidth: 80,
+        //   name: nameList.value[3],
+        // },
         {
           data: sgList.value,
           type: echartTypr.value,
           itemStyle: { color: '#55d187' },
           barMaxWidth: 80,
-          name: nameList.value[4],
-        },
-        {
-          data: sgobjList.value,
-          type: echartTypr.value,
-          itemStyle: { color: '#faa19d' },
-          barMaxWidth: 80,
-          name: nameList.value[5],
+          name: nameList.value[3],
         },
+        // {
+        //   data: sgobjList.value,
+        //   type: echartTypr.value,
+        //   itemStyle: { color: '#faa19d' },
+        //   barMaxWidth: 80,
+        //   name: nameList.value[5],
+        // },
         {
           data: yzlList.value,
           type: echartTypr.value,
           itemStyle: { color: '#00c8af' },
           barMaxWidth: 80,
-          name: nameList.value[6],
+          name: nameList.value[4],
         },
       ],
     });
@@ -146,19 +147,19 @@
   watch(
     () => props.echartData,
     (echartData) => {
-      kjList.value = echartData.kjList ||[]
-      kkList.value = echartData.kkList ||[]
-      ssList.value = echartData.ssList ||[]
-      ssobjList.value = echartData.ssobjList ||[]
-      sgList.value = echartData.sgList ||[]
-      sgobjList.value = echartData.sgobjList ||[]
-      yzlList.value = echartData.yzlList ||[]
-      yixStringData.value = echartData.xdata ||[]
-      if(echartData.nameList){
-        nameList.value = echartData.nameList
+      kjList.value = echartData.kjList || [];
+      kkList.value = echartData.kkList || [];
+      ssList.value = echartData.ssList || [];
+      ssobjList.value = echartData.ssobjList || [];
+      sgList.value = echartData.sgList || [];
+      sgobjList.value = echartData.sgobjList || [];
+      yzlList.value = echartData.yzlList || [];
+      yixStringData.value = echartData.xdata || [];
+      if (echartData.nameList) {
+        nameList.value = echartData.nameList;
       }
-      if(echartData.echartTypr){
-        echartTypr.value = echartData.echartTypr
+      if (echartData.echartTypr) {
+        echartTypr.value = echartData.echartTypr;
       }
       handlesetOptions();
     },

+ 3 - 3
src/views/statistics/scene/index.vue

@@ -1,12 +1,12 @@
 <template>
   <div class="p-4">
     <GrowCard :loading="loading" :list="growCardList" class="enter-y" />
-    <sceneEchart
+    <!-- <sceneEchart
       title="场景趋势分析"
       class="!my-4 enter-y"
       @change="Search"
       :echartData="echartData"
-    />
+    /> -->
   </div>
 </template>
 <script lang="ts" setup>
@@ -35,7 +35,7 @@
   });
   onMounted(() => {
     getData();
-    getList();
+    // getList();
   });
   async function getList() {
     let downlist = [],

+ 194 - 0
src/views/workerShare/addModal.vue

@@ -0,0 +1,194 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    :title="title"
+    @cancel="resetFields"
+    @ok="handleSubmit"
+  >
+    <div class="pt-2px pr-3px">
+      <BasicForm @register="registerForm">
+        <template #text="{ model, field }">
+          {{ model[field] }}
+        </template>
+      </BasicForm>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, onMounted, reactive } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { getinnerByRyId, userShareAdd } from '/@/api/operate';
+
+  const { t } = useI18n();
+  export default defineComponent({
+    components: { BasicModal, BasicForm },
+    props: {
+      userData: { type: Object },
+    },
+    emits: ['ok'],
+    setup(_, { emit }) {
+      const modelRef = ref(false);
+      const fileFlow = reactive({
+        file: null,
+        id: '',
+      });
+      const { createMessage } = useMessage();
+      const optionsName = ref([]);
+      const title = ref('新增人员');
+      const schemas: FormSchema[] = [
+        {
+          field: 'id',
+          component: 'Input',
+          show: false,
+          label: 'id',
+          defaultValue: '111',
+          required: false,
+        },
+        {
+          field: 'ryNo',
+          component: 'Input',
+          label: '人员编号',
+          required: true,
+          rules: [
+            {
+              required: true,
+              // @ts-ignore
+              validator: async (rule, value) => {
+                let myData = await getFieldsValue();
+                if (!value) {
+                  return Promise.reject('请输入人员编号');
+                }
+                let res = await getinnerByRyId({ ryNo: value });
+                fileFlow.id = res && res.data ? res.data.id : '';
+                console.log('value', value, res);
+                if (res && !res.data) {
+                  return Promise.reject('人员编号不存在');
+                }
+                Promise.resolve();
+                let ryNickName = res && res.data && res.data.ryNickName;
+                if(myData.ryNickName != ryNickName || !myData.ryNickName){
+                  setFieldsValue({
+                    ryNickName: res && res.data ? res.data.ryNickName : '',
+                    id: res && res.data ? res.data.id : '',
+                  });
+                }
+              },
+              trigger: 'blur',
+            },
+          ],
+          colProps: {
+            span: 20,
+          },
+        },
+        {
+          field: 'ryNickName',
+          component: 'Input',
+          label: '姓名',
+          colProps: {
+            span: 20,
+          },
+          componentProps: {
+            disabled: true,
+          },
+        },
+        {
+          field: 'shareTypes',
+          component: 'CheckboxGroup',
+          required: true,
+          label: '共享内容',
+          componentProps: {
+            options: [
+              { label: '查看实景三维', value: 'scene' },
+              { label: '查看多元融合', value: 'fusion' },
+            ],
+          },
+          colProps: {
+            span: 24,
+          },
+        },
+      ];
+      const [
+        registerForm,
+        { validate, resetFields, setFieldsValue, getFieldsValue, updateSchema },
+      ] = useForm({
+        labelWidth: 110,
+        schemas,
+        showActionButtonGroup: false,
+        actionColOptions: {
+          span: 24,
+        },
+      });
+
+      onMounted(() => {});
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner(async (data) => {
+        console.log('option', data);
+        fileFlow.id = data.id;
+        title.value = data.id ? '编辑人员' : '新增人员';
+        // let shareTypeObj = {
+        //   0: [0],
+        //   1: [1],
+        //   2: [0, 1],
+        // }
+        setFieldsValue({
+          ...data,
+          // shareType: data.shareType && shareTypeObj[data.shareType]||[]
+        })
+      });
+      function onFilterOption(inputText: string, option) {
+        console.log('option', inputText, option.value);
+        if (option.value) {
+          return option.value.indexOf(inputText) >= 0;
+        }
+        // return option.value.indexOf(inputText.toUpperCase()) >= 0;
+      }
+      async function onSearch(searchText) {
+        const res = await getinnerByRyId({ ryNo: searchText });
+        console.log('res', res.data);
+        if (!res.data) return;
+        optionsName.value = res.data || {};
+        updateSchema({
+          field: 'ryNo',
+          componentProps: {
+            options: [optionsName.value],
+          },
+        });
+      }
+      const handleSubmit = async () => {
+        const params = await validate();
+        try {
+          console.log('params', params);
+          // let shareType = params.shareType.length == 2 ? 2 : params.shareType[0];
+          await userShareAdd({
+            ...params,
+            id: fileFlow.id,
+            // shareType: shareType,
+          });
+          closeModal();
+          resetFields();
+          emit('ok');
+          createMessage.success('操作成功');
+        } catch (error) {
+          console.log('not passing', error);
+        }
+      };
+
+      return {
+        register,
+        schemas,
+        registerForm,
+        modelRef,
+        fileFlow,
+        handleSubmit,
+        addListFunc,
+        resetFields,
+        title,
+        t,
+      };
+    },
+  });
+</script>

+ 38 - 0
src/views/workerShare/data.ts

@@ -0,0 +1,38 @@
+// import { FormSchema } from '/@/components/Form/index';
+import { BasicColumn } from '/@/components/Table/src/types/table';
+
+export const userListSchema: BasicColumn[] = [
+  {
+    title: '姓名',
+    width: 200,
+    dataIndex: 'ryNickName',
+    fixed: 'left',
+  },
+  {
+    title: '人员编号',
+    width: 200,
+    dataIndex: 'ryNo',
+  },
+  {
+    title: '共享内容',
+    width: 200,
+    dataIndex: 'ryNo1',
+    customRender: ({ record }) => {
+      if (!record.shareTypes) return '';
+      const shareTypes = record.shareTypes.toString();
+      return shareTypes == 'scene'
+        ? '查看实景三维'
+        : shareTypes == 'fusion'
+        ? '查看多元融合'
+        : '查看实景三维 查看多元融合';
+    },
+  },
+  {
+    title: '状态',
+    width: 200,
+    dataIndex: 'state',
+    customRender: ({ record }) => {
+      return record.status == 1 ? '正常' : '冻结';
+    },
+  },
+];

+ 121 - 0
src/views/workerShare/giveList.vue

@@ -0,0 +1,121 @@
+<template>
+  <div>
+    <BasicTable @register="registerTimeTable">
+      <template #action="{ record }">
+        <TableAction
+          :actions="[
+            {
+              label: record.sceneCount || '-',
+              onClick: handleCreate.bind(null, record),
+            },
+          ]"
+        />
+      </template>
+    </BasicTable>
+    <sceneListModal @register="register" />
+  </div>
+</template>
+<script lang="ts">
+  import { defineComponent } from 'vue';
+  import { BasicTable, useTable, FormProps, TableAction } from '/@/components/Table';
+  import { userShareList } from '/@/api/account';
+  import { userListSchema } from './data';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { usePermissionStore } from '/@/store/modules/permission';
+  import sceneListModal from './sceneListModal.vue';
+  import { useModal } from '/@/components/Modal';
+
+  export default defineComponent({
+    components: {
+      BasicTable,
+      sceneListModal,
+      TableAction,
+    },
+    setup() {
+      const { t } = useI18n();
+      const permissionStore = usePermissionStore();
+      const [register, { openModal }] = useModal();
+      const { getCheckPerm } = permissionStore;
+      const searchForm: Partial<FormProps> = {
+        labelWidth: 100,
+        schemas: [
+          {
+            field: 'ryNickName',
+            label: '姓名',
+            component: 'Input',
+            componentProps: {
+              maxLength: 100,
+            },
+            colProps: {
+              xl: 6,
+              xxl: 6,
+            },
+          },
+          {
+            field: 'ryNo',
+            label: '人员编号',
+            component: 'Input',
+            componentProps: {
+              maxLength: 100,
+            },
+            colProps: {
+              xl: 8,
+              xxl: 8,
+            },
+          },
+        ],
+      };
+      const [registerTimeTable, { reload }] = useTable({
+        api: userShareList,
+        columns: userListSchema,
+        useSearchForm: true,
+        formConfig: searchForm,
+        showTableSetting: true,
+        showIndexColumn: false,
+        searchInfo: { type: 1 },
+        rowKey: 'id',
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'pageSize',
+          listField: 'list',
+          totalField: 'total',
+        },
+        actionColumn: {
+          width: 100,
+          title: '场景',
+          dataIndex: 'action',
+          slots: { customRender: 'action' },
+        },
+        canResize: true,
+      });
+      function handleCreate(record) {
+        openModal(true, record);
+      }
+      function tabChange(val: string) {
+        console.log('tabChange', val);
+        reload();
+      }
+      function handleOpen(record) {
+        console.log('点击了启用', record);
+      }
+      return {
+        registerTimeTable,
+        handleOpen,
+        tabChange,
+        reload,
+        register,
+        getCheckPerm,
+        handleCreate,
+        t,
+      };
+    },
+  });
+</script>
+<style lang="less" scoped>
+  .desc-wrap-BasicTable {
+    background-color: #f0f2f5;
+    .vben-basic-table-form-container {
+      padding: 0;
+    }
+  }
+</style>

+ 152 - 0
src/views/workerShare/index.vue

@@ -0,0 +1,152 @@
+<template>
+  <div>
+    <BasicTable @register="registerTimeTable">
+      <template #toolbar>
+        <a-button type="primary" @click="handleCreate" v-if="getCheckPerm('sceneShare-add')">
+          新增</a-button
+        >
+      </template>
+      <template #action="{ record }">
+        <TableAction
+          :actions="[
+            {
+              label: '编辑',
+              ifShow: getCheckPerm('sceneShare-edit'),
+              onClick: handleEdit.bind(null, record),
+            },
+            {
+              label: '删除',
+              color: 'error',
+              ifShow: getCheckPerm('sceneShare-del'),
+              onClick: handleDlet.bind(null, record),
+            },
+          ]"
+        />
+      </template>
+    </BasicTable>
+    <addModal @register="registerAdd" @ok="reload" />
+  </div>
+</template>
+<script lang="ts">
+  import { defineComponent } from 'vue';
+  import { BasicTable, useTable, FormProps, TableAction } from '/@/components/Table';
+  import { userShareList, userShareDel } from '/@/api/account';
+  import { userListSchema } from './data';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useModal } from '/@/components/Modal';
+  import { usePermissionStore } from '/@/store/modules/permission';
+  import addModal from './addModal.vue';
+  import { useMessage } from '/@/hooks/web/useMessage';
+
+  export default defineComponent({
+    components: {
+      BasicTable,
+      TableAction,
+      addModal,
+    },
+    setup() {
+      const { t } = useI18n();
+      const { createMessage, createConfirm } = useMessage();
+      const permissionStore = usePermissionStore();
+      const [registerAdd, { openModal: openAddModal }] = useModal();
+      const { getCheckPerm } = permissionStore;
+      const searchForm: Partial<FormProps> = {
+        labelWidth: 100,
+        schemas: [
+          {
+            field: 'ryNickName',
+            label: '姓名',
+            component: 'Input',
+            componentProps: {
+              maxLength: 100,
+            },
+            colProps: {
+              xl: 6,
+              xxl: 6,
+            },
+          },
+          {
+            field: 'ryNo',
+            label: '人员编号',
+            component: 'Input',
+            componentProps: {
+              maxLength: 100,
+            },
+            colProps: {
+              xl: 8,
+              xxl: 8,
+            },
+          },
+        ],
+      };
+      const [registerTimeTable, { reload }] = useTable({
+        api: userShareList,
+        columns: userListSchema,
+        useSearchForm: true,
+        formConfig: searchForm,
+        showTableSetting: true,
+        showIndexColumn: false,
+        searchInfo: { type: 0 },
+        rowKey: 'id',
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'pageSize',
+          listField: 'list',
+          totalField: 'total',
+        },
+        actionColumn: {
+          width: 100,
+          title: '操作',
+          dataIndex: 'action',
+          slots: { customRender: 'action' },
+        },
+        canResize: true,
+      });
+      function handleCreate() {
+        openAddModal(true, {});
+      }
+      function tabChange(val: string) {
+        console.log('tabChange', val);
+        reload();
+      }
+      function handleOpen(record) {
+        console.log('点击了启用', record);
+      }
+      function handleEdit(record) {
+        openAddModal(true, record);
+      }
+      
+      async function handleDlet(record) {
+        createConfirm({
+          title: '删除',
+          content: `确定要删除 ${record.ryNo} 吗?`,
+          onOk: async () => {
+            await userShareDel({id: record.id });
+            createMessage.success('操作成功');
+            reload();
+          },
+        });
+      }
+      return {
+        registerTimeTable,
+        registerAdd,
+        handleOpen,
+        tabChange,
+        reload,
+        handleDlet,
+        getCheckPerm,
+        handleEdit,
+        handleCreate,
+        t,
+      };
+    },
+  });
+</script>
+<style lang="less" scoped>
+  .desc-wrap-BasicTable {
+    background-color: #f0f2f5;
+    .vben-basic-table-form-container {
+      padding: 0;
+    }
+  }
+</style>

+ 166 - 0
src/views/workerShare/sceneListModal.vue

@@ -0,0 +1,166 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    title="场景列表"
+    :width="1200"
+    :showOkBtn="false"
+    @ok="handleSubmit"
+  >
+    <div class="pt-3px pr-3px">
+      <div class="table_list">
+        <BasicTable @register="registerSubtable">
+          <template #href="{ record }">
+            <a
+              :title="record.sceneName"
+              v-if="record.webSite"
+              target="_blank"
+              :href="record.webSite"
+              >{{ record.title }}</a
+            >
+            <span v-else-if="record.sceneName">{{ record.sceneName }}</span>
+            <span v-else>-</span>
+          </template>
+        </BasicTable>
+      </div>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, onMounted, ref, h } from 'vue';
+  import { BasicTable, useTable, BasicColumn } from '/@/components/Table';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { Time } from '/@/components/Time';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { sceneList } from '/@/api/operate';
+
+  const { t } = useI18n();
+  export default defineComponent({
+    components: { BasicModal, BasicTable },
+    props: {
+      userData: { type: Object },
+    },
+    emits: ['update'],
+    setup(props, { emit }) {
+      const id = ref(null);
+      const columns: BasicColumn[] = [
+        {
+          title: '场景标题',
+          dataIndex: 'sceneName',
+          ellipsis: true,
+          slots: { customRender: 'href' },
+          width: 150,
+        },
+        {
+          title: '场景码',
+          dataIndex: 'num',
+          ellipsis: true,
+          width: 180,
+        },
+        {
+          title: '拍摄时间',
+          dataIndex: 'createTime',
+          width: 180,
+          customRender: ({ record }) => {
+            return (
+              record.createTime &&
+              h(Time, {
+                value: record.createTime,
+                mode: 'datetime',
+              })
+            );
+          },
+        },
+        {
+          title: '计算完成时间',
+          dataIndex: 'amount',
+          width: 180,
+          customRender: ({ record }) => {
+            return (
+              (record.algorithmTime &&
+                h(Time, {
+                  value: record.algorithmTime,
+                  mode: 'datetime',
+                })) ||
+              '-'
+            );
+          },
+        },
+        {
+          title: '人员编号',
+          dataIndex: 'ryNo',
+          width: 100,
+        },
+        {
+          title: t('routes.staff.userName'),
+          dataIndex: 'ryNickName',
+          width: 100,
+          customRender: ({ record }) => {
+            return record.ryNickName || '-';
+          },
+        },
+        {
+          title: '状态',
+          dataIndex: 'status',
+          width: 80,
+          customRender: ({ record }) => {
+            let str;
+            switch (record.status - 0) {
+              case 0:
+                str = '计算中';
+                break;
+              case 1:
+                str = '计算成功';
+                break;
+              case -2:
+                str = '计算成功';
+                break;
+              case -1:
+                str = '计算失败';
+                break;
+            }
+            return record.payStatus == -2 ? '封存' : str;
+          },
+        },
+      ];
+      const [registerSubtable, { reload }] = useTable({
+        api: sceneList,
+        showIndexColumn: true,
+        columns: columns,
+        searchInfo: { jyUserId: id },
+        rowKey: 'id',
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'pageSize',
+          listField: 'list',
+          totalField: 'total',
+        },
+        canResize: true,
+        bordered: true,
+      });
+
+      onMounted(() => {});
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner((data) => {
+        data && onDataReceive(data);
+      });
+      function onDataReceive(data) {
+        console.log('onDataReceive', data);
+        id.value = data.userId;
+        reload();
+      }
+      const handleSubmit = async () => {
+        closeModal();
+        emit('update');
+      };
+      return {
+        register,
+        handleSubmit,
+        addListFunc,
+        registerSubtable,
+        reload,
+        t,
+      };
+    },
+  });
+</script>