瀏覽代碼

地点选择

Hwf 10 月之前
父節點
當前提交
d77c346abf

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

@@ -0,0 +1,10 @@
+import request from '@/utils/request';
+
+// 获取事件列表
+export function getEvent(params) {
+  return request({
+    url: '/api/event_management/event/list',
+    method: 'get',
+    params: params
+  });
+}

+ 104 - 0
src/api/emergencyCommandMap/JointDuty.ts

@@ -0,0 +1,104 @@
+import request from '@/utils/request';
+import CryptoJS from 'crypto-js';
+import { nanoid } from 'nanoid';
+
+// 二维码
+export const getMapProduct = (data) => {
+  const nonce = nanoid();
+  const timestampHeader = (Date.now() / 1000).toFixed();
+  const token = 'dsfsdfsdfsf';
+  const signatureHeader = CryptoJS.SHA256(timestampHeader + token + nonce + timestampHeader).toString(CryptoJS.enc.Hex);
+  return request({
+    url: 'https://yzh.gdgov.cn/yzm-generator/generateCode',
+    method: 'POST',
+    headers: {
+      'x-yzm-nonce': nonce,
+      'x-yzm-signature': signatureHeader,
+      'x-yzm-paasid': token,
+      'x-yzm-timestamp': timestampHeader,
+      'Content-Type': 'application/json;charset=utf-8'
+    },
+    data: {
+      id: data.id,
+      name: data.name,
+      areaCode: data.areaCode,
+      ext: data.ext
+    }
+  });
+};
+
+// 获取签名列表
+export function getCheckinList(eventId: string) {
+  return request({
+    url: '/api/event_management/checkin/list',
+    method: 'get',
+    params: {
+      event_id: eventId
+    }
+  });
+}
+
+// 更新事发地点 (用于将表单数据发送到服务器以更新某个事件的位置信息)
+export function updateEventLocation(eventId: string, address: string, longitude: string, latitude: string) {
+  return request({
+    url: '/api/event_management/event/save_address',
+    method: 'post',
+    params: {
+      eventId: eventId,
+      address: address,
+      longitude: longitude,
+      latitude: latitude
+    }
+  });
+}
+
+// 新建事件
+export function addEvent(data) {
+  return request({
+    url: '/api/event_management/event/create',
+    method: 'post',
+    data: data
+  });
+}
+// 任务新增
+export function addTask(data) {
+  return request({
+    url: '/api/taskRegistration/create',
+    method: 'post',
+    data: data
+  });
+}
+// 任务查询
+export function selectTask(params) {
+  return request({
+    url: '/api/taskRegistration/select',
+    method: 'get',
+    params: params
+  });
+}
+// 任务更新
+export function updateTaskRegistration(data) {
+  return request({
+    url: '/api/taskRegistration/update',
+    method: 'put',
+    data: data
+  });
+}
+
+// 查看事业单位
+export function getUnits(params) {
+  return request({
+    url: '/api/taskRegistration/selectUnit',
+    method: 'get',
+    params: params
+  });
+}
+
+// 任务删除
+export function deleteTask(data) {
+  return request({
+    url: '/api/taskRegistration/delete',
+    method: 'post',
+    data: data
+  });
+}

二進制
src/assets/images/event/icon11.png


+ 1 - 0
src/styles/index.less

