Selaa lähdekoodia

迭代四修改

zhangyihao 10 kuukautta sitten
vanhempi
commit
2791e17280

+ 8 - 0
src/api/duty/eventing.ts

@@ -8,6 +8,14 @@ export function getEvent(params) {
     params: params
   });
 }
+//获取天气
+export function getWeather(params) {
+  return request({
+    url: '/api/gateway/v2/get_weather_info',
+    method: 'get',
+    params: params
+  });
+}
 
 // 新建事件
 export function addEvent(data) {

+ 6 - 6
src/components/Map/company-map.vue

@@ -89,7 +89,7 @@ const props = defineProps({
 const router = useRouter();
 const emits = defineEmits(['update:visible']);
 // 地图对象
-let map = {};
+let map = null;
 let amap = {};
 let location = ref('');
 let marker = null; //地图上的点标记
@@ -130,9 +130,10 @@ onMounted(() => {
   window.addEventListener('resize', handleResize);
 });
 onUnmounted(() => {
-  if (map) {
-    map.destroy();
+  if (!!map) {
     map.off('rightclick');
+    map.destroy();
+    map = null;
   }
   window.removeEventListener('resize', handleResize);
 });
@@ -247,8 +248,8 @@ function handleRightclick(e) {
 }
 function setMarks(lnglat) {
   //添加标记
-  if (marker.value) map.remove(marker.value);
-  let marker = new AMap.Marker({
+  if (marker) map.remove(marker);
+  marker = new AMap.Marker({
     position: lnglat,
     icon: new AMap.Icon({
       size: new AMap.Size(22, 28), //图标所处区域大小
@@ -259,7 +260,6 @@ function setMarks(lnglat) {
     offset: new AMap.Pixel(0, 0)
   });
   marker.setMap(map);
-  marker.value = marker;
 }
 function handleClose() {
   emits('update:visible', false);

+ 0 - 1
src/types/components.d.ts

@@ -99,7 +99,6 @@ declare module 'vue' {
     UserSelect: typeof import('./../components/UserSelect/index.vue')['default']
     VideoContainer: typeof import('./../components/HKVideo/video-container.vue')['default']
     YMap: typeof import('./../components/Map/YMap.vue')['default']
-    YMapold: typeof import('./../components/Map/YMapold.vue')['default']
     YztMap: typeof import('./../components/Map/YztMap/index.vue')['default']
   }
   export interface ComponentCustomProperties {

+ 13 - 3
src/views/emergencyCommandMap/LeftSection/CloseCommand.vue

@@ -13,6 +13,7 @@
         </el-select>
         <span v-else>{{ form.event_title }}</span>
       </el-form-item>
+      <span style="color: red; display: block; margin-top: 5px">注意:本次指挥未关联事件,指挥记录将不会保留,若需要保留指挥记录,请关联事件</span>
     </el-form>
     <template #footer>
       <div class="dialog-footer">
@@ -25,7 +26,7 @@
 
 <script lang="ts" setup>
 import { ref, reactive, toRefs } from 'vue';
-import { addEvent, editEvent, postEditEvent, registeredEvent } from '@/api/duty/eventing';
+import { editEvent, registeredEvent } from '@/api/duty/eventing';
 import { useRouter } from 'vue-router';
 const proxy = getCurrentInstance()?.proxy;
 const { mm_event_title, region } = toRefs<any>(proxy?.useDict('mm_event_title', 'region'));
@@ -65,7 +66,6 @@ watch(
 const initFormData = {
   event_title: '', // 事件标题
   event_id: '',
-  address: '',
   event_type: '', // 事件类型
   event_level: '', // 事件等级
   event_status: '0' // 事件状态
@@ -93,7 +93,6 @@ const submitForm = async () => {
         // 提交关闭事件请求
         await closeEvent({
           event_id: form.value.event_id,
-          address: form.value.address
         });
         proxy?.$modal.msgSuccess('已成功关闭');
         closeDialog();
@@ -128,6 +127,9 @@ const closeDialog = () => {
   form.value.event_title = '';
 };
 const endProcess = () => {
+  // 确保在点击结束指挥时重新显示对话框
+  ensureDialogVisible();
+
   // 判断是否需要提交表单
   if (props.eventId === '') {
     // 如果没有 eventId,则提交表单
@@ -153,4 +155,12 @@ const showFormDialog = () => {
     fetchEvents();
   }
 };
+const selectEvent = (item) => {
+  // 更新表单中的 event_id 和 event_title
+  form.value.event_id = item.event_id;
+  form.value.event_title = item.event_title;
+
+  // 可以在这里进行其他逻辑处理
+  console.log('Selected event:', item);
+};
 </script>

+ 53 - 39
src/views/emergencyCommandMap/LeftSection/index.vue

@@ -5,25 +5,23 @@
         <div class="weather-box">
           <div class="weather-item">
             <div class="weatherBox1">天气</div>
-            <div class="weatherBox2">
-              <img :src="weatherImageUrl" alt="Weather Image" />
-            </div>
+            <div class="weatherBox2">{{ weatherDescription }}</div>
           </div>
           <div class="weather-item">
             <div class="weatherBox1">温度</div>
-            <div class="weatherBox2">31℃</div>
+            <div class="weatherBox2">{{ temperature }}℃</div>
           </div>
           <div class="weather-item">
             <div class="weatherBox1">湿度</div>
-            <div class="weatherBox2">45%</div>
+            <div class="weatherBox2">{{ humidity }}%</div>
           </div>
           <div class="weather-item">
             <div class="weatherBox1">风力风向</div>
-            <div class="weatherBox2">北风1级</div>
+            <div class="weatherBox2">{{ windDirection }} {{ windLevel }}级</div>
           </div>
           <div class="weather-item">
             <div class="weatherBox1">降雨量</div>
-            <div class="weatherBox2">0.0mm</div>
+            <div class="weatherBox2">{{ rainfall }}mm</div>
           </div>
         </div>
       </div>
@@ -114,7 +112,7 @@
   </div>
 </template>
 <script lang="ts" setup name="LeftSection">
-import { getEventDetail } from '@/api/duty/eventing';
+import { getEventDetail, getWeather } from '@/api/duty/eventing';
 import VideoMonitor from '@/views/emergencyCommandMap/LeftSection/VideoMonitor.vue';
 import { ref, onMounted, onUnmounted, computed } from 'vue';
 import CloseCommand from './CloseCommand.vue';
@@ -125,40 +123,56 @@ const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { mm_event_type, mm_event_level, mm_event_state, region } = toRefs<any>(
   proxy?.useDict('mm_event_type', 'mm_event_level', 'mm_event_state', 'region')
 );
-interface WeatherData {
-  location: string;
-  temperature: string;
-  condition: string;
-}
-const weatherData = ref<WeatherData>({
-  location: '',
-  temperature: '',
-  condition: ''
-});
-const weatherImageUrl = ref<string>('');
-
-const fetchWeatherData = async () => {
+const weatherDescription = ref('');
+const temperature = ref('');
+const humidity = ref('');
+const windDirection = ref('');
+const windLevel = ref('');
+const rainfall = ref('');
+// 获取天气数据
+async function fetchWeatherData() {
   try {
-    const response = await axios.get<WeatherData>('https://api.example.com/weather'); // 替换为实际的API URL
-    weatherData.value = response.data;
-    weatherImageUrl.value = getWeatherImageUrl(weatherData.value.condition);
+    const response = await getWeather({});
+    if (response && response.rows && response.rows.length > 0) {
+      const weatherData = response.rows[0];
+      weatherDescription.value = weatherData.sk_s;
+      temperature.value = weatherData.sk_t;
+      humidity.value = weatherData.sk_h;
+      windDirection.value = getWindDirection(weatherData.sk_wd);
+      windLevel.value = weatherData.sk_wp_level;
+      rainfall.value = weatherData.sk_r1h;
+    }
   } catch (error) {
-    console.error('Error fetching weather data:', error);
+    console.error('Failed to fetch weather data:', error);
   }
-};
-
-const getWeatherImageUrl = (condition: string): string => {
-  const weatherToImageUrl = {
-    sunny: 'https://example.com/images/sunny.png',
-    cloudy: 'https://example.com/images/cloudy.png',
-    rainy: 'https://example.com/images/rainy.png',
-    snowy: 'https://example.com/images/snowy.png',
-    // 添加更多天气条件
-    default: 'https://example.com/images/default.png'
-  };
-
-  return weatherToImageUrl[condition] || weatherToImageUrl.default;
-};
+}
+// 根据风向角度获取风向名称
+function getWindDirection(angle) {
+  const directions = [
+    '北',
+    '北偏北',
+    '北偏东北',
+    '东北',
+    '东偏东北',
+    '东偏东',
+    '东',
+    '东偏东南',
+    '东南',
+    '南偏东南',
+    '南偏南',
+    '南',
+    '南偏西南',
+    '西南',
+    '西偏西南',
+    '西偏西',
+    '西',
+    '西偏西北',
+    '西北',
+    '北偏西北'
+  ];
+  const index = Math.floor(((angle + 11.25) % 360) / 22.5);
+  return directions[index];
+}
 let eventId = ref('');
 // 事件信息
 const eventData = ref({

+ 10 - 10
src/views/routineCommandMap/EventManage.vue

@@ -97,9 +97,9 @@
               <el-tooltip content="查看" placement="top">
                 <el-button link type="primary" icon="View" @click="handleView(scope.row)"></el-button>
               </el-tooltip>
-              <el-tooltip content="编辑" placement="top">
-                <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
-              </el-tooltip>
+              <!--              <el-tooltip content="编辑" placement="top">-->
+              <!--                <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>-->
+              <!--              </el-tooltip>-->
               <el-tooltip content="关闭事件" placement="top">
                 <el-button link type="primary" icon="Close" @click="handleClose(scope.row)"></el-button>
               </el-tooltip>
@@ -233,13 +233,13 @@ const eventDetailsState = reactive({
 // };
 
 // 修改事件
-const handleUpdate = (row) => {
-  if (row) {
-    eventId.value = row.event_id;
-    eventEditDialogState.title = '修改事件';
-    eventEditDialogState.show = true;
-  }
-};
+// const handleUpdate = (row) => {
+//   if (row) {
+//     eventId.value = row.event_id;
+//     eventEditDialogState.title = '修改事件';
+//     eventEditDialogState.show = true;
+//   }
+// };
 //查看事件详情
 const handleView = (row) => {
   // 查看事件详情逻辑

+ 1 - 1
src/views/routineCommandMap/MiddleSection.vue

@@ -13,7 +13,7 @@
 import GlobalMap from '../globalMap/index.vue';
 import { ref } from 'vue';
 // import Dialog from "@/components/Dialog/index2.vue";
-import CompanyMap from '@/components/Map/company-map.vue';
+import CompanyMap from './company-map.vue';
 
 const form = ref({
   address: '',

+ 455 - 0
src/views/routineCommandMap/company-map.vue

@@ -0,0 +1,455 @@
+<template>
+  <div>
+    <div v-if="visible" class="dialog-wrap">
+      <div class="dialog">
+        <div class="dialog-header">
+          <div class="dialog-title">{{ title }}</div>
+          <div class="icon-close" @click="handleClose">
+            <el-icon size="40px"><Close /></el-icon>
+          </div>
+        </div>
+        <div class="dialog-content">
+          <el-form ref="queryFormRef" :model="form" :rules="rules" :inline="true">
+            <el-form-item label="详细地址" prop="address">
+              <el-input v-model="form.address" placeholder="请输入" clearable />
+            </el-form-item>
+            <el-form-item label="经度" prop="longitude">
+              <el-input v-model="form.longitude" placeholder="请输入" />
+            </el-form-item>
+            <el-form-item label="纬度" prop="latitude">
+              <el-input v-model="form.latitude" placeholder="请输入" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" size="large" @click="submit">确定</el-button>
+            </el-form-item>
+          </el-form>
+          <div ref="containerRef" class="map_box">
+            <div id="map" class="map" :style="{ width: width, height: height }"></div>
+            <div class="search">
+              <!-- @input="handleInput(0)" -->
+              <el-input v-model="location" placeholder="请输入地址" />
+              <el-button class="btn" type="primary" @click="handleInput(0)">搜索</el-button>
+            </div>
+
+            <div v-if="searchPop" class="scroll_box">
+              <div style="height: 30px; line-height: 30px">
+                <span style="font-weight: bold">搜索结果列表</span>
+                <i class="el-icon-close" style="float: right; font-size: 20px; cursor: pointer" @click="closeSearchList()" />
+              </div>
+
+              <el-scrollbar class="scroll" style="height: 250px">
+                <div v-for="(item, index) in searchList" v-show="searchList.length" :key="index" class="item" @click="handlePanTo(index)">
+                  <el-image class="img" :src="item.img" :alt="item.name" lazy>
+                    <template #error>
+                      <div class="image-slot">
+                        <i class="el-icon-picture-outline"></i>
+                      </div>
+                    </template>
+                  </el-image>
+                  <div>
+                    <div class="text">{{ item.name }}</div>
+                    <div>{{ item.address }}</div>
+                  </div>
+                </div>
+                <div v-show="!searchList.length" class="empty" style="text-align: center">没有搜索到内容</div>
+              </el-scrollbar>
+
+              <el-pagination
+                background
+                small
+                :hide-on-single-page="true"
+                layout="prev, pager, next"
+                :total="total"
+                :page-size="pageSize"
+                :current-page="pageNum"
+                style="margin-top: 10px"
+                @current-change="handleChangePage"
+              >
+              </el-pagination>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import AMapLoader from '@amap/amap-jsapi-loader';
+import { useRouter } from 'vue-router';
+
+const props = defineProps({
+  visible: {
+    type: Boolean,
+    default: () => {
+      return false;
+    }
+  }
+});
+const router = useRouter();
+const emits = defineEmits(['update:visible']);
+// 地图对象
+let map = null;
+let amap = {};
+let location = ref('');
+let marker = null; //地图上的点标记
+let contextMenu = null;
+let lnglatPosition = ref([]); //选中的新坐标
+let rules = reactive({
+  address: [{ required: true, message: '详细地址不能为空', trigger: 'blur' }],
+  longitude: [{ required: true, message: '经度不能为空', trigger: 'blur' }],
+  latitude: [{ required: true, message: '纬度不能为空', trigger: 'blur' }]
+});
+let pageNum = ref(1);
+let pageSize = ref(10);
+let total = ref(0);
+
+let searchList = ref([]);
+let searchPop = ref(false);
+let placeSearch;
+let form = reactive({
+  address: '',
+  longitude: '',
+  latitude: ''
+});
+let open = ref(false);
+let geocoder = {};
+let width = ref('100%');
+let height = ref('100%');
+watch(
+  () => props.visible,
+  (n) => {
+    if (n) {
+      nextTick(() => {
+        initMap();
+      });
+    }
+  }
+);
+onMounted(() => {
+  window.addEventListener('resize', handleResize);
+});
+onUnmounted(() => {
+  if (!!map) {
+    map.off('rightclick');
+    map.destroy();
+    map = null;
+  }
+  window.removeEventListener('resize', handleResize);
+});
+
+function handleInput(flag) {
+  if (!location.value) return;
+
+  if (!flag) {
+    //搜索
+    total.value = 0;
+    pageNum.value = 1;
+  }
+
+  if (!placeSearch) {
+    placeSearch = new amap.PlaceSearch({
+      pageSize: 10, // 每页条数,默认10,范围1-50
+      pageIndex: 1, // 页码
+      extensions: 'all' // 默认base,返回基本地址信息;all:返回详细信息
+    });
+  }
+
+  searchPop.value = true;
+  placeSearch.setPageIndex(pageNum.value);
+  placeSearch.search(location.value, (status, result) => {
+    // console.log(result.poiList.pois, 'result')
+    if (!!result.poiList && result.poiList.pois && result.poiList.pois.length > 0) {
+      let arr = [];
+      const pois = result.poiList.pois;
+      total.value = result.poiList ? result.poiList.count : 0;
+      arr = pois.map((item) => {
+        return {
+          name: item.name,
+          address: item.address,
+          img: item.photos[0]?.url,
+          lnglat: [item.location.lng, item.location.lat]
+        };
+      });
+      searchList.value = arr;
+    } else {
+      total.value = 0;
+      searchList.value = [];
+    }
+  });
+}
+
+function handleChangePage(newNum) {
+  if (!searchPop.value) return;
+  pageNum.value = newNum;
+  this.handleInput(1);
+}
+
+function closeSearchList() {
+  searchPop.value = false;
+  location.value = '';
+  searchList.value = [];
+  total.value = 0;
+  pageNum.value = 1;
+}
+
+// 地图中心的平移至指定点位置
+function handlePanTo(index) {
+  let lnglat = searchList.value[index].lnglat;
+  form.longitude = searchList.value[index].name + '(' + searchList.value[index] + ')';
+  form.latitude = lnglat[0];
+  form.latitude = lnglat[1];
+  map.panTo(lnglat);
+  setMarks(lnglat);
+  closeSearchList();
+}
+
+const initMap = async () => {
+  let position = [110.93154257997, 21.669064031332];
+  const AMap = await AMapLoader.load({
+    key: '30d3d8448efd68cb0b284549fd41adcf', // 申请好的Web端开发者Key,首次调用 load 时必填
+    version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
+    plugins: ['AMap.PlaceSearch', 'AMap.ContextMenu', 'AMap.PolygonEditor', 'AMap.Geocoder'] // 插件列表
+  });
+  map = new AMap.Map('map', {
+    viewMode: '3D', //是否为3D地图模式
+    center: position,
+    zoom: 15
+  });
+  amap = AMap;
+  geocoder = new AMap.Geocoder({
+    // city 指定进行编码查询的城市,支持传入城市名、adcode 和 citycode
+    city: '010'
+  });
+  // 创建右键菜单
+  ContextMenu();
+  map.on('rightclick', handleRightclick);
+  handleResize();
+};
+
+function ContextMenu() {
+  contextMenu = new AMap.ContextMenu();
+  contextMenu.addItem(
+    '选择标点',
+    () => {
+      form.longitude = lnglatPosition.value[0];
+      form.latitude = lnglatPosition.value[1];
+      contextMenu.close();
+      let lnglat = [form.longitude, form.latitude];
+      geocoder.getAddress(lnglat, (status, result) => {
+        if (status === 'complete' && result.info === 'OK') {
+          form.address = result.regeocode.formattedAddress;
+        }
+      });
+      setMarks(lnglat);
+    },
+    1
+  );
+}
+
+// 右键事件
+function handleRightclick(e) {
+  let lnglat = [e.lnglat.getLng(), e.lnglat.getLat()];
+  contextMenu.open(map, e.lnglat);
+  lnglatPosition.value = lnglat;
+}
+
+function setMarks(lnglat) {
+  //添加标记
+  if (marker) map.remove(marker);
+  marker = new AMap.Marker({
+    position: lnglat,
+    icon: new AMap.Icon({
+      size: new AMap.Size(22, 28), //图标所处区域大小
+      imageSize: new AMap.Size(22, 28), //图标大小
+      image: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png'
+    }),
+    anchor: 'bottom-center',
+    offset: new AMap.Pixel(0, 0)
+  });
+  marker.setMap(map);
+}
+
+function handleClose() {
+  emits('update:visible', false);
+}
+
+let queryFormRef = ref();
+let containerRef = ref();
+
+function handleResize() {
+  const containerWidth = containerRef.value.clientWidth * (document.body.clientWidth / 8960);
+  const containerHeight = containerRef.value.clientHeight * (document.body.clientHeight / 2520);
+  width.value = containerWidth + 'px';
+  height.value = containerHeight + 'px';
+  nextTick(() => {
+    map.resize();
+  });
+}
+
+function submit() {
+  queryFormRef.value.validate((valid) => {
+    if (valid) {
+      console.log('提交数据', form);
+      router.push({
+        path: '/emergencyCommandMap',
+        query: { id: '11111111' }
+      });
+    }
+  });
+}
+</script>
+
+<style lang="scss" scoped>
+.map_box {
+  position: relative;
+  background: rgba(0, 0, 0, 0.3);
+  margin-bottom: 20px;
+}
+
+.map {
+  width: 100%;
+  height: 100%;
+}
+
+.search {
+  width: 50%;
+  position: absolute;
+  right: 2%;
+  top: 10px;
+  background: #fff;
+  padding: 8px 8px;
+  border-radius: 3px;
+  display: flex;
+}
+
+.btn {
+  margin-left: 10px;
+}
+
+.scroll_box {
+  width: 50%;
+  padding-top: 30px;
+  padding-bottom: 20px;
+  background: #fff;
+  position: absolute;
+  right: 2%;
+  top: 70px;
+  padding: 15px;
+  border-radius: 3px;
+
+  .close {
+    position: absolute;
+    right: 2%;
+    top: 10px;
+    cursor: pointer;
+    font-size: 20px;
+  }
+}
+
+.scroll {
+  width: 100%;
+  max-height: 250px;
+
+  .item {
+    display: flex;
+    font-size: 14px;
+    cursor: pointer;
+    padding: 8px;
+
+    &:hover {
+      background-color: #f6f6f6;
+    }
+
+    .img {
+      width: 50px;
+      height: 45px;
+      min-width: 50px;
+      margin-right: 10px;
+    }
+
+    &::v-deep {
+      .image-slot {
+        width: 100%;
+        height: 100%;
+        background-color: #f5f7fa;
+        text-align: center;
+        line-height: 50px;
+      }
+
+      .el-icon-picture-outline {
+        font-size: 25px;
+      }
+    }
+
+    .text {
+      color: #3385ff;
+      margin-bottom: 6px;
+    }
+  }
+}
+
+::v-deep {
+  .el-scrollbar__wrap {
+    overflow-x: hidden !important;
+  }
+
+  .is-horizontal {
+    display: none;
+  }
+}
+
+.empty {
+  margin: 20px 0;
+}
+
+.dialog-wrap {
+  position: fixed;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  z-index: 2000;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 16px;
+
+  .dialog {
+    width: 4000px;
+    height: 2000px;
+    margin: 0 auto;
+    background-color: #fff;
+    border-radius: 10px;
+  }
+}
+
+.dialog {
+  padding: 0 20px;
+
+  .dialog-header {
+    width: 100%;
+    height: 70px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+
+    .dialog-title {
+      font-size: 36px;
+    }
+
+    .icon-close {
+      cursor: pointer;
+    }
+  }
+
+  .dialog-content {
+    padding: 10px 0;
+
+    .map_box {
+      width: calc(4000px - 50px) !important;
+      height: calc(2000px - 200px) !important;
+      overflow: hidden;
+    }
+  }
+}
+</style>