dt项目 画区域的组件的封装

119 阅读1分钟

地图划区域的方法

import useComContainer from "./useComContainer";
declare type Data = Record<string, unknown>;
const { addCtrl:addComCtrl, removeCtrl: removeComCtrol} =  useComContainer();
export default function useDialogContainer(){
 
  let eleDiv: HTMLElement;
  const parentContainer = document.querySelector('.dialog-container');
  eleDiv = document.createElement('div');
  eleDiv.className = 'dilogWrap'
  parentContainer?.appendChild(eleDiv);
  const addCtrl = (vueEle: any,option ?:Data | null) => {
    return addComCtrl(eleDiv,vueEle,option);
  };
  const removeCtrl = () =>{
    removeComCtrol();
    // eleDiv.remove();
  }
  const isEleExist = () => {
    return  !!eleDiv.childElementCount;
  }
  return {
    addCtrl,
    removeCtrl,
    isEleExist,
  }
}

区域组件列表-添加区域-弹窗

<template>
  <div class="areaTable_add">
    <el-button size="small" color="#1cb16f" @click="addBjdRow">添加区域</el-button>
  </div>
  <el-table
    class="areaTable"
    :data="props.areaList"
    :size="'small'"
    max-height="320"
    :header-cell-style="{
      color: '#fff',
      backgroundColor: 'rgba(21, 29, 27, 1)',
      borderColor: 'rgba(40, 58, 51, 1)',
      padding: '0 0',
    }"
    :cell-style="{ backgroundColor: 'rgba(16, 19, 18, 1)', color: '#999999' }"
  >
    <el-table-column type="index" label="序号" align="center" width="100" />
    <el-table-column prop="shape" label="区域类型" align="center">
      <template #default="scope">
        <span>{{ getValue(scope.row.shape, shapeType2) }}</span>
      </template>
    </el-table-column>
    <el-table-column label="操作" align="center">
      <template #default="scope">
        <el-button color="#f5494a" size="small" @click="deleteBjdRow(scope.$index, scope.row)">删除</el-button>
      </template>
    </el-table-column>
  </el-table>
</template>

<script lang="ts">
export default {
  name: 'areaTable', // 区域表格
};
</script>

<script lang="ts" setup>
import { reactive, toRefs, watch, onUnmounted } from 'vue';
import { getValue, shapeType2, removeArea } from '@/utils/dict';
import areaTypePlus from '../areaTypePlus/index.vue';
import useDialogContainer from '@/views/comprehensiveSituation/hooks/useDialogContainer';
import { localStorage } from '@/utils/storage';

const { addCtrl: addDialogCtrl, removeCtrl: removeDialogCtrl } = useDialogContainer();

interface Props {
  areaList: any;
  close: Function;
  mapColor: string;
  maplabel: string;
}

const props = withDefaults(defineProps<Props>(), {
  areaList: [],
  close: () => {},
  mapColor: '',
  maplabel: '',
});

const state = reactive<any>({
  formData: {
    shape: 3,
    list: [{ flat: null, flon: null }],
    coordsObj: {},
  },
});

const { formData } = toRefs(state);

// 添加区域
const addBjdRow = () => {
  localStorage.set('mapColor', props.mapColor);
  localStorage.set('maplabel', props.maplabel);
  addDialogCtrl(areaTypePlus, { close: props.close, formData: state.formData });
};

// 删除区域
const deleteBjdRow = (index: number, row: any) => {
  localStorage.set('coordsRemove', 2);
  props.areaList.splice(index, 1);
  row.coordsObj.remove();
  row.coordsObj.marker.remove();
};

// 编辑区域弹窗-保存添加区域列表上
const getareaSave = () => {
  if (localStorage.get('coordsRemove') === 1) {
    const obj = { ...state.formData };
    props.areaList.push(obj);
  }
};

// 监听目标数据的变化
watch(
  () => state.formData,
  () => {
    getareaSave();
  },
  {
    deep: true,
  }
);

// 关闭弹窗清除地图区域
onUnmounted(() => {
  removeArea(props.areaList);
});
</script>
<style lang="scss">
@import './style.scss';
</style>

添加区域弹窗组件


<template>
  <el-dialog
    v-model="dialogVisible"
    class="taishi-dialog"
    title="编辑区域"
    draggable
    width="24%"
    :before-close="cancel"
  >
    <div class="areaType">
      <el-form ref="formRef" :model="state.formDataPlus" :label-width="'100px'">
        <el-form-item label="区域形状:">
          <el-radio-group v-model="state.formDataPlus.shape" class="list_radio2" @change="getShape">
              <!-- shapeType2=  { code: 1, value: '点' },{ code: 2, value: '线' },{ code: 3, value: '圆形' },{ code: 4, value: '扇形' },{ code: 5, value: '多边形' } -->
            <el-radio :label="item.code" :key="item.code" v-for="item in shapeType2">{{ item.value }} </el-radio>
          </el-radio-group>
        </el-form-item>
      </el-form>
      <el-divider />
      <div>
        <div class="areaType_add">
          <el-button size="small" color="#1cb16f" @click="setArea">设置</el-button>
          <!-- <el-button size="small" color="#1cb16f" @click="add">新增</el-button> -->
          <!-- <el-button size="small" color="#1cb16f" @click="cases">案例1</el-button> -->
        </div>
        <el-table
          class="areaType_table"
          :data="state.formDataPlus.list"
          :size="'small'"
          max-height="320"
          :header-cell-style="{
            color: '#fff',
            backgroundColor: 'rgba(21, 29, 27, 1)',
            borderColor: 'rgba(40, 58, 51, 1)',
            padding: '0 0',
          }"
          :cell-style="{ backgroundColor: 'rgba(16, 19, 18, 1)', color: '#999999' }"
        >
          <el-table-column type="index" label="序号" align="center" width="80">
            <template #default="scope">
              <span>{{ scope.$index + 1 }}</span>
            </template>
          </el-table-column>
          <el-table-column prop="flon" label="经度" align="center">
            <template #default="scope">
              <span
                ><el-input
                  type="number"
                  v-model="scope.row.flon"
                  placeholder="请输入"
                  clearable
                  @blur="getAreaData('flatFlon')"
              /></span>
            </template>
          </el-table-column>
          <el-table-column prop="flat" label="纬度" align="center">
            <template #default="scope">
              <span
                ><el-input
                  type="number"
                  v-model="scope.row.flat"
                  placeholder="请输入"
                  clearable
                  @blur="getAreaData('flatFlon')"
              /></span>
            </template>
          </el-table-column>
          <el-table-column label="操作" align="center">
            <template #default="scope">
              <el-button color="#1cb16f" size="small" @click="dt(scope.$index)">标点</el-button>
              <!-- <el-button
                v-if="state.formDataPlus.shape === 2 || state.formDataPlus.shape === 5"
                color="#f5494a"
                size="small"
                @click="deleteBjdRow(scope.$index)"
                >删除</el-button
              > -->
            </template>
          </el-table-column>
        </el-table>
        <el-form ref="formRef" :model="state.formDataPlus" :label-width="'120px'">
          <div v-if="state.formDataPlus.shape === 3" class="elForm">
            <el-form-item label="圆半径:">
              <el-input
                type="number"
                style="width: 240px"
                v-model="state.formDataPlus.circleRadius"
                @blur="getAreaData('circleRadius')"
                placeholder="请输入"
              >
                <template #suffix></template>
              </el-input>
            </el-form-item>
            <el-form-item label="圆中心高度:" style="margin: 15px 0">
              <el-input
                type="number"
                disabled
                style="width: 240px"
                v-model="state.formDataPlus.circleCenterHeight"
                placeholder="请输入"
              >
                <template #suffix></template>
              </el-input>
            </el-form-item>
          </div>
          <div v-if="state.formDataPlus.shape === 4" class="elForm">
            <el-form-item label="开始角度范围:" style="margin: 15px 0">
              <el-input style="width: 240px" v-model="state.formDataPlus.startAngle" placeholder="请输入">
                <template #suffix></template>
              </el-input>
            </el-form-item>
            <el-form-item label="结束角度范围:" style="margin: 15px 0">
              <el-input style="width: 240px" v-model="state.formDataPlus.stopAngle" placeholder="请输入">
                <template #suffix></template>
              </el-input>
            </el-form-item>
          </div>
        </el-form>
      </div>
    </div>
    <template #footer>
      <span class="dialog-footer">
        <!-- <el-button type="primary" @click="cases"> 案例1 </el-button> -->
        <el-button type="primary" @click="save"> 保存 </el-button>
        <el-button @click="cancel">取消</el-button>
      </span>
    </template>
  </el-dialog>