@@ -37,6 +37,7 @@ html {
   width: 100%;
   height: 100%;
   font-size: 16px;
+  color: #445267;
   .container {
     width: 100%;
     background-color: #f4f8fa;

+ 1 - 1
src/views/event/AssociationPlan.vue

@@ -37,7 +37,7 @@
 </template>
 
 <script lang="ts" setup>
-import {getCurrentInstance, reactive, ref, toRefs, watch, defineEmits} from 'vue';
+import { ref, watch, defineEmits } from 'vue';
 import { uploadCasualties } from "@/api/event";
 
 interface Form {

+ 341 - 0
src/views/mobileControl/PositionSelect.vue

@@ -0,0 +1,341 @@
+<template>
+  <van-dialog v-model:show="showPositionSelect" title="请选择事发地点" show-cancel-button @close="handleClose" @confirm="submit">
+    <div class="position-container">
+      <div style="position: relative">
+        <div class="box">
+          <van-search
+              v-model="form.address"
+              show-action
+              label="详细地址"
+              left-icon="none"
+              placeholder="请输入"
+              @search="handleInput"
+          >
+            <template #action>
+              <div @click="handleInput">搜索</div>
+            </template>
+          </van-search>
+        </div>
+        <div v-if="searchPop" class="scroll_box">
+          <div class="scroll-header">
+            <span>搜索结果列表</span>
+            <i class="close-icon" @click="closeSearchList()" />
+          </div>
+
+          <div class="scroll">
+            <div v-for="(item, index) in searchList" v-show="searchList.length" :key="index" class="item" @click="handlePanTo(index)">
+              <van-image width="50" height="50" fit="fill" :src="item.img" style="flex-shrink: 0; margin-right: 8px;" />
+              <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>
+          </div>
+        </div>
+      </div>
+      <van-field v-model="form.longitude" label="经度" placeholder="请输入" />
+      <van-field v-model="form.latitude" label="纬度" placeholder="请输入" />
+      <div id="map" class="map" />
+    </div>
+  </van-dialog>
+
+</template>
+
+<script  lang="ts" setup name="PositionSelect">
+import AMapLoader from '@amap/amap-jsapi-loader';
+import { useRouter } from 'vue-router';
+import { addEvent } from '@/api/emergencyCommandMap/JointDuty';
+import {nextTick, onUnmounted, reactive, ref, watch} from "vue";
+import {showFailToast} from "vant";
+
+const props = defineProps({
+  visible: {
+    type: Boolean,
+    default: () => {
+      return false;
+    }
+  }
+});
+const router = useRouter();
+const emits = defineEmits(['update:visible', 'confirm']);
+let showPositionSelect = ref(false);
+// 地图对象
+let map = null;
+let amap = {};
+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;
+// 提交事件时间改为当前时间currentTime
+const now = new Date();
+const year = now.getFullYear();
+const month = String(now.getMonth() + 1).padStart(2, '0');
+const day = String(now.getDate()).padStart(2, '0');
+const hours = String(now.getHours()).padStart(2, '0');
+const minutes = String(now.getMinutes()).padStart(2, '0');
+const seconds = String(now.getSeconds()).padStart(2, '0');
+const currentTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+let form = reactive({
+  address: '',
+  longitude: '',
+  latitude: '',
+  event_title: '',
+  event_type: '',
+  event_level: '',
+  event_status: '1',
+  event_time: currentTime,
+  report_time: '1970-01-01 00:00:00',
+  deaths: '0',
+  injuries: '0',
+  missing: '0',
+  event_source: '',
+  event_description: '',
+  casualties: '',
+  del_flag: '9' // 临时事件
+});
+let geocoder = {};
+let width = ref('100%');
+let height = ref('100%');
+watch(
+    () => props.visible,
+    (n) => {
+      if (n) {
+        showPositionSelect.value = n;
+        nextTick(() => {
+          initMap();
+        });
+      }
+    },
+    {
+      immediate: true
+    }
+);
+onUnmounted(() => {
+  if (!!map) {
+    map.off('rightclick');
+    map.destroy();
+    map = null;
+  }
+});
+function handleInput(flag?: any) {
+  if (!form.address) return;
+
+  if (!flag) {
+    //搜索
+    total.value = 0;
+    pageNum.value = 1;
+  }
+
+  if (!placeSearch) {
+    placeSearch = new amap.PlaceSearch({
+      pageSize: pageSize.value, // 每页条数,默认10,范围1-50
+      pageIndex: pageNum.value, // 页码
+      extensions: 'all' // 默认base,返回基本地址信息;all:返回详细信息
+    });
+  }
+
+  searchPop.value = true;
+  placeSearch.setPageIndex(pageNum.value);
+  placeSearch.search(form.address, (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;
+  handleInput(1);
+}
+function closeSearchList() {
+  searchPop.value = false;
+  searchList.value = [];
+  total.value = 0;
+  pageNum.value = 1;
+}
+// 地图中心的平移至指定点位置
+function handlePanTo(index) {
+  let lnglat = searchList.value[index].lnglat;
+  form.address = searchList.value[index].name + '(' + searchList.value[index].address + ')';
+  form.longitude = 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);
+};
+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();
+
+function submit() {
+  if (!form.address) {
+    showFailToast('详细地址不能为空');
+  } else if (!form.longitude) {
+    showFailToast('经度不能为空');
+  } else if (!form.latitude) {
+    showFailToast('纬度不能为空');
+  } else {
+    addEvent(form).then((res) => {
+      emits('confirm', res);
+      handleClose();
+    });
+  }
+}
+</script>
+
+<style  lang="scss"scoped>
+.position-container {
+  height: calc(100vh - 250px);
+  min-height: 60%;
+  display: flex;
+  flex-direction: column;
+  .position-header {
+    font-size: 16px;
+    font-weight: bold;
+    height: 45px;
+    line-height: 45px;
+    border-bottom: 1px solid #eeeeee;
+    padding: 0 10px;
+    color: #445267;
+  }
+  #map {
+    width: 100%;
+    flex: 1;
+  }
+}
+.scroll_box {
+  width: 100%;
+  background-color: #fff;
+  position: absolute;
+  left: 0;
+  top: 45px;
+  z-index: 9;
+  padding: 10px;
+  border-radius: 3px;
+  .scroll-header {
+    height: 45px;
+    line-height: 45px;
+    font-size: 16px;
+  }
+  .close-icon {
+    position: absolute;
+    right: 10px;
+    top: 10px;
+    cursor: pointer;
+    font-size: 20px;
+    width: 30px;
+    height: 30px;
+    background: url('@/assets/images/close.png') no-repeat;
+    background-size: 100% 100%;
+  }
+}
+.scroll {
+  width: 100%;
+  height: 380px;
+  overflow-y: auto;
+
+  .item {
+    display: flex;
+    font-size: 14px;
+    cursor: pointer;
+    padding: 8px;
+    .text {
+      color: #3385ff;
+      margin-bottom: 6px;
+    }
+  }
+}
+.box {
+  border-bottom: 1px solid #eeeeee;
+}
+</style>

+ 98 - 7
src/views/mobileControl/index.vue

@@ -2,7 +2,7 @@
   <div class="container">
     <div class="top-content">
       <!--    <YztMap v-if="['satellite2', 'satellite3'].includes(activeMap)" ref="map2Ref" :active-map="activeMap" :point-type="pointType" />-->
-      <Map ref="mapRef" :active-map="activeMap" :point-type="pointType" :class="showMenu && !!eventId && !fullscreen ? 'containerHeight1' : 'containerHeight2'"/>
+      <Map ref="mapRef" :active-map="activeMap" :point-type="pointType" :class="showMenu && !!eventId && !temp && !fullscreen ? 'containerHeight1' : 'containerHeight2'"/>
       <div v-show="!fullscreen" class="top-left-panel">
       </div>
       <div class="top-right-panel">
@@ -17,7 +17,7 @@
           <i class="back-btn" />
           <div>首页</div>
         </div>
-        <div v-show="!eventId" class="button2">
+        <div v-show="!eventId" class="button2" @click="handleShowPosition">
           <i class="command-btn" />
           <div>指挥作战</div>
         </div>
@@ -34,27 +34,50 @@
           <div>协同标绘</div>
         </div>
       </div>
-      <i v-if="!!eventId" v-show="!fullscreen" :class="showMenu ? 'arrow-icon' : 'arrow-icon turn'" @click="showMenu = !showMenu" />
+      <i v-if="!!eventId && !temp" v-show="!fullscreen" :class="showMenu ? 'arrow-icon' : 'arrow-icon turn'" @click="showMenu = !showMenu" />
     </div>
 
-    <div v-if="!!eventId" v-show="showMenu && !fullscreen">
+    <div v-if="!!eventId && !temp" v-show="showMenu && !fullscreen">
       <EventBox :eventId="eventId" />
     </div>
+    <!--地点选择-->
+    <PositionSelect v-model:visible="showPositionSelect" @confirm="handleEnterCommand" />
+    <!--临时结束指挥-->
+    <van-dialog v-model:show="endEventState.show" title="结束指挥" confirm-button-text="结束指挥" show-cancel-button @close="handleClose" @confirm="submit">
+      <div class="form">
+        <div class="form-item">
+          <i class="icon" />
+          <div class="form-label">灾害事件:</div>
+          <div class="form-select" @click="endEventState.showPicker = true">{{ endEventState.eventId }}</div>
+        </div>
+        <div class="form-text">注意:本次指挥未关联事件,指挥记录将不会保留。若要保留记录,请关联事件。</div>
+      </div>
+    </van-dialog>
+    <van-popup v-model:show="endEventState.showPicker" round position="bottom">
+      <van-picker
+          :columns="endEventState.columns"
+          :columns-field-names="{ text: 'event_title', value: 'event_id' }"
+          @cancel="endEventState.showPicker = false"
+          @confirm="onConfirm"
+      />
+    </van-popup>
   </div>
-
 </template>
 
 <script lang="ts" setup>
-import {onMounted, ref} from "vue";
+import {onMounted, reactive, ref} from "vue";
 import {useRoute, useRouter} from "vue-router";
 import EventBox from "./EventBox.vue";
 import SearchBtn from "./SearchBtn.vue";
 import {deepClone} from "@/utils";
 import {iconList} from "@/components/Map/mapData";
+import PositionSelect from "@/views/mobileControl/PositionSelect.vue";
+import {getEvent} from "@/api/duty/eventing";
 
 const router = useRouter();
 const route = useRoute();
 const eventId = ref('');
+const temp = ref(true);
 let fullscreen = ref(false);
 let showMenu = ref(true);
 let mapRef = ref(null);
@@ -62,10 +85,24 @@ let map2Ref = ref(null);
 // logical vectorgraph satellite satellite2 satellite3
 let activeMap = ref('vectorgraph');
 let pointType = ref([]);
+let endEventState = reactive({
+  show: true,
+  showPicker: false,
+  queryParams: {
+    page: 1,
+    page_size: 100
+  },
+  columns: [],
+  eventId: ''
+});
 
 
 const toIndex = () => {
-  router.push('/leader/index');
+  if (!temp) {
+    router.push('/leader/index');
+  } else {
+    endEventState.show = true;
+  }
 };
 
 // 点击搜索结果,添加标注
@@ -114,8 +151,25 @@ const getMap = () => {
   }
   return map;
 }
+let showPositionSelect = ref(false);
+const handleShowPosition = () => {
+  showPositionSelect.value = true;
+}
+const handleEnterCommand = (res) => {
+  temp.value = true;
+  eventId.value = res.data;
+}
 onMounted(() => {
   eventId.value = route.query.event_id as string;
+  getEvent(endEventState.queryParams).then((res) => {
+    const data = [];
+    res.data.forEach((item) => {
+      if (!!item.event_title) {
+        data.push(item);
+      }
+    })
+    endEventState.columns = data;
+  });
 })
 </script>
 
@@ -244,4 +298,41 @@ onMounted(() => {
 .containerHeight2 {
   height: calc(100vh - 55px);
 }
+.form {
+  padding: 15px 20px 0;
+  .form-item {
+    display: flex;
+    align-items: center;
+    .icon {
+      flex-shrink: 0;
+      width: 17px;
+      height: 16px;
+      background: url('@/assets/images/event/icon11.png') no-repeat;
+      background-size: 100% 100%;
+      margin-right: 5px;
+    }
+    .form-label {
+      flex-shrink: 0;
+      font-size: 14px;
+    }
+    .form-select {
+      flex: 1;
+      height: 30px;
+      background: #FFFFFF;
+      border: 1px solid #DCE0EE;
+      border-radius: 2px;
+      margin-left: 6px;
+      padding-right: 40px;
+      position: relative;
+      &::before {
+        content: '';
+      }
+    }
+  }
+  .form-text {
+    font-size: 14px;
+    color: #FF2F3C;
+    margin: 10px 0;
+  }
+}
 </style>