Hwf преди 1 ден
родител
ревизия
7a6cb8dd06

+ 1 - 1
.env.development

@@ -37,4 +37,4 @@ VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
 
 # websocket 开关
 VITE_APP_WEBSOCKET = false
-VITE_APP_BASE_WEBSOCKET= 'ws://10.181.7.236:9988'
+VITE_APP_BASE_WEBSOCKET= 'ws://10.181.7.235:8086'

+ 1 - 1
src/utils/websocket.ts

@@ -6,7 +6,7 @@ let rec; //断线重连后,延迟5秒重新创建WebSocket连接  rec用来存
 let closeFlag = false; // 是否关闭socket
 let global_callback = null;
 
-const wsUrl = `${import.meta.env.VITE_APP_BASE_WEBSOCKET}/api/pattern/`;
+const wsUrl = `${import.meta.env.VITE_APP_BASE_WEBSOCKET}/ws/api/pattern/`;
 function createWebSocket(id, callback) {
   if (webSock != null) {
     return;

+ 1 - 1
src/views/comprehensiveGuarantee/electronicDisasterMapManage/index.vue

@@ -371,7 +371,7 @@ const handleRoutes = async (item) => {
   const ststrategy = ['最快路线', '最短路线', '避开高速'];
   routeData.value = [];
   for (let i = 0; i < 3; i++) {
-    const url = `http://api.tianditu.gov.cn/drive?postStr={"orig":"${start}","dest":"${end}","style":"${i}"}&type=search&tk=${tkKey}`;
+    const url = `https://api.tianditu.gov.cn/drive?postStr={"orig":"${start}","dest":"${end}","style":"${i}"}&type=search&tk=${tkKey}`;
     const response = await fetch(url);
     if (response.status == 200) {
       const parser = new DOMParser();

+ 1 - 1
src/views/emergencyCommandMap/LeftSection/Communication.vue

@@ -103,7 +103,7 @@
       </div>
     </div>
     <Drone v-show="activeIndex === 1" />
-    <IndividualEquipment v-show="activeIndex === 2" />
+    <IndividualEquipment v-show="activeIndex === 2" :height="210" />
 
     <Dialog v-if="showJoinMeeting" customShow type="xs" height="280px" title="加入会议" @confirm="handleJoinMeeting" @close="closeDialog">
       <div class="dialog-content">

+ 365 - 12
src/views/emergencyCommandMap/LeftSection/IndividualEquipment.vue

@@ -9,35 +9,99 @@
         </el-input>
       </div>
       <div class="tree-container">
-        <div class="tree-box">
-          <div style="overflow-y: auto; height: 100%">
-            <el-tree :data="treeData" accordion @node-click="handleNodeClick" />
+        <div class="user-box" :style="{ height: height + 'px' }">
+          <div class="user-table">
+            <div class="tr">
+              <div class="td2">
+                <div :class="getCheckedClass()" @click="handleChecked" />
+              </div>
+              <div class="td">设备</div>
+            </div>
+            <div class="table-content" :style="{ height: height - 45 + 'px' }">
+              <div v-for="(item, index) in userList" :key="index" class="tr2">
+                <div class="td2">
+                  <div :class="item.checked ? 'common-checked-active' : 'common-checked'" @click="handleChecked2(item)"></div>
+                </div>
+                <div class="td">{{ item.label }}</div>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div class="select-box2" :style="{ height: height + 'px' }">
+          <div class="select-header">
+            <div class="left-item">
+              <div>已选择:</div>
+              <div class="text">{{ selectList.length }}</div>
+              <div>个</div>
+            </div>
+            <div class="clear-btn" @click="clearSelect">清空</div>
+          </div>
+          <div class="select-content" :style="{ height: height - 50 + 'px' }">
+            <div v-for="(item, index) in selectList" :key="index" class="box-item">
+              <div class="line">
+                <div class="text1">{{ item.label }}</div>
+              </div>
+              <div class="close-btn" @click="deleteItem(item)"></div>
+            </div>
+          </div>
+        </div>
+        <div class="btn-box">
+          <div class="btn" @click="handleOpenMeeting">
+            <div class="icon3"></div>
+            <div class="text">发起会议</div>
           </div>
         </div>
       </div>
     </div>
-    <Dialog v-if="showIframe" v-model="showIframe"  type="xl" height="90%" :title="iframeTitle" hide-footer>
-      <iframe :src="iframeUrl" style="width: 100%; height: 99%; border: none" />
+    <Dialog v-if="showIframe" v-model="showIframe" type="lg" :title="iframeTitle" hide-footer>
+      <iframe :src="iframeUrl" style="width: 100%; height: 100%" />
+    </Dialog>
+    <Dialog
+      v-if="showOpenMeeting"
+      custom-show
+      type="xs"
+      height="660px"
+      :title="type === '0' ? '发起会议' : '电话呼叫'"
+      @confirm="handleStartCall"
+      @close="closeOpenDialog"
+    >
+      <el-form ref="form2Ref" :model="openMeetingForm" :rules="rules2">
+        <el-form-item label="账号" label-width="200px" prop="username">
+          <el-input v-model="openMeetingForm.username" class="custom-input2" clearable placeholder="请输入设备账号" />
+        </el-form-item>
+
+        <el-form-item label="密码" label-width="200px" prop="userpass">
+          <el-input v-model="openMeetingForm.userpass" type="password" class="custom-input2" clearable placeholder="请输入设备密码" />
+        </el-form-item>
+      </el-form>
     </Dialog>
   </div>
 </template>
 
 <script setup lang="ts">
 import { Search } from '@element-plus/icons-vue';
-//import { getAvconDeptTree } from '@/api/emergencyCommandMap/communication';
 import { getDroneTree } from '@/api/emergencyCommandMap/Drone';
+import { deepClone } from '@/utils';
+import { getStartMiniParam } from '@/api/emergencyCommandMap/communication';
 interface QueryParams {
   equipment: string;
 }
+const props = defineProps({
+  height: {
+    type: Number,
+    required: false,
+    default: 200
+  }
+});
 const queryParams = reactive<QueryParams>({
   equipment: '单兵设备'
 });
-
-const treeData = ref([]);
-
+const proxy = getCurrentInstance()?.proxy;
+const userList = ref([]);
+const selectList = ref([]);
 const getTree = () => {
   getDroneTree(queryParams).then((res) => {
-    treeData.value = res.data;
+    userList.value = res.data;
   });
 };
 let showIframe = ref(false);
@@ -50,6 +114,135 @@ const handleNodeClick = (data, node) => {
     showIframe.value = true;
   }
 };
+const changeSelectList = (item) => {
+  const index = selectList.value.findIndex((item2) => item2.id === item.id);
+  if (item.checked) {
+    if (index === -1) {
+      selectList.value.push(deepClone(item));
+    }
+  } else {
+    if (index > -1) {
+      selectList.value.splice(index, 1);
+    }
+  }
+};
+const getCheckedClass = () => {
+  let res = 'common-checked';
+  const len = userList.value.length;
+  let len2 = 0;
+  userList.value.forEach((item) => {
+    const index = selectList.value.findIndex((item2) => item2.id === item.id);
+    if (index > -1) {
+      len2++;
+    }
+  });
+  if (len2 > 0 && len2 === len) {
+    res = 'common-checked-active';
+  } else if (len2 > 0) {
+    res = 'common-checked-half';
+  }
+  return res;
+};
+
+// 全选、全取消
+const handleChecked = () => {
+  const checkedClass = getCheckedClass();
+  let flag = true;
+  if (checkedClass === 'common-checked-active') {
+    flag = false;
+  }
+  userList.value.forEach((item) => {
+    item.checked = flag;
+    changeSelectList(item);
+  });
+};
+
+// 单个选中、取消选中
+const handleChecked2 = (item) => {
+  item.checked = !item.checked;
+  changeSelectList(item);
+};
+// 清空
+const clearSelect = () => {
+  userList.value.forEach((item) => {
+    if (item.checked) {
+      item.checked = false;
+    }
+  });
+  selectList.value = [];
+};
+// 清空指定项
+const deleteItem = (item) => {
+  for (let i = 0; i < userList.value.length; i++) {
+    if (item.id === userList.value[i].id) {
+      userList.value[i].checked = false;
+      break;
+    }
+  }
+  item.checked = false;
+  changeSelectList(item);
+};
+// 0 会议 1 电话
+let type = ref('0');
+let form2Ref = ref();
+let showOpenMeeting = ref(false);
+let openMeetingForm = reactive({
+  username: '',
+  userpass: ''
+});
+const rules2 = reactive({
+  username: [{ required: true, message: '会议账号不能为空', trigger: 'blur' }],
+  userpass: [{ required: true, message: '会议密码不能为空', trigger: 'blur' }]
+});
+const handleOpenMeeting = () => {
+  type.value = '0';
+  showOpenMeeting.value = true;
+};
+const closeOpenDialog = () => {
+  showOpenMeeting.value = false;
+};
+// 电话呼叫
+const handleStartCall = () => {
+  form2Ref.value?.validate((valid) => {
+    if (valid) {
+      let dev_list = [];
+      userList.value.forEach((item) => {
+        if (item.checked && item.mobile != '') {
+          dev_list.push({ id: item.mobile, avtype: type.value === '0' ? 'av' : 'a' }); // a 音频 v 视频 默认 av
+        }
+      });
+      if (dev_list.length == 0) {
+        proxy?.$modal.msgError('请勾选人员');
+        return false;
+      }
+      const screenWidth = window.screen.width * window.devicePixelRatio;
+      const screenHeight = window.screen.height * window.devicePixelRatio;
+      const data = {
+        userid: openMeetingForm.username, // 空表示后台获取当前用户对应融合通信dev_id
+        password: openMeetingForm.userpass,
+        windowpos: { 'x': 0, 'y': 0, 'width': screenWidth, 'height': screenHeight, 'top': true },
+        members: {
+          num: dev_list.length + 2, // 配置多少个座位,一般就是邀请人多少个就多少个
+          'dev-list': dev_list
+        }
+      };
+      getStartMiniParam(data).then((res) => {
+        // 创建一个a标签元素
+        const a = document.createElement('a');
+        // 设置a标签的href属性
+        a.href = res.data;
+        // 触发点击事件
+        a.click();
+
+        // 保存账号和密码
+        localStorage.setItem('meeting_username', openMeetingForm.username);
+        localStorage.setItem('meeting_userpass', openMeetingForm.userpass);
+      });
+      closeOpenDialog();
+    }
+  });
+};
+
 onMounted(() => {
   getTree();
 });
@@ -72,10 +265,9 @@ onMounted(() => {
       }
     }
     :deep(.el-tree) {
-      height: 100%;
       background-color: transparent;
       color: #fbffff;
-      font-size: 14px;
+      font-size: 38px;
       .el-tree-node__content {
         height: auto;
         padding-top: 10px;
@@ -85,6 +277,7 @@ onMounted(() => {
       }
       .el-tree-node__expand-icon {
         color: #297cfc;
+        font-size: 23px;
       }
       .el-tree-node:focus > .el-tree-node__content,
       .el-tree-node__content:hover {
@@ -98,4 +291,164 @@ onMounted(() => {
     flex: 1;
   }
 }
+.tree-container {
+  margin-top: 15px;
+  display: flex;
+}
+.user-box {
+  margin-left: 10px;
+  flex: 1;
+  height: 180px;
+  background: url('@/assets/images/emergencyCommandMap/communication/treeBg.png') no-repeat;
+  background-size: 100% 100%;
+  .user-table {
+    padding: 10px 5px;
+    display: flex;
+    flex-direction: column;
+    font-size: 14px;
+    color: #fbffff;
+    .tr {
+      background-color: #102e76;
+    }
+    .tr,
+    .tr2 {
+      display: flex;
+      padding: 5px 0;
+      .td {
+        flex: 2;
+        display: flex;
+        align-items: center;
+      }
+      .td2 {
+        width: 65px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+      }
+      .td3 {
+        flex: 3;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+      }
+    }
+    .table-content {
+      height: 133px;
+      overflow-y: auto;
+    }
+    .tr2 {
+      margin-top: 5px;
+      background-color: #122868;
+    }
+    .phone-icon {
+      flex-shrink: 0;
+      width: 24px;
+      height: 25px;
+      background: url('@/assets/images/emergencyCommandMap/communication/phone.png') no-repeat;
+      background-size: 100%;
+      cursor: pointer;
+    }
+  }
+}
+.select-box2 {
+  margin-left: 3px;
+  flex: 1;
+  height: 180px;
+  background: url('@/assets/images/emergencyCommandMap/communication/peopleBg.png') no-repeat;
+  background-size: 100% 100%;
+  .select-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    color: #fbffff;
+    font-size: 14px;
+    border-bottom: 1px solid #247dff;
+    padding: 6px;
+    .left-item {
+      display: flex;
+      align-items: center;
+      .text {
+        margin: 0 3px;
+        color: #00e8ff;
+        font-family: 'BEBAS-1';
+      }
+    }
+    .clear-btn {
+      color: #00e8ff;
+      cursor: pointer;
+    }
+  }
+  .select-content {
+    height: 120px;
+    overflow-y: auto;
+    .box-item {
+      border-bottom: 1px solid #247dff;
+      padding: 6px;
+      position: relative;
+      .line {
+        color: #fff;
+        font-size: 14px;
+        display: flex;
+        .text1 {
+          margin-right: 12px;
+        }
+        .text2 {
+          color: #a7ccdf;
+        }
+      }
+      .close-btn {
+        position: absolute;
+        right: 3px;
+        top: 16px;
+        cursor: pointer;
+        width: 10px;
+        height: 10px;
+        background: url('@/assets/images/emergencyCommandMap/communication/close.png') no-repeat;
+      }
+    }
+  }
+}
+.btn-box {
+  width: 114px;
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+  .btn {
+    width: 114px;
+    height: 43px;
+    background: url('@/assets/images/emergencyCommandMap/communication/btn.png') no-repeat;
+    background-size: 100% 100%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    cursor: pointer;
+    .icon1,
+    .icon2,
+    .icon3 {
+      margin-top: 3px;
+    }
+    .icon1 {
+      width: 19px;
+      height: 20px;
+      background: url('@/assets/images/emergencyCommandMap/communication/icon1.png') no-repeat;
+      background-size: 100% 100%;
+    }
+    .icon2 {
+      width: 20px;
+      height: 20px;
+      background: url('@/assets/images/emergencyCommandMap/communication/icon2.png') no-repeat;
+      background-size: 100% 100%;
+    }
+    .icon3 {
+      width: 20px;
+      height: 20px;
+      background: url('@/assets/images/emergencyCommandMap/communication/icon3.png') no-repeat;
+      background-size: 100% 100%;
+    }
+    .text {
+      color: #fff;
+      font-size: 14px;
+    }
+  }
+}
 </style>

+ 1 - 1
src/views/globalMap/RightMenu/FixedPointAnalysis.vue

@@ -283,7 +283,7 @@ const handleRoutes = async (item) => {
   const ststrategy = ['最快路线', '最短路线', '避开高速'];
   routeData.value = [];
   for (let i = 0; i < 3; i++) {
-    const url = `http://api.tianditu.gov.cn/drive?postStr={"orig":"${start}","dest":"${end}","style":"${i}"}&type=search&tk=${tkKey}`;
+    const url = `https://api.tianditu.gov.cn/drive?postStr={"orig":"${start}","dest":"${end}","style":"${i}"}&type=search&tk=${tkKey}`;
     const response = await fetch(url);
     if (response.status == 200) {
       const parser = new DOMParser();