</template>

<script lang="ts">
export default {
  name: 'areaType', // 区域弹窗
};
</script>

<script lang="ts" setup>
import { ref, reactive, toRefs, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import { getComFixed3, getFlatFlon, shapeType2 } from '@/utils/dict';
import { localStorage } from '@/utils/storage';
import useCommandDraw from './useCommandDraw';
import useInterActionCircle from '@/views/comprehensiveSituation/hooks/useInterActionCircle';
import useInterActionPolygon from '@/views/comprehensiveSituation/hooks/useInterActionPolygon';
import L from 'leaflet';

const { addComMarker } = useCommandDraw();
const { drawCircle, cancelDraw } = useInterActionCircle(); // 画圆 取消画圆
const { drawPolygon, cancelDraw2 } = useInterActionPolygon(); // 画多边形 取消多边形

const dialogVisible = ref(true);

const props = withDefaults(
  defineProps<{
    close: Function;
    formData: any;
  }>(),
  {
    close: () => {},
    formData: {},
  }
);

const state = reactive<any>({
  formDataPlus: {
    shape: 3,
    list: [{ flat: null, flon: null }],
    circleCenterHeight: 0,
    coordsObj: {},
  },
});

const { formDataPlus } = toRefs(state);

// 失去焦点-改变数据后地图区域重新绘制
const getAreaData = (type: string) => {
  if (state.formDataPlus.shape === 3 && type === 'flatFlon') {
    state.formDataPlus.coordsObj.setLatLng(L.latLng(state.formDataPlus.list[0].flat, state.formDataPlus.list[0].flon));
  }
  if (state.formDataPlus.shape === 3 && type === 'circleRadius') {
    state.formDataPlus.coordsObj.setRadius(state.formDataPlus.circleRadius);
  }
  if (state.formDataPlus.shape === 5 && type === 'flatFlon') {
    const latLngs = state.formDataPlus.list.map((item: any, cIndex: number) => {
      const latLng = L.latLng(item.flat, item.flon);
      return latLng;
    });
    state.formDataPlus.coordsObj.setLatLngs(latLngs);
  }
};

// 保存
const save = () => {
  if (state.formDataPlus.shape === 3) {
    props.formData.shape = state.formDataPlus.shape;
    props.formData.list = state.formDataPlus.list;
    props.formData.circleRadius = state.formDataPlus.circleRadius;
    props.formData.circleCenterHeight = state.formDataPlus.circleCenterHeight;
    props.formData.coordsObj = state.formDataPlus.coordsObj;
  } else if (state.formDataPlus.shape === 5) {
    props.formData.shape = state.formDataPlus.shape;
    props.formData.list = state.formDataPlus.list;
    props.formData.coordsObj = state.formDataPlus.coordsObj;
  }
  localStorage.set('coordsRemove', 1);
  cancel2();
};

// 未保存前关闭弹窗-清除区域
const cancel = () => {
  props.close();
  dialogVisible.value = false;
  cancelDraw();
  cancelDraw2();
  localStorage.set('coordsRemove', 2);
  removeLayer();
};

// 保存后关闭弹窗-不清除区域
const cancel2 = () => {
  props.close();
  dialogVisible.value = false;
};
// 移除图层
const removeLayer = () => {
  if (Object.keys(state.formDataPlus.coordsObj).length > 0) {
    state.formDataPlus.coordsObj.remove();
    state.formDataPlus.list = [{ flat: null, flon: null }];
    state.formDataPlus.circleRadius = 0;
    if (state.formDataPlus.coordsObj.marker) {
      state.formDataPlus.coordsObj.marker.remove();
    }
  }
};
// 切换区域形状-绘制
const getShape = async () => {
  removeLayer();
  if (state.formDataPlus.shape === 3) {
    cancelDraw2();
    const coords: any = await drawCircle();
    state.formDataPlus.list = [
      { flat: getComFixed3(coords._latlng.lat, 6), flon: getComFixed3(coords._latlng.lng, 6) },
    ];
    state.formDataPlus.circleRadius = getComFixed3(coords._mRadius, 2);
    state.formDataPlus.coordsObj = coords;
    console.log(coords);

    state.formDataPlus.circleCenterHeight = 0;
  } else if (state.formDataPlus.shape === 5) {
    cancelDraw();
    const coords: any = await drawPolygon();
    state.formDataPlus.coordsObj = coords;
    coords._latlngs[0].pop();
    const latLngList = getFlatFlon(coords._latlngs[0]);
    state.formDataPlus.list = latLngList;
  }
};

// 案例1-测试用
const cases = () => {
  switch (state.formDataPlus.shape) {
    case 1:
      state.formDataPlus.list = [{ flat: 39.846932, flon: 116.156543 }];
      break;
    case 2:
      state.formDataPlus.list = [
        { flat: 39.846932, flon: 116.156543 },
        { flat: 39.845582, flon: 116.156872 },
      ];
      break;
    case 3:
      state.formDataPlus.list = [{ flat: 39.846932, flon: 116.156543 }];
      state.formDataPlus.circleRadius = 10000;
      state.formDataPlus.circleCenterHeight = 0;
      break;
    case 4:
      state.formDataPlus.list = [{ flat: 39.846932, flon: 116.156543 }];
      state.formDataPlus.startAngle = 0;
      state.formDataPlus.stopAngle = 360;
      break;
    case 5:
      state.formDataPlus.list = [
        { flat: 39.846932, flon: 116.156543 },
        { flat: 39.845582, flon: 116.156872 },
        { flat: 39.844607, flon: 116.157784 },
        { flat: 39.843831, flon: 116.158367 },
        { flat: 39.843302, flon: 116.159316 },
      ];
      break;
  }
};

// 重新绘制
const setArea = () => {
  removeLayer();
  getShape();
};

// 新增
const add = () => {
  if (
    (state.formDataPlus.shape === 1 || state.formDataPlus.shape === 3 || state.formDataPlus.shape === 4) &&
    state.formDataPlus.list.length > 0
  ) {
    return ElMessage.error('最多添加1个点');
  }

  const obj = { flon: null, flat: null };
  state.formDataPlus.list.push(obj);
};

// 删除某个形状的点
// const deleteBjdRow = (index: number) => {
//   state.formDataPlus.list.splice(index, 1);
// };

// 地图标点
const dt = async (index: number) => {
  const coords = (await addComMarker(index)) as number[];
  state.formDataPlus.list[index].flon = getComFixed3(coords[1], 6);
  state.formDataPlus.list[index].flat = getComFixed3(coords[0], 6);
  getAreaData('flatFlon');
};

onMounted(() => {
  getShape();
});
</script>

<style lang="scss">
.areaTypePlus {
  width: 0 !important;
  height: 0 !important;
}
.elForm {
  margin-top: 5px;
}
</style>

<style lang="scss">
@import './style.scss';
</style>

引入区域组件具体页面

<template> 
    <div>
      <el-form-item
        :label="区域"
        prop="areaList"
      >
        <areaTable :areaList="formData.areaList" />
      </el-form-item>
    </div>
</template>
        
<script setup lang="ts">
<areaTable :areaList="formData.areaList" />
<script>

// 区域解析-最终要的数据
const areaTypleList = getAreaTypleList(state.formData.areaList);
  
  
 // 区域类型转化-按照指定的结构
export const getAreaTypleList = (arr: any) => {
  const list = arr.map((item: any) => {
    const obj: any = {
      type: 'Feature',
      geometry: {
        type: null,
        coordinates: [],
      },
    };
    const { shape, list, circleRadius, startAngle, stopAngle } = item;
    switch (shape) {
      case 1: // 点 一维
        obj.properties = {};
        obj.geometry.type = 'Point';
        obj.geometry.coordinates = getFlatFlonList(list)[0];
        break;
      case 2: //线 二维
        obj.properties = [];
        obj.geometry.type = 'LineString';
        obj.geometry.coordinates = getFlatFlonList(list);
        break;
      case 3: // 圆 一维
        obj.properties = {};
        obj.geometry.type = 'Circle';
        obj.geometry.radius = circleRadius;
        obj.geometry.coordinates = getFlatFlonList(list)[0];
        break;
      case 4: // 扇形 一维
        obj.properties = {};
        obj.geometry.type = 'SemiCircle';
        obj.geometry.startAngle = startAngle;
        obj.geometry.stopAngle = stopAngle;
        obj.geometry.coordinates = getFlatFlonList(list)[0];
        break;
      case 5: // 多边形 三维
        obj.properties = [];
        obj.geometry.type = 'Polygon';
        obj.geometry.coordinates = [getFlatFlonList(list)];
        break;
    }
    return obj;
  });
  return list;
};