فهرست منبع

提交代码inti

tangning 1 ماه پیش
والد
کامیت
745c9dcf4b

+ 5 - 0
.env

@@ -3,7 +3,12 @@ VITE_CDN = https://4dscene.4dage.com/new4dkk/
 
 
 # oss 对外访问域名
 # oss 对外访问域名
 VITE_OSS_PUBLIC_URL = https://4dkk.4dage.com
 VITE_OSS_PUBLIC_URL = https://4dkk.4dage.com
+
 VITE_PATH = https://test.4dkankan.com/
 VITE_PATH = https://test.4dkankan.com/
+
+#激光url
+VITE_LASER_URL = https://uat-laser.4dkankan.com/uat
+
 # spa-title
 # spa-title
 VITE_GLOB_APP_TITLE = 四维时代
 VITE_GLOB_APP_TITLE = 四维时代
 
 

+ 6 - 1
.env.cn-prod

@@ -4,8 +4,13 @@ VITE_CDN = https://4dscene.4dage.com/new4dkk/
 # oss 对外访问域名
 # oss 对外访问域名
 VITE_OSS_PUBLIC_URL = https://4dkk.4dage.com
 VITE_OSS_PUBLIC_URL = https://4dkk.4dage.com
 
 
+VITE_PATH = https://www.4dkankan.com/
+
+#激光url
+VITE_LASER_URL = https://laser.4dkankan.com
+
 # spa-title
 # spa-title
-VITE_GLOB_APP_TITLE = 四维时代管理后台
+VITE_GLOB_APP_TITLE = 四维时代
 
 
 # spa shortname
 # spa shortname
 VITE_GLOB_APP_SHORT_NAME = 4DAGE
 VITE_GLOB_APP_SHORT_NAME = 4DAGE

+ 5 - 0
.env.cn-test

@@ -4,6 +4,11 @@ VITE_CDN = https://4dscene.4dage.com/new4dkk/
 # oss 对外访问域名
 # oss 对外访问域名
 VITE_OSS_PUBLIC_URL = https://4dkk.4dage.com
 VITE_OSS_PUBLIC_URL = https://4dkk.4dage.com
 
 
+VITE_PATH = https://test.4dkankan.com/
+
+#激光url
+VITE_LASER_URL = https://uat-laser.4dkankan.com/uat
+
 # spa-title
 # spa-title
 VITE_GLOB_APP_TITLE = 四维时代管理后台
 VITE_GLOB_APP_TITLE = 四维时代管理后台
 
 

+ 6 - 0
.env.intl-prod

@@ -4,6 +4,12 @@ VITE_PORT = 3100
 # spa-title
 # spa-title
 VITE_GLOB_APP_TITLE = 四维时代管理后台
 VITE_GLOB_APP_TITLE = 四维时代管理后台
 
 
+VITE_PATH = https://eur.4dkankan.com/
+
+#激光url
+VITE_LASER_URL = https://eurlaser.4dkankan.com
+
+
 # spa shortname
 # spa shortname
 VITE_GLOB_APP_SHORT_NAME = 4DAGE
 VITE_GLOB_APP_SHORT_NAME = 4DAGE
 
 

+ 5 - 0
.env.intl-test

@@ -4,6 +4,11 @@ VITE_PORT = 3100
 # spa-title
 # spa-title
 VITE_GLOB_APP_TITLE = 四维时代管理后台
 VITE_GLOB_APP_TITLE = 四维时代管理后台
 
 
+VITE_PATH = https://test-eur.4dkankan.com/
+
+#激光url
+VITE_LASER_URL = https://test-eurlaser.4dkankan.com/uat
+
 # spa shortname
 # spa shortname
 VITE_GLOB_APP_SHORT_NAME = 4DAGE
 VITE_GLOB_APP_SHORT_NAME = 4DAGE
 
 

+ 2 - 1
package.json

@@ -45,7 +45,8 @@
   },
   },
    "pnpm": {
    "pnpm": {
     "overrides": {
     "overrides": {
-      "rolldown": "1.0.0"
+      "rolldown": "1.0.0",
+      "rolldown-vite": "1.0.0"
     }
     }
   }
   }
 }
 }

+ 9 - 9
src/api/scene/index.js

@@ -3,13 +3,13 @@ import { useUserStore } from "@/stores/user";
 
 
 const Api = {
 const Api = {
   sceneList: '/ucenter/szy/sceneList',
   sceneList: '/ucenter/szy/sceneList',
-  folderList: 'ucenter/szy/folder/findListTree',
-  folderSave: 'ucenter/szy/folder/save',
-  folderMove: 'ucenter/szy/folder/move',
-  folderDelete: 'ucenter/szy/folder/delete',
-  findListTree: 'ucenter/szy/folder/findListTree',
-  findListByName: 'ucenter/szy/folder/findListByName',
-  updateFolder: 'ucenter/szy/folder/update',
+  folderList: '/ucenter/szy/folder/findListTree',
+  folderSave: '/ucenter/szy/folder/save',
+  folderMove: '/ucenter/szy/folder/move',
+  folderDelete: '/ucenter/szy/folder/delete',
+  findListTree: '/ucenter/szy/folder/findListTree',
+  findListByName: '/ucenter/szy/folder/findListByName',
+  updateFolder: '/ucenter/szy/folder/update',
   //下载e57
   //下载e57
   checkDownLoadE57: 'ucenter/user/scene/checkDownLoadE57',
   checkDownLoadE57: 'ucenter/user/scene/checkDownLoadE57',
   downSceneE57: 'ucenter/user/scene/downSceneE57',
   downSceneE57: 'ucenter/user/scene/downSceneE57',
@@ -24,9 +24,9 @@ const Api = {
   relevanceE57: 'ucenter/user/scene/relevanceE57List',
   relevanceE57: 'ucenter/user/scene/relevanceE57List',
   assumeRole: 'cloud-acl/sts/assumeRole',
   assumeRole: 'cloud-acl/sts/assumeRole',
   copyScene: 'ucenter/user/scene/copyScene',
   copyScene: 'ucenter/user/scene/copyScene',
-  sceneDetail: 'ucenter/szy/sceneDetail',
+  sceneDetail: '/ucenter/szy/sceneDetail',
   getTakeLookRoomId: 'ucenter/user/scene/getTakeLookRoomId',
   getTakeLookRoomId: 'ucenter/user/scene/getTakeLookRoomId',
-  buildObj: 'ucenter/szy/buildObj',
+  buildObj: '/ucenter/szy/buildObj',
   sceneResourceList: 'ucenter/user/scene/cooperation/sceneResourceList',
   sceneResourceList: 'ucenter/user/scene/cooperation/sceneResourceList',
   saveBatch: 'ucenter/user/scene/cooperation/saveBatch',
   saveBatch: 'ucenter/user/scene/cooperation/saveBatch',
   saveCamera: 'ucenter/user/scene/cooperation/saveCamera',
   saveCamera: 'ucenter/user/scene/cooperation/saveCamera',

BIN
src/assets/image/scene/folder.png


BIN
src/assets/image/scene/nofolder.png


BIN
src/assets/image/scene/treeFolder.png


+ 11 - 1
src/assets/style/index.less

@@ -9,7 +9,17 @@
   --ant-primary-2: #bae7ff;
   --ant-primary-2: #bae7ff;
   line-height:normal;
   line-height:normal;
 }
 }
-
+/* 处理浏览器自动填充变色 */
+input:-webkit-autofill,
+input:-webkit-autofill:hover,
+input:-webkit-autofill:focus,
+input:-webkit-autofill:active {
+  /* 铺满白色背景,替换浏览器默认浅蓝填充色 */
+  -webkit-box-shadow: 0 0 0 1000px #ffffff inset !important;
+  /* 文字黑色,保证可读性 */
+  -webkit-text-fill-color: #000000 !important;
+  box-shadow: none !important;
+}
 html,
 html,
 body,
 body,
 #app {
 #app {

+ 251 - 40
src/layouts/header.vue

@@ -1,124 +1,335 @@
 <script setup>
 <script setup>
-import { useUserStore } from "@/stores";
+
+import { useUserStore, useNotificationStore } from "@/stores";
+
 import { useI18n } from "vue-i18n";
 import { useI18n } from "vue-i18n";
-import { createVNode, ref } from 'vue'
-const userStore = useUserStore();
+
+import { createVNode, ref, watch, onMounted } from "vue";
+
 import {
 import {
+
   QuestionCircleOutlined,
   QuestionCircleOutlined,
+
   BellOutlined,
   BellOutlined,
+
   DownOutlined,
   DownOutlined,
+
   ExclamationCircleFilled,
   ExclamationCircleFilled,
+
 } from "@ant-design/icons-vue";
 } from "@ant-design/icons-vue";
-import { Modal } from 'ant-design-vue';
-import { useRouter, useRoute } from 'vue-router'
+
+import { Modal } from "ant-design-vue";
+
+import { useRouter, useRoute } from "vue-router";
+
+import { getWsClient } from "@/utils/wsClient";
+
+
+
+const userStore = useUserStore();
+
+const notificationStore = useNotificationStore();
+
 const { t } = useI18n();
 const { t } = useI18n();
-const router = useRouter()
-const route = useRoute()
-const type = route.params?.type
-const visible = ref(false)
-console.log(route)
+
+const router = useRouter();
+
+const route = useRoute();
+
+const type = route.params?.type;
+
+const visible = ref(false);
+
+const wsClient = getWsClient();
+
+
+
+const handleBellClick = () => {
+
+  notificationStore.clearUnread();
+
+};
+
+
+
 const handleMenuClick = (e) => {
 const handleMenuClick = (e) => {
+
   if (e.key === "1") {
   if (e.key === "1") {
-    // 跳转到账户信息页面
-    console.log("我的账户");
-    router.push('/information')
+
+    router.push("/information");
+
     visible.value = true;
     visible.value = true;
+
   } else if (e.key === "2") {
   } else if (e.key === "2") {
-    // 执行退出登录操作
+
     Modal.confirm({
     Modal.confirm({
-        title: t('common.tip'),
-        icon: createVNode(ExclamationCircleFilled),
-        content: t('login.logoutTip'),
-        centered: true,
-        // okText: '确认',
-        // cancelText: '取消',
-        onOk: async () => {
-          await userStore.logout()
-        }
-      });
+
+      title: t("common.tip"),
+
+      icon: createVNode(ExclamationCircleFilled),
+
+      content: t("login.logoutTip"),
+
+      centered: true,
+
+      onOk: async () => {
+
+        wsClient.disconnect(true);
+
+        await userStore.logout();
+        
+      },
+
+    });
+
   }
   }
+
 };
 };
+
+
+
+watch(
+
+  () => userStore.getToken,
+
+  (token) => {
+
+    if (token) {
+
+      wsClient.connect(token);
+
+    } else {
+
+      wsClient.disconnect(true);
+
+    }
+
+  },
+
+  { immediate: true }
+
+);
+
+const initWebbsock = () => {
+
+}
+
+onMounted(() => {
+
+  const token = userStore.getToken;
+  console.log('token', token)
+  if (token) {
+
+    wsClient.connect(token);
+
+  }
+
+});
+
 </script>
 </script>
+
 <template>
 <template>
-  <div class="flex items-center justify-between px-10 bg-white h-21">
+
+  <div class="flex items-center justify-between px-10 bg-white h-21 haeder">
+
     <div class="haeder-left">
     <div class="haeder-left">
+
       <span v-if="route.name == 'sceneomore'" class="haeder-left-name">
       <span v-if="route.name == 'sceneomore'" class="haeder-left-name">
-        <span class="cursor-pointer font-route" @click="$router.push(type == 'laser'?'/sceneobj': '/scenemesh')">{{type == 'laser'?$t('scene.obj'):$t('scene.mesh')}}</span>
+
+        <span
+
+          class="cursor-pointer font-route"
+
+          @click="$router.push(type == 'laser' ? '/sceneobj' : '/scenemesh')"
+
+          >{{ type == "laser" ? $t("scene.obj") : $t("scene.mesh") }}</span
+
+        >
+
         <span class="font-fh">/</span>
         <span class="font-fh">/</span>
-        <span class="font-name">{{$t('scene.moreAction')}}</span>
+
+        <span class="font-name">{{ $t("scene.moreAction") }}</span>
+
       </span>
       </span>
+
     </div>
     </div>
+
     <div class="flex items-center gap-4">
     <div class="flex items-center gap-4">
-      <div class="cursor-pointer haeder-right-item">
+
+      <div
+
+        class="cursor-pointer haeder-right-item bell-wrap"
+
+        @click="handleBellClick"
+
+      >
+
         <BellOutlined />
         <BellOutlined />
+
+        <span v-if="notificationStore.hasUnread" class="bell-dot"></span>
+
       </div>
       </div>
 
 
+
+
       <div class="cursor-pointer haeder-right-item">
       <div class="cursor-pointer haeder-right-item">
+
         <QuestionCircleOutlined />
         <QuestionCircleOutlined />
+
       </div>
       </div>
 
 
+
+
       <div
       <div
+
         class="cursor-pointer haeder-right-item haeder-right-head"
         class="cursor-pointer haeder-right-item haeder-right-head"
+
         :class="{ vip: userStore.incrementNum }"
         :class="{ vip: userStore.incrementNum }"
+
         :style="{ 'background-image': `url(${userStore.head})` }"
         :style="{ 'background-image': `url(${userStore.head})` }"
+
         @click="$router.push('/information')"
         @click="$router.push('/information')"
-      >
-        <!-- <div class="user avatar"  /> -->
-      </div>
 
 
-      <a-dropdown v-model:open="visible" arrow placement="bottom">
+      ></div>
+
+
+
+      <a-dropdown v-model:open="visible" arrow placement="bottom" :overlayStyle="{minWidth: '100px', textAlign: 'center'}">
+
         <div class="flex items-center cursor-pointer">
         <div class="flex items-center cursor-pointer">
+
           <span class="mr-1">{{ userStore.nickName }}</span>
           <span class="mr-1">{{ userStore.nickName }}</span>
+
           <DownOutlined style="font-size: 10px" />
           <DownOutlined style="font-size: 10px" />
+
         </div>
         </div>
+
         <template #overlay>
         <template #overlay>
+
           <a-menu @click="handleMenuClick">
           <a-menu @click="handleMenuClick">
-            <a-menu-item key="1">{{ t('mall.myAccount') }}</a-menu-item>
-            <a-menu-item key="2">{{ t('mall.logOut') }}</a-menu-item>
+
+            <a-menu-item key="1">{{ t("mall.myAccount") }}</a-menu-item>
+
+            <a-menu-item key="2">{{ t("mall.logOut") }}</a-menu-item>
+
           </a-menu>
           </a-menu>
+
         </template>
         </template>
+
       </a-dropdown>
       </a-dropdown>
+
     </div>
     </div>
+
   </div>
   </div>
+
 </template>
 </template>
 
 
 
 
+
 <style lang="less" scoped>
 <style lang="less" scoped>
+
 .haeder {
 .haeder {
+
   font-weight: normal;
   font-weight: normal;
+
   font-size: 14px;
   font-size: 14px;
+
   color: #4e5969;
   color: #4e5969;
+
   .haeder-left {
   .haeder-left {
+
     font-weight: normal;
     font-weight: normal;
+
     font-size: 14px;
     font-size: 14px;
+
     color: #1d2129;
     color: #1d2129;
-    &-name{
+
+    &-name {
+
       font-weight: normal;
       font-weight: normal;
+
       font-size: 14px;
       font-size: 14px;
-      color: #4E5969;
-      .font-fh{
+
+      color: #4e5969;
+
+      .font-fh {
+
         margin: 0 4px;
         margin: 0 4px;
+
         user-select: none;
         user-select: none;
+
       }
       }
-      .font-name{
-        color: #1D2129;
+
+      .font-name {
+
+        color: #1d2129;
+
       }
       }
+
     }
     }
+
   }
   }
+
   .haeder-right-item {
   .haeder-right-item {
+
     width: 32px;
     width: 32px;
+
     height: 32px;
     height: 32px;
+
     line-height: 32px;
     line-height: 32px;
+
     background: #f2f3f5;
     background: #f2f3f5;
+
     border-radius: 18px;
     border-radius: 18px;
+
     text-align: center;
     text-align: center;
+
   }
   }
+
+  .bell-wrap {
+
+    position: relative;
+
+  }
+
+  .bell-dot {
+
+    position: absolute;
+
+    top: 4px;
+
+    right: 4px;
+
+    width: 8px;
+
+    height: 8px;
+
+    background: #f53f3f;
+
+    border-radius: 50%;
+
+    border: 1px solid #fff;
+
+    pointer-events: none;
+
+  }
+
   .haeder-right-head {
   .haeder-right-head {
+
     border: 1px solid #efefef;
     border: 1px solid #efefef;
+
     background: no-repeat center/cover;
     background: no-repeat center/cover;
+
   }
   }
+
   .vip {
   .vip {
+
     border-color: #d8af7c;
     border-color: #d8af7c;
+
   }
   }
+
 }
 }
-</style>
+
+</style>
+
+

+ 9 - 1
src/layouts/menu.vue

@@ -19,6 +19,10 @@
           @click="handleClick"
           @click="handleClick"
         ></a-menu>
         ></a-menu>
       </div>
       </div>
+      <div class="cursor-pointer" style="padding: 10px 36px" @click="oldItem">
+        <i class="iconfont icon-common_sidebar_legacy"></i>
+        <span style="margin-left: 10px; font-size: 14px">返回旧版</span>
+      </div>
     </div>
     </div>
   </div>
   </div>
 </template>
 </template>
@@ -34,7 +38,11 @@ const { t } = useI18n()
 const router = useRouter()
 const router = useRouter()
 const route = useRoute()
 const route = useRoute()
 const userStore = useUserStore()
 const userStore = useUserStore()
-
+const oldItem = () => {
+const pathname = ref(import.meta.env.VITE_PATH || window.location.pathname)
+console.log('pathname', pathname)
+window.open(pathname.value)
+}
 /** 拼接第三方/相对路径为完整 URL */
 /** 拼接第三方/相对路径为完整 URL */
 const resolveLink = (link) => {
 const resolveLink = (link) => {
   if (!link) return ''
   if (!link) return ''

+ 4 - 0
src/locales/en.json

@@ -1109,6 +1109,10 @@
     "contactPhone": "Contact Phone",
     "contactPhone": "Contact Phone",
     "electronicOption": "VAT General Invoice (Electronic)"
     "electronicOption": "VAT General Invoice (Electronic)"
   },
   },
+  "notification": {
+    "sceneComputeDoneTitle": "Scene Calculation Completed",
+    "sceneComputeDoneDesc": "Scene \"{title}\" is ready. You can view it now."
+  },
   "common": {
   "common": {
     "tip": "Notice",
     "tip": "Notice",
     "search": "Search",
     "search": "Search",

+ 4 - 0
src/locales/zh.json

@@ -1112,6 +1112,10 @@
     "contactPhone": "联系电话",
     "contactPhone": "联系电话",
     "electronicOption": "增值税普票(电子发票)"
     "electronicOption": "增值税普票(电子发票)"
   },
   },
+  "notification": {
+    "sceneComputeDoneTitle": "场景计算完成",
+    "sceneComputeDoneDesc": "场景「{title}」已计算完成,可前往查看"
+  },
   "common": {
   "common": {
     "tip": "提示",
     "tip": "提示",
     "search": "搜索",
     "search": "搜索",

+ 1 - 0
src/stores/index.js

@@ -3,3 +3,4 @@ export { useUserStore } from './user'
 export { useCartStore } from './cart'
 export { useCartStore } from './cart'
 export { useOrderStore } from './order'
 export { useOrderStore } from './order'
 export { useSceneStore } from './scene'
 export { useSceneStore } from './scene'
+export { useNotificationStore } from './notification'

+ 17 - 0
src/stores/notification.js

@@ -0,0 +1,17 @@
+import { defineStore } from 'pinia'
+
+export const useNotificationStore = defineStore('notification', {
+  state: () => ({
+    hasUnread: false,
+    latestMessage: null,
+  }),
+  actions: {
+    markUnread(payload) {
+      this.hasUnread = true
+      this.latestMessage = payload
+    },
+    clearUnread() {
+      this.hasUnread = false
+    },
+  },
+})

+ 17 - 0
src/utils/index.js

@@ -1,3 +1,5 @@
+import router from '@/router'
+
 export function autoFormatKbSplit(kb, fixed = 1) {
 export function autoFormatKbSplit(kb, fixed = 1) {
   if (!kb || kb <= 0) return;
   if (!kb || kb <= 0) return;
   const units = ['B', 'KB', 'MB', 'GB', 'TB'];
   const units = ['B', 'KB', 'MB', 'GB', 'TB'];
@@ -39,4 +41,19 @@ export function downloadSceneURL(url) {
   iframe.style.display = 'none'
   iframe.style.display = 'none'
   iframe.src = "javascript: '<script>location.href=\"" + url + "\"<\/script>'"
   iframe.src = "javascript: '<script>location.href=\"" + url + "\"<\/script>'"
   document.getElementsByTagName('body')[0].appendChild(iframe)
   document.getElementsByTagName('body')[0].appendChild(iframe)
+}
+
+/**
+ * 路由跳转区分内外链
+ * @param url 跳转地址
+ * @param target 窗口打开方式
+ */
+
+export function jump(url, target = '_blank') {
+  const externalReg = /^http(s)?:\/\//
+  if (externalReg.test(url)) {
+    window.open(url, target)
+    return
+  }
+  router.push(url)
 }
 }

+ 164 - 0
src/utils/wsClient.js

@@ -0,0 +1,164 @@
+import { notification } from 'ant-design-vue'
+import i18n from '@/locales'
+import router from '@/router'
+import { useNotificationStore } from '@/stores/notification'
+
+const PING_INTERVAL = 10000
+const RECONNECT_DELAY = 5000
+
+function resolveCallType(callType) {
+  if (Array.isArray(callType)) return callType[0] || 'mesh'
+  return callType || 'mesh'
+}
+
+function getWsUrl(token) {
+  const path = import.meta.env.VITE_PATH || import.meta.env.VITE_API_BASE_URL || ''
+  let host = window.location.host
+
+  if (path) {
+    try {
+      host = new URL(path).host
+    } catch {
+      // keep current host
+    }
+  }
+
+  const protocol = import.meta.env.DEV || path.startsWith('https') || window.location.protocol === 'https:'
+    ? 'wss:'
+    : 'ws:'
+
+  return `${protocol}//${host}/ucenter/ws/${encodeURIComponent(token)}`
+}
+
+class WsClient {
+  ws = null
+  pingTimer = null
+  reconnectTimer = null
+  manualClose = false
+  currentToken = ''
+
+  connect(token) {
+    if (!token) return
+    if (this.currentToken === token && this.ws?.readyState === WebSocket.OPEN) return
+
+    this.disconnect(true)
+    this.currentToken = token
+    this.manualClose = false
+
+    try {
+      this.ws = new WebSocket(getWsUrl(token))
+    } catch (err) {
+      console.error('[ws] connect failed', err)
+      this.scheduleReconnect()
+      return
+    }
+
+    this.ws.onopen = () => {
+      this.startPing()
+    }
+
+    this.ws.onmessage = (event) => {
+      try {
+        const message = JSON.parse(event.data)
+        this.handleMessage(message)
+      } catch (err) {
+        console.error('[ws] parse message failed', err)
+      }
+    }
+
+    this.ws.onclose = () => {
+      this.stopPing()
+      if (!this.manualClose) {
+        this.scheduleReconnect()
+      }
+    }
+
+    this.ws.onerror = () => {
+      this.stopPing()
+      this.ws?.close()
+    }
+  }
+
+  handleMessage(message) {
+    const { command, content } = message || {}
+    if (command === 'open' || command === 'pong') return
+
+    if (command === 'scene_compute_done') {
+      const data = content?.data || {}
+      const notificationStore = useNotificationStore()
+      notificationStore.markUnread(data)
+
+      const { t } = i18n.global
+      const key = `scene_compute_done_${data.num || ''}_${Date.now()}`
+      notification.open({
+        key,
+        message: t('notification.sceneComputeDoneTitle'),
+        description: t('notification.sceneComputeDoneDesc', {
+          title: data.title || data.num || '',
+        }),
+        duration: 0,
+        onClick: () => {
+          const type = resolveCallType(data.callType)
+          const num = data.num
+          if (num) {
+            router.push({ path: `/sceneomore/${type}/${num}` })
+          }
+          notification.close(key)
+          notificationStore.clearUnread()
+        },
+      })
+    }
+  }
+
+  sendPing() {
+    if (this.ws?.readyState !== WebSocket.OPEN) return
+    this.ws.send(JSON.stringify({ command: 'ping', content: {} }))
+  }
+
+  startPing() {
+    this.stopPing()
+    this.sendPing()
+    this.pingTimer = setInterval(() => this.sendPing(), PING_INTERVAL)
+  }
+
+  stopPing() {
+    if (this.pingTimer) {
+      clearInterval(this.pingTimer)
+      this.pingTimer = null
+    }
+  }
+
+  scheduleReconnect() {
+    if (this.reconnectTimer || !this.currentToken || this.manualClose) return
+    this.reconnectTimer = setTimeout(() => {
+      this.reconnectTimer = null
+      if (!this.currentToken || this.manualClose) return
+      this.connect(this.currentToken)
+    }, RECONNECT_DELAY)
+  }
+
+  disconnect(resetToken = false) {
+    this.manualClose = true
+    this.stopPing()
+    if (this.reconnectTimer) {
+      clearTimeout(this.reconnectTimer)
+      this.reconnectTimer = null
+    }
+    if (this.ws) {
+      this.ws.close()
+      this.ws = null
+    }
+    if (resetToken) {
+      this.currentToken = ''
+    }
+  }
+}
+
+let client = null
+
+export function getWsClient() {
+  if (!client) {
+    client = new WsClient()
+  }
+  return client
+}

+ 1 - 1
src/views/account/components/aside.vue

@@ -203,7 +203,7 @@ onUnmounted(() => {
             }
             }
           }
           }
           .primary {
           .primary {
-            background: @primary-color;
+            background: var(--account-primary-color);
             color: #fff;
             color: #fff;
             border-radius: 4px;
             border-radius: 4px;
           }
           }

+ 33 - 24
src/views/account/index.vue

@@ -1,43 +1,52 @@
 <script setup>
 <script setup>
 import loginHeader from "./components/header.vue";
 import loginHeader from "./components/header.vue";
-import { useRouter, useRoute } from 'vue-router'
+import { useRouter, useRoute } from "vue-router";
 import { useI18n } from "vue-i18n";
 import { useI18n } from "vue-i18n";
+import { ACCOUNT_PRIMARY_COLOR, accountTheme } from "./theme";
 
 
 const { t } = useI18n();
 const { t } = useI18n();
-const router = useRouter()
-const route = useRoute()
-console.log(route)
+const router = useRouter();
+const route = useRoute();
+
 const toOtherLogin = () => {
 const toOtherLogin = () => {
-  console.log(route)
-  if(route.name == 'login'){
-    router.push({name:'QrCode'})
-    return
-  }else{
-    router.push({name:'login'})
+  if (route.name == "login") {
+    router.push({ name: "QrCode" });
+    return;
   }
   }
-}
+  router.push({ name: "login" });
+};
 </script>
 </script>
 <template>
 <template>
-  <div class="account-layout">
-    <loginHeader class="h-20 container " />
-    <div class="account-container container mt-20">
-      <div class="loginContentdiv">
-        <div class="loginTitle" style="top: 20%">
-          <div class="name">{{ t('accountPage.platformDesc') }}</div>
-          <div class="text">{{ t('accountPage.platformSubDesc') }}</div>
-        </div>
-        <div class="login-container">
+  <a-config-provider :theme="accountTheme">
+    <div
+      class="account-layout"
+      :style="{ '--account-primary-color': ACCOUNT_PRIMARY_COLOR }"
+    >
+      <loginHeader class="h-20 container" />
+      <div class="account-container container mt-20">
+        <div class="loginContentdiv">
+          <div class="loginTitle" style="top: 20%">
+            <div class="name">{{ t("accountPage.platformDesc") }}</div>
+            <div class="text">{{ t("accountPage.platformSubDesc") }}</div>
+          </div>
+          <div class="login-container">
             <div class="change">
             <div class="change">
-              <img @click="toOtherLogin" class="typeImg" :src="`${$cdn}images/newLogin/${route.name === 'QrCode'?'login_account.svg':'login_code.svg'}`" alt="">
+              <img
+                @click="toOtherLogin"
+                class="typeImg"
+                :src="`${$cdn}images/newLogin/${route.name === 'QrCode' ? 'login_account.svg' : 'login_code.svg'}`"
+                alt=""
+              />
             </div>
             </div>
             <div class="login-title">
             <div class="login-title">
-              {{ t('accountPage.platformTitle') }}
+              {{ t("accountPage.platformTitle") }}
             </div>
             </div>
             <router-view />
             <router-view />
+          </div>
         </div>
         </div>
       </div>
       </div>
     </div>
     </div>
-  </div>
+  </a-config-provider>
 </template>
 </template>
 <style lang="less" scoped>
 <style lang="less" scoped>
 .account-layout {
 .account-layout {
@@ -112,7 +121,7 @@ const toOtherLogin = () => {
         border-width: 0 72px 72px 0;
         border-width: 0 72px 72px 0;
         border-style: solid;
         border-style: solid;
         /* 右下三角形:上、左透明,右、下为主题色 */
         /* 右下三角形:上、左透明,右、下为主题色 */
-        border-color: transparent @primary-color transparent transparent;
+        border-color: transparent var(--account-primary-color) transparent transparent;
         border-radius: 0 10px 0 0;
         border-radius: 0 10px 0 0;
       }
       }
       .typeImg{
       .typeImg{

+ 10 - 8
src/views/account/login.vue

@@ -40,10 +40,10 @@ const formRules = computed(() => ({
     {
     {
       validator: async (_rule, value) => {
       validator: async (_rule, value) => {
         if (!value) return Promise.resolve();
         if (!value) return Promise.resolve();
-        const res = await checkSms(value);
-        if (res.code !== 0) {
-          return Promise.reject(t("toast.3006"));
-        }
+        // const res = await checkSms(value);
+        // if (res.code !== 0) {
+        //   return Promise.reject(t("toast.3006"));
+        // }
         return Promise.resolve();
         return Promise.resolve();
       },
       },
       trigger: "blur",
       trigger: "blur",
@@ -250,7 +250,8 @@ const switchLoginType = (loginType) => {
         </a-input>
         </a-input>
       </a-form-item>
       </a-form-item>
       <a-form-item>
       <a-form-item>
-        <a-button class="login-btn w-full" type="primary" html-type="submit">{{
+        <a-button class="login-btn w-full" 
+      :style="{ 'background': ACCOUNT_PRIMARY_COLOR }" type="primary" style="ba" html-type="submit">{{
           $t("login.login")
           $t("login.login")
         }}</a-button>
         }}</a-button>
       </a-form-item>
       </a-form-item>
@@ -268,15 +269,16 @@ const switchLoginType = (loginType) => {
   .login-btn {
   .login-btn {
     margin: 51px 0 0;
     margin: 51px 0 0;
     height: 40px;
     height: 40px;
+    background: var(--account-primary-color);
   }
   }
   .registerTip {
   .registerTip {
     padding-top: 4px;
     padding-top: 4px;
     span {
     span {
-      color: @primary-color;
+      color: var(--account-primary-color);
     }
     }
   }
   }
   .code-btn {
   .code-btn {
-    color: @primary-color;
+    color: var(--account-primary-color);
   }
   }
   .areaCode {
   .areaCode {
     position: relative;
     position: relative;
@@ -298,7 +300,7 @@ const switchLoginType = (loginType) => {
     font-size: 16px;
     font-size: 16px;
     color: #333333;
     color: #333333;
     font-weight: bold;
     font-weight: bold;
-    border-bottom: 2px solid @primary-color;
+    border-bottom: 2px solid var(--account-primary-color);
   }
   }
 }
 }
 </style>
 </style>

+ 4 - 4
src/views/account/qrcode.vue

@@ -84,17 +84,17 @@ onUnmounted(() => {
   }
   }
   .registerTip {
   .registerTip {
     span {
     span {
-      color: @primary-color;
+      color: var(--account-primary-color);
     }
     }
   }
   }
   .code-btn {
   .code-btn {
-    color: @primary-color;
+    color: var(--account-primary-color);
   }
   }
   .areaCode {
   .areaCode {
     position: relative;
     position: relative;
   }
   }
   .qrcodeTips {
   .qrcodeTips {
-    padding: 19px 0 0;
+    padding: 30px 0 0;
     line-height: 20px;
     line-height: 20px;
     font-family: PingFang SC;
     font-family: PingFang SC;
     font-weight: 400;
     font-weight: 400;
@@ -120,7 +120,7 @@ onUnmounted(() => {
     font-size: 16px;
     font-size: 16px;
     color: #333333;
     color: #333333;
     font-weight: bold;
     font-weight: bold;
-    border-bottom: 2px solid @primary-color;
+    border-bottom: 2px solid var(--account-primary-color);
   }
   }
 }
 }
 </style>
 </style>

+ 4 - 3
src/views/account/register.vue

@@ -271,14 +271,15 @@ const handleProtocol = () => {
   .login-btn {
   .login-btn {
     margin: 20px 0 0;
     margin: 20px 0 0;
     height: 40px;
     height: 40px;
+    background: var(--account-primary-color);
   }
   }
   .registerTip {
   .registerTip {
     span {
     span {
-      color: @primary-color;
+      color: var(--account-primary-color);
     }
     }
   }
   }
   .code-btn {
   .code-btn {
-    color: @primary-color;
+    color: var(--account-primary-color);
   }
   }
   .areaCode {
   .areaCode {
     position: relative;
     position: relative;
@@ -300,7 +301,7 @@ const handleProtocol = () => {
     font-size: 16px;
     font-size: 16px;
     color: #333333;
     color: #333333;
     font-weight: bold;
     font-weight: bold;
-    border-bottom: 2px solid @primary-color;
+    border-bottom: 2px solid var(--account-primary-color);
   }
   }
 }
 }
 </style>
 </style>

+ 8 - 0
src/views/account/theme.js

@@ -0,0 +1,8 @@
+/** 登录模块独立主题色,不影响全局 #3275FF */
+export const ACCOUNT_PRIMARY_COLOR = '#15BEC8'
+
+export const accountTheme = {
+  token: {
+    colorPrimary: '#3275FF',
+  },
+}

+ 0 - 13
src/views/device/data.ts

@@ -63,19 +63,6 @@ export enum SceneType {
   SWSX,
   SWSX,
 }
 }
 
 
-export const SceneTypePaths = {
-  [SceneType.SWKK]: [
-    "/swkk/spg.html",
-    "/swkk/epg.html",
-  ],
-  [SceneType.SWKJ]: ["/swkk/spg.html", "/swkk/epg.html"],
-  [SceneType.SWSS]: ["/swss/index.html", "/swss/index.html"],
-  [SceneType.SWSX]: ["/swss/index.html", "/swss/index.html"],
-  [SceneType.SWMX]: ["/dev-code/index.html", "/dev-code/index.html"],
-  [SceneType.SWSSMX]: ["/swkk/spg.html", "/swkk/epg.html"],
-  [SceneType.SWYDSS]: ["/swss/index.html", "/swss/index.html"],
-  [SceneType.SWYDMX]: ["/swkk/spg.html", "/swkk/epg.html"],
-};
 export const getCameraType = [
 export const getCameraType = [
   { value: null, label: t("common.all") },
   { value: null, label: t("common.all") },
   { value: CameraType.SWKK, label: t("camera.device."+CameraType.SWKK) },
   { value: CameraType.SWKK, label: t("camera.device."+CameraType.SWKK) },

+ 0 - 13
src/views/equity/data.ts

@@ -68,19 +68,6 @@ export enum SceneType {
   SWSX,
   SWSX,
 }
 }
 
 
-export const SceneTypePaths = {
-  [SceneType.SWKK]: [
-    "/swkk/spg.html",
-    "/swkk/epg.html",
-  ],
-  [SceneType.SWKJ]: ["/swkk/spg.html", "/swkk/epg.html"],
-  [SceneType.SWSS]: ["/swss/index.html", "/swss/index.html"],
-  [SceneType.SWSX]: ["/swss/index.html", "/swss/index.html"],
-  [SceneType.SWMX]: ["/dev-code/index.html", "/dev-code/index.html"],
-  [SceneType.SWSSMX]: ["/swkk/spg.html", "/swkk/epg.html"],
-  [SceneType.SWYDSS]: ["/swss/index.html", "/swss/index.html"],
-  [SceneType.SWYDMX]: ["/swkk/spg.html", "/swkk/epg.html"],
-};
 export const getdownType = [
 export const getdownType = [
   { value: null, label: t("common.all") },
   { value: null, label: t("common.all") },
   { value: 'sub', label: '使用'  },
   { value: 'sub', label: '使用'  },

+ 3 - 2
src/views/home/components/notice.vue

@@ -2,13 +2,14 @@
 import { RightOutlined } from "@ant-design/icons-vue";
 import { RightOutlined } from "@ant-design/icons-vue";
 import { computed } from "vue";
 import { computed } from "vue";
 import { useI18n } from "vue-i18n";
 import { useI18n } from "vue-i18n";
+import { jump } from '@/utils/index'
 
 
 const { t } = useI18n();
 const { t } = useI18n();
 
 
 const notice = computed(() => ({
 const notice = computed(() => ({
   title: t("homePage.noticeTitle"),
   title: t("homePage.noticeTitle"),
   content: t("homePage.noticeContent"),
   content: t("homePage.noticeContent"),
-  path: "/home/scene/pointcloud",
+  path: "https://support.4dkankan.com/showdoc/51",
 }));
 }));
 </script>
 </script>
 
 
@@ -17,7 +18,7 @@ const notice = computed(() => ({
     <div class="notice-title text-white">{{ notice.title }}</div>
     <div class="notice-title text-white">{{ notice.title }}</div>
     <div
     <div
       class="notice-content flex justify-between items-center cursor-pointer"
       class="notice-content flex justify-between items-center cursor-pointer"
-      @click="$router.push(notice.path)"
+      @click="jump(notice.path)"
     >
     >
       <div class="text-black">{{ notice.content }}</div>
       <div class="text-black">{{ notice.content }}</div>
       <RightOutlined style="font-size: 10px; color: #4e5969" />
       <RightOutlined style="font-size: 10px; color: #4e5969" />

+ 12 - 12
src/views/home/index.vue

@@ -63,16 +63,16 @@ const allEquityList = computed(() =>
 const equityList = ref([])
 const equityList = ref([])
 
 
 const loadEquityList = async () => {
 const loadEquityList = async () => {
-  const list = allEquityList.value
-  try {
-    const userList = await userSerciceList()
-    const showPanorama = hasPanoramaUserService(userList)
-    equityList.value = list.filter(
-      (item) => item.id !== PANORAMA_SERVICE_ID || showPanorama
-    )
-  } catch {
-    equityList.value = list.filter((item) => item.id !== PANORAMA_SERVICE_ID)
-  }
+  equityList.value = allEquityList.value
+  // try {
+  //   const userList = await userSerciceList()
+  //   const showPanorama = hasPanoramaUserService(userList)
+  //   equityList.value = list.filter(
+  //     (item) => item.id !== PANORAMA_SERVICE_ID || showPanorama
+  //   )
+  // } catch {
+  //   equityList.value = list.filter((item) => item.id !== PANORAMA_SERVICE_ID)
+  // }
 }
 }
 
 
 onMounted(loadEquityList)
 onMounted(loadEquityList)
@@ -92,7 +92,7 @@ const handleServes = async (item) => {
   <div class="layout-home" style="padding-bottom: 60px">
   <div class="layout-home" style="padding-bottom: 60px">
     <homeNotice />
     <homeNotice />
     <div class="flex gap-10 equityServer">
     <div class="flex gap-10 equityServer">
-      <div class="flex-1 equity">
+      <div class="flex-2 equity">
         <div class="title">{{ $t('homePage.myEquity') }}</div>
         <div class="title">{{ $t('homePage.myEquity') }}</div>
         <div class="flex gap-4 list">
         <div class="flex gap-4 list">
           <div class="flex-1 cursor-pointer member-item" @click="$router.push('/equity')">
           <div class="flex-1 cursor-pointer member-item" @click="$router.push('/equity')">
@@ -123,7 +123,7 @@ const handleServes = async (item) => {
           </div>
           </div>
         </div>
         </div>
       </div>
       </div>
-      <div class="equity flex-2">
+      <div class="equity flex-3">
         <div class="flex items-center justify-between title">
         <div class="flex items-center justify-between title">
           <span>{{ $t('mall.valueAddedTitle') }}</span>
           <span>{{ $t('mall.valueAddedTitle') }}</span>
           <span class="text-sm text-blue-500 cursor-pointer" @click="$router.push('/mall')">{{ $t('homePage.viewMore') }}</span>
           <span class="text-sm text-blue-500 cursor-pointer" @click="$router.push('/mall')">{{ $t('homePage.viewMore') }}</span>

+ 0 - 13
src/views/information/data.ts

@@ -61,19 +61,6 @@ export enum SceneType {
   SWSX,
   SWSX,
 }
 }
 
 
-export const SceneTypePaths = {
-  [SceneType.SWKK]: [
-    "/swkk/spg.html",
-    "/swkk/epg.html",
-  ],
-  [SceneType.SWKJ]: ["/swkk/spg.html", "/swkk/epg.html"],
-  [SceneType.SWSS]: ["/swss/index.html", "/swss/index.html"],
-  [SceneType.SWSX]: ["/swss/index.html", "/swss/index.html"],
-  [SceneType.SWMX]: ["/dev-code/index.html", "/dev-code/index.html"],
-  [SceneType.SWSSMX]: ["/swkk/spg.html", "/swkk/epg.html"],
-  [SceneType.SWYDSS]: ["/swss/index.html", "/swss/index.html"],
-  [SceneType.SWYDMX]: ["/swkk/spg.html", "/swkk/epg.html"],
-};
 export const getCameraType = [
 export const getCameraType = [
   { value: null, label: t("common.all") },
   { value: null, label: t("common.all") },
   { value: CameraType.SWKK, label: t("camera.device."+CameraType.SWKK) },
   { value: CameraType.SWKK, label: t("camera.device."+CameraType.SWKK) },

+ 1 - 30
src/views/information/index.vue

@@ -17,14 +17,6 @@ import BaseTable from "@/components/BaseTable/index.vue";
 import info from "./components/info.vue";
 import info from "./components/info.vue";
 import { useCartStore } from "@/stores";
 import { useCartStore } from "@/stores";
 import brandInfo from "./components/brandInfo.vue";
 import brandInfo from "./components/brandInfo.vue";
-import {
-  equityColumns,
-  downColumns,
-  getStatusImg,
-  getStatusText,
-  SceneTypePaths,
-  getCameraType,
-} from "./data";
 const { t } = useI18n();
 const { t } = useI18n();
 const router = useRouter();
 const router = useRouter();
 const cart = useCartStore();
 const cart = useCartStore();
@@ -88,28 +80,7 @@ const getList = async ({ pageNum, pageSize }) => {
 const searchClick = () => {
 const searchClick = () => {
   baseTableRef.value.resetPage();
   baseTableRef.value.resetPage();
 };
 };
-const handleItem = (record, item) => {
-  switch (record.key) {
-    case "more":
-      router.push({ path: "/sceneomore/obj/" + item.num });
-      break;
-    case "collaborativeScene":
-      handleEditItem(record);
-      break;
-  }
-  console.log(record, "handleItem", record, item);
-};
-const handleSee = (record) => {
-  let path = SceneTypePaths[record.sceneSource];
-  window.open(path[0], "_blank");
-};
-const handleEditItem = (record) => {
-  if(record.tbType == 'f'){// 修改文件夹
-    return handleRename(record)
-  }
-  let path = SceneTypePaths[record.sceneSource];
-  window.open(path[1], "_blank");
-};
+
 const hendleCooperation = () => {
 const hendleCooperation = () => {
   const isNorn =  selectTable.value.some((item) => item.status == 2 || item.status == 0);
   const isNorn =  selectTable.value.some((item) => item.status == 2 || item.status == 0);
   console.log(isNorn, 'isNorn')
   console.log(isNorn, 'isNorn')

+ 1 - 13
src/views/order/data.ts

@@ -63,19 +63,7 @@ export enum SceneType {
   SWSX,
   SWSX,
 }
 }
 
 
-export const SceneTypePaths = {
-  [SceneType.SWKK]: [
-    "/swkk/spg.html",
-    "/swkk/epg.html",
-  ],
-  [SceneType.SWKJ]: ["/swkk/spg.html", "/swkk/epg.html"],
-  [SceneType.SWSS]: ["/swss/index.html", "/swss/index.html"],
-  [SceneType.SWSX]: ["/swss/index.html", "/swss/index.html"],
-  [SceneType.SWMX]: ["/dev-code/index.html", "/dev-code/index.html"],
-  [SceneType.SWSSMX]: ["/swkk/spg.html", "/swkk/epg.html"],
-  [SceneType.SWYDSS]: ["/swss/index.html", "/swss/index.html"],
-  [SceneType.SWYDMX]: ["/swkk/spg.html", "/swkk/epg.html"],
-};
+
 export const getOrderType = [
 export const getOrderType = [
   // { value: null, label: t("common.all") },
   // { value: null, label: t("common.all") },
   { value: 0, label: t("mall.member.memberTitle") },
   { value: 0, label: t("mall.member.memberTitle") },

+ 7 - 2
src/views/scene/components/cooperation.vue

@@ -45,7 +45,12 @@ import dayjs from 'dayjs'
 
 
 const { t } = useI18n();
 const { t } = useI18n();
 const visible = ref(false);
 const visible = ref(false);
-
+const props = defineProps({
+  type: {
+    type: String,
+    default: 'laser'
+  },
+})
 const columns = computed(() => [
 const columns = computed(() => [
   {
   {
     title: t('scene.cooperationModal.account'),
     title: t('scene.cooperationModal.account'),
@@ -75,7 +80,7 @@ const columns = computed(() => [
 
 
 const data = ref([]);
 const data = ref([]);
 const apiData = ref({
 const apiData = ref({
-  type: 'laser',
+  type: props.type || 'laser',
   userNameList: [],
   userNameList: [],
   sceneNum: '',
   sceneNum: '',
   cameraId: '',
   cameraId: '',

+ 7 - 1
src/views/scene/components/moveSceneModal.vue

@@ -75,11 +75,17 @@ import {
   CloseOutlined
   CloseOutlined
 } from '@ant-design/icons-vue'
 } from '@ant-design/icons-vue'
 
 
+const props = defineProps({
+  type: {
+    type: String,
+    default: 'laser'
+  },
+})
 const { t } = useI18n();
 const { t } = useI18n();
 const visible = ref(false)
 const visible = ref(false)
 const editInputRef = ref(null)
 const editInputRef = ref(null)
 const apiData = ref({
 const apiData = ref({
-  type: 'laser',
+  type: props.type || 'laser',
   folderIdList: [],
   folderIdList: [],
   numList: [],
   numList: [],
   parentId: ''
   parentId: ''

+ 10 - 9
src/views/scene/data.ts

@@ -72,18 +72,19 @@ export enum SceneType {
   SWSX,
   SWSX,
 }
 }
 
 
+const laserUrl = import.meta.env.VITE_LASER_URL
 export const SceneTypePaths = {
 export const SceneTypePaths = {
   [SceneType.SWKK]: [
   [SceneType.SWKK]: [
-    "/swkk/spg.html",
-    "/swkk/epg.html",
+    "/spg.htm",
+    "/epg.html",
   ],
   ],
-  [SceneType.SWKJ]: ["/swkk/spg.html", "/swkk/epg.html"],
-  [SceneType.SWSS]: ["/swss/index.html", "/swss/index.html"],
-  [SceneType.SWSX]: ["/swss/index.html", "/swss/index.html"],
+  [SceneType.SWKJ]: ["/spg.html", "/epg.html"],
+  [SceneType.SWSS]: [laserUrl + "/index.html", laserUrl + "/index.html"],
+  [SceneType.SWSX]: [laserUrl + "/index.html", laserUrl + "/index.html"],
   [SceneType.SWMX]: ["/dev-code/index.html", "/dev-code/index.html"],
   [SceneType.SWMX]: ["/dev-code/index.html", "/dev-code/index.html"],
-  [SceneType.SWSSMX]: ["/swkk/spg.html", "/swkk/epg.html"],
-  [SceneType.SWYDSS]: ["/swss/index.html", "/swss/index.html"],
-  [SceneType.SWYDMX]: ["/swkk/spg.html", "/swkk/epg.html"],
+  [SceneType.SWSSMX]: ["/spg.html", "/epg.html"],
+  [SceneType.SWYDSS]: [laserUrl + "/index.html", laserUrl + "/index.html"],
+  [SceneType.SWYDMX]: ["/spg.html", "/epg.html"],
 };
 };
 export const getCameraType = [
 export const getCameraType = [
   { value: null, label: t("common.all") },
   { value: null, label: t("common.all") },
@@ -91,5 +92,5 @@ export const getCameraType = [
   { value: CameraType.SWKJ, label: t("camera.device."+CameraType.SWKJ) },
   { value: CameraType.SWKJ, label: t("camera.device."+CameraType.SWKJ) },
   { value: CameraType.SWSS, label: t("camera.device."+CameraType.SWSS)  },
   { value: CameraType.SWSS, label: t("camera.device."+CameraType.SWSS)  },
   { value: CameraType.SWSX, label: t("camera.device."+CameraType.SWSX)  },
   { value: CameraType.SWSX, label: t("camera.device."+CameraType.SWSX)  },
-  { value: 0, label: t("common.myUpload")  },
+  { value: 57, label: t("common.myUpload")  },
 ]
 ]

+ 10 - 8
src/views/scene/mesh.vue

@@ -20,6 +20,8 @@ import {
   objColumns,
   objColumns,
   getStatusImg,
   getStatusImg,
   getStatusText,
   getStatusText,
+  getCameraType,
+  SceneTypePaths,
 } from "./data";
 } from "./data";
 const { t } = useI18n();
 const { t } = useI18n();
 const router = useRouter();
 const router = useRouter();
@@ -53,7 +55,7 @@ const folderId = ref(null);
 const folderPath = ref([
 const folderPath = ref([
   {
   {
     name: t("scene.gml"),
     name: t("scene.gml"),
-    id: 0,
+    id: null,
     index: 0,
     index: 0,
   },
   },
 ]);
 ]);
@@ -101,7 +103,7 @@ const getList = async ({ pageNum, pageSize, current }) => {
     title: (search.value.type == "name" && search.value.key) || "",
     title: (search.value.type == "name" && search.value.key) || "",
     sn: (search.value.type == "sn" && search.value.key) || "",
     sn: (search.value.type == "sn" && search.value.key) || "",
     num: (search.value.type == "num" && search.value.key) || "",
     num: (search.value.type == "num" && search.value.key) || "",
-    // folderId: folderId.value,
+    folderId: folderId.value,
     labType: activeKey.value,
     labType: activeKey.value,
     cameraType: cameraType.value,
     cameraType: cameraType.value,
   };
   };
@@ -212,7 +214,7 @@ const handleLivestream = async (item) => {
 };
 };
 const handleSee = (record) => {
 const handleSee = (record) => {
   let path = SceneTypePaths[record.sceneSource];
   let path = SceneTypePaths[record.sceneSource];
-  window.open(path[0], "_blank");
+  window.open(path[0] + `?m=${record.num}`, "_blank");
 };
 };
 const generateApi = async (num) => {
 const generateApi = async (num) => {
   await buildSceneObj({num});
   await buildSceneObj({num});
@@ -225,7 +227,7 @@ const handleEditItem = (record) => {
     return handleRename(record);
     return handleRename(record);
   }
   }
   let path = SceneTypePaths[record.sceneSource];
   let path = SceneTypePaths[record.sceneSource];
-  window.open(path[1], "_blank");
+  window.open(path[1] + `?m=${record.num}&token=${userStore.token}`, "_blank");
 };
 };
 const hendleCooperation = (item) => {
 const hendleCooperation = (item) => {
   console.log("handleFolder", selectTable.value);
   console.log("handleFolder", selectTable.value);
@@ -469,7 +471,7 @@ onMounted(() => {
               <img
               <img
                 v-if="record.tbType == 'f'"
                 v-if="record.tbType == 'f'"
                 @click.stop="handleFolderItem(record)"
                 @click.stop="handleFolderItem(record)"
-                src="/src/assets/image/scene/folder.png"
+                :src="record.sceneNum != 0 ? '/src/assets/image/scene/folder.png': '/src/assets/image/scene/nofolder.png'"
                 alt=""
                 alt=""
                 class="w-32 mr-2 Folder h-22"
                 class="w-32 mr-2 Folder h-22"
               />
               />
@@ -578,9 +580,9 @@ onMounted(() => {
       </BaseTable>
       </BaseTable>
     </div>
     </div>
     <div class="moadl">
     <div class="moadl">
-      <cooperation ref="cooperationRef" />
-      <uploadModal isObj="0" ref="uploadModalRef" @refresh="handleUploadSuccess" />
-      <moveSceneModal ref="moveModalRef" @refresh="baseTableRef?.refresh" />
+      <cooperation ref="cooperationRef"  type="mesh" />
+      <uploadModal isObj="0"  ref="uploadModalRef" @refresh="handleUploadSuccess" />
+      <moveSceneModal type="mesh" ref="moveModalRef" @refresh="baseTableRef?.refresh" />
       <renameModal
       <renameModal
         v-model:visible="reName.show"
         v-model:visible="reName.show"
         :item="reName.item"
         :item="reName.item"

+ 9 - 6
src/views/scene/obj.vue

@@ -15,15 +15,18 @@ import cooperation from "./components/cooperation.vue";
 import uploadModal from "./components/uploadModal.vue";
 import uploadModal from "./components/uploadModal.vue";
 import moveSceneModal from "./components/moveSceneModal.vue";
 import moveSceneModal from "./components/moveSceneModal.vue";
 import renameModal from "./components/renameModal.vue";
 import renameModal from "./components/renameModal.vue";
-import { useSceneStore } from "@/stores";
+import { useSceneStore, useUserStore } from "@/stores";
 import {
 import {
   objColumns,
   objColumns,
   getStatusImg,
   getStatusImg,
   getStatusText,
   getStatusText,
+  getCameraType,
+  SceneTypePaths,
 } from "./data";
 } from "./data";
 const { t } = useI18n();
 const { t } = useI18n();
 const router = useRouter();
 const router = useRouter();
 const useScene = useSceneStore();
 const useScene = useSceneStore();
+const userStore = useUserStore();
 const activeKey = ref("0");
 const activeKey = ref("0");
 const isObj = ref(0);
 const isObj = ref(0);
 const tablist = ref([
 const tablist = ref([
@@ -47,7 +50,7 @@ const folderId = ref(null);
 const folderPath = ref([
 const folderPath = ref([
   {
   {
     name: t("scene.gml"),
     name: t("scene.gml"),
-    id: 0,
+    id: null,
     index: 0,
     index: 0,
   },
   },
 ]);
 ]);
@@ -95,7 +98,7 @@ const getList = async ({ pageNum, pageSize, current }) => {
     title: (search.value.type == "name" && search.value.key) || "",
     title: (search.value.type == "name" && search.value.key) || "",
     sn: (search.value.type == "sn" && search.value.key) || "",
     sn: (search.value.type == "sn" && search.value.key) || "",
     num: (search.value.type == "num" && search.value.key) || "",
     num: (search.value.type == "num" && search.value.key) || "",
-    // folderId: folderId.value,
+    folderId: folderId.value,
     labType: activeKey.value,
     labType: activeKey.value,
     cameraType: cameraType.value,
     cameraType: cameraType.value,
   };
   };
@@ -183,7 +186,7 @@ const handleGenerate = async (item) => {
 };
 };
 const handleSee = (record) => {
 const handleSee = (record) => {
   let path = SceneTypePaths[record.sceneSource];
   let path = SceneTypePaths[record.sceneSource];
-  window.open(path[0], "_blank");
+  window.open(path[0] + `?m=${record.num}`, "_blank");
 };
 };
 const generateApi = async (num) => {
 const generateApi = async (num) => {
   await buildSceneObj({num});
   await buildSceneObj({num});
@@ -196,7 +199,7 @@ const handleEditItem = (record) => {
     return handleRename(record);
     return handleRename(record);
   }
   }
   let path = SceneTypePaths[record.sceneSource];
   let path = SceneTypePaths[record.sceneSource];
-  window.open(path[1], "_blank");
+  window.open(path[1] + `?m=${record.num}&token=${userStore.token}`, "_blank");
 };
 };
 const hendleCooperation = (item) => {
 const hendleCooperation = (item) => {
   console.log("handleFolder", selectTable.value);
   console.log("handleFolder", selectTable.value);
@@ -441,7 +444,7 @@ onMounted(() => {
               <img
               <img
                 v-if="record.tbType == 'f'"
                 v-if="record.tbType == 'f'"
                 @click.stop="handleFolderItem(record)"
                 @click.stop="handleFolderItem(record)"
-                src="/src/assets/image/scene/folder.png"
+                :src="record.sceneNum != 0 ? '/src/assets/image/scene/folder.png': '/src/assets/image/scene/nofolder.png'"
                 alt=""
                 alt=""
                 class="w-32 mr-2 Folder h-22"
                 class="w-32 mr-2 Folder h-22"
               />
               />

+ 10 - 0
vite.config.js

@@ -34,6 +34,16 @@ export default defineConfig({
       }
       }
     }
     }
   },
   },
+  // 关键:设置基础路径为相对路径
+  base: './',
+  build: {
+    // 可选:打包资源文件夹名称,默认assets
+    assetsDir: 'static',
+    // 静态资源内联阈值,小图片转base64
+    assetsInlineLimit: 4096,
+    // 关闭 sourcemap(生产环境推荐)
+    sourcemap: false
+  },
   // 加上这个!解决热更新失效
   // 加上这个!解决热更新失效
   server: {
   server: {
     port: 5173,         // 你想优先用的端口
     port: 5173,         // 你想优先用的端口