您的当前位置:首页>全部文章>文章详情

【AntDesignPro】使用高德地图设置考勤区域

CrazyPanda发表于:2023-12-14 19:45:35浏览:761次TAG:

参考高德开放平台https://lbs.amap.com/api/javascript-api-v2/guide/abc/amap-react

功能要求:使用AntDesignPro开发系统管理端,考勤模块需要设置APP考勤打卡区域,需要页面显示地图定位并设置考勤范围(地图上画圈),以便APP在画圈范围内打卡使用。

1、 准备

image.png

2、 下载react类组件代码

image.png


image.png

参考官网流程,可正常加载出地图组件,下面是我的页面和组件文件

image.png

组件文件

image.png


3、 安装并引入AmAP Loader

npm i @amap/amap-jsapi-loader --save

组件文件引入

import React, { Component } from 'react';
import AmapLoader from '@amap/amap-jsapi-loader';
import './MapContainer.css';
import { ProForm, ProFormItem, ProFormText } from '@ant-design/pro-components';
import { Button, Col, Form, Input, message, Row } from 'antd';

4、 由于是新申请的key,需要配置秘钥(2021-12-02以前申请的key)可忽略此步骤

在引用文件下直接写(保证在使用key之前引入就可以):

window._AMapSecurityConfig = {
  securityJsCode: 'xxxxxxxxxxxxxxxxx',
};

5、 参考官网,绘制地图

// 2.dom渲染成功后进行map对象的创建
  componentDidMount() {
    let that = this;
    AmapLoader.load({
      key: 'xxxxxxxxxxxxxx', // 申请好的Web端开发者Key,首次调用 load 时必填
      version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
      plugins: ['AMap.Map', 'AMap.Geocoder', 'AMap.Marker', 'AMap.LngLat', 'AMap.Circle'], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
    })
      .then((AMap) => {
        const map = new AMap.Map('container', {
          //设置地图容器id
          resizeEnable: true,
          zoom: 11,
        });
        let oldmarker = 1;
        AMap.plugin('AMap.Geocoder', function () {
          const geocoder = new AMap.Geocoder({
            city: '0371', //默认城市
          });
        });
      })
      .catch((e) => {
        console.log(e);
      });
  }

  render() {
    // 1.初始化创建地图容器,div标签作为地图容器,同时为该div指定id属性;

    return (
      <div>
        <div id="container" className="map" style={{ height: '300px' }}></div>
      </div>
    );
  }
}

6、 地图显示出来后,第一步已经完成了,接下来需要根据页面输入地址,获取地址坐标值

image.png

此处需要用到地理编码和你地理编码接口

image.png

在Amap.plugin方法里面继续写入

function geoCode() {
            let address = document.getElementById('address').value;
            console.log(address);
            if (address) {
              geocoder.getLocation(address, function (status, result) {
                console.log(status);
                console.log(result);
                if (status === 'complete' && result.geocodes.length) {
                  let lnglat = result.geocodes[0].location;
                  //设置页面值
                                      let radius = document.getElementById('radius').value;
                                      document.getElementById('gps').value = lnglat.lng + ',' + lnglat.lat;
                                      that.onChangeGps(lnglat.lng + ',' + lnglat.lat);
                } else {
                  message.error('请输入有效的地址信息');
                }
              });
            }
          }
          //定义页面按钮点击事件
          document.getElementById('address_confirm').onclick = geoCode;

7、获取地址坐标成功后,需要在地图画圈

此处用到添加覆盖物,这里使用圆形,也可以设置其他形状


1702551701507.jpg

画圆圈需要中心坐标点,次坐标由上一步获得,然后设置半径,此值由页面输入

定义画圆方法,此方法定义在了Amap.plugin外面

function addCircle() {
          if (document.getElementById('gps').value) {
            let lnglat = document.getElementById('gps').value.split(',');
            let radius = document.getElementById('radius').value;
            console.log(lnglat);
            console.log(radius);
            map.clearMap();    //清除全部覆盖物
            const circle = new AMap.Circle({
              center: new AMap.LngLat(lnglat[0], lnglat[1]), // 圆心位置
              radius: radius, //半径
              strokeColor: '#F33', //线颜色
              strokeOpacity: 1, //线透明度
              strokeWeight: 3, //线粗细度
              fillColor: '#ee2200', //填充颜色
              fillOpacity: 0.35, //填充透明度
            });
            map.add(circle);//添加覆盖物
            map.setFitView();//根据覆盖物范围调整视野
          }
        }

然后在上一步获取坐标值的地方,调用画圈方法



function geoCode() {
            let address = document.getElementById('address').value;
            console.log(address);
            if (address) {
              geocoder.getLocation(address, function (status, result) {
                console.log(status);
                console.log(result);
                if (status === 'complete' && result.geocodes.length) {
                  let lnglat = result.geocodes[0].location;
                  //设置页面值
                  let radius = document.getElementById('radius').value;
                  document.getElementById('gps').value = lnglat.lng + ',' + lnglat.lat;
                  that.onChangeGps(lnglat.lng + ',' + lnglat.lat);
                  //调用画圈方法
                  addCircle(); 
                } else {
                  message.error('请输入有效的地址信息');
                }
              });
            }
          }

到此,已经实现根据页面地址和半径范围,检索地址和画圈了,如图

image.png

修改半径范围,可调整区域大小

image.png

8、 编辑时,需要进入页面直接显示画圈范围,并显示标记的地址

在Amap.plugin方法里面最后,直接调用画圈方法 addCircle(),可以根据编辑页面初始值直接画圈。

根据坐标获取地理位置,需要用到逆向地理编码方法,在Amap.plugin方法里面添加逆地理编码方法

//根据坐标获取地址
          function regeoCode() {
            let lnglat = document.getElementById('gps').value.split(',');
            //需要正确配置地图apikey才可以获取
            geocoder.getAddress(lnglat, function (status, result) {
              console.log(status);
              console.log(result);
              if (status === 'complete' && result.regeocode) {
                let address = result.regeocode.formattedAddress;
                document.getElementById('address').value = address;
              } else {
                layer.msg('根据经纬度查询地址失败');
              }
            });
          }

这样就可以在编辑页面,初始化时直接显示地址并画圈

image.png

9、 最后,调用组件问题

地址和半径都由页面表单设置,涉及到与组件交互,表单赋值的问题,最终试了好久才实现。

(初学的时候做的这个功能,对组件交互不是很熟,后来也没再调整过,也许有更简单的方法吧)

先给表单设置from

const [addForm] = Form.useForm();
<ModalForm
        title="新建签到点"
        width="800px"
        form={addForm}
        onInit={() => {
          addForm.resetFields();
        }}
        visible={createModalVisible}
        onVisibleChange={setCreateModalVisible}
        onFinish={async (value) => {
          const success = await modify(value as API.CompanyItem);
          if (success) {
            setCreateModalVisible(false);
            if (actionRef.current) {
              actionRef.current.reload();
            }
          }
        }}
        modalProps={{
          destroyOnClose: true,
          maskClosable: false,
          bodyStyle: { maxHeight: 500, overflowY: 'auto' },
        }}
      >

然后将此form作为参数,直接传入组件内,组件内form的属性同样可以使用,但是不会提示对应的属性方法,此处直接写就可以(我在组件内使用的时候,一直没有提示form方法,以致一直以为form不能使用)

<MapComponent form={addForm}></MapComponent>

组件内获取参数并使用

constructor(props) {
    super(props);
  }

  onChangeGps(value) {
    this.props.form.setFieldValue('gps', value);//将坐标值赋值给表单
  }

10、 完整代码

页面index.tsx新建表单

<ModalForm
        title="新建签到点"
        width="800px"
        form={addForm}
        onInit={() => {
          addForm.resetFields();
        }}
        visible={createModalVisible}
        onVisibleChange={setCreateModalVisible}
        onFinish={async (value) => {
          const success = await modify(value as API.CompanyItem);
          if (success) {
            setCreateModalVisible(false);
            if (actionRef.current) {
              actionRef.current.reload();
            }
          }
        }}
        modalProps={{
          destroyOnClose: true,
          maskClosable: false,
          bodyStyle: { maxHeight: 500, overflowY: 'auto' },
        }}
      >
        <ProFormSelect
          name="cid"
          label="公司名称"
          showSearch
          options={companySelect}
          rules={[
            {
              required: true,
              message: '请选择公司',
            },
          ]}
          placeholder="请选择公司"
        />
        <ProFormText
          name="name"
          label="签到点名称"
          rules={[
            {
              required: true,
              message: '请输入签到点名称',
            },
            {
              max: 16,
              message: '最多可输入16个字符',
            },
          ]}
          placeholder="请输入签到点名称"
        />
        <ProFormText
          name="radius"
          id="radius"
          label="签到半径(米)"
          placeholder="请输入签到半径"
          initialValue={200}
        />
        <Row gutter={24}>
          <Col xl={{ span: 21 }}>
            <ProFormText name="address" id="address" label="签到地址" placeholder="请输入地址" />
          </Col>
          <Col xl={{ span: 2 }}>
            <Button key="search" type="primary" id="address_confirm" style={{ marginTop: 29 }}>
              搜索
            </Button>
          </Col>
        </Row>
        <ProFormText hidden name="gps" id="gps" />
        <MapComponent form={addForm}></MapComponent>
      </ModalForm>

页面index.tsx编辑表单

<ModalForm
        title="编辑签到点"
        width="800px"
        form={editForm}
        onInit={() => {
          editForm.resetFields();
        }}
        visible={updateModalVisible}
        onVisibleChange={setUpdateModalVisible}
        onFinish={async (value) => {
          const success = await modify(value as API.CompanyItem);
          if (success) {
            setUpdateModalVisible(false);
            if (actionRef.current) {
              actionRef.current.reload();
            }
          }
        }}
        modalProps={{
          destroyOnClose: true,
          maskClosable: false,
          bodyStyle: { maxHeight: 500, overflowY: 'auto' },
        }}
      >
        <ProFormSelect
          name="cid"
          label="公司名称"
          showSearch
          options={companySelect}
          rules={[
            {
              required: true,
              message: '请选择公司',
            },
          ]}
          disabled
          placeholder="请选择公司"
          initialValue={currentRow?.cid || ''}
        />
        <ProFormText hidden name="id" initialValue={currentRow?.id} />
        <ProFormText
          name="name"
          label="签到点名称"
          rules={[
            {
              required: true,
              message: '请输入签到点名称',
            },
            {
              max: 16,
              message: '最多可输入16个字符',
            },
          ]}
          placeholder="请输入签到点名称"
          initialValue={currentRow?.name}
        />
        <ProFormText
          name="radius"
          id="radius"
          label="签到半径(米)"
          placeholder="请输入签到半径"
          initialValue={currentRow?.radius || null}
        />
        <Row gutter={24}>
          <Col xl={{ span: 21 }}>
            <ProFormText
              name="address"
              id="address"
              label="签到地址"
              placeholder="请输入地址"
              initialValue={currentRow?.address || null}
            />
          </Col>
          <Col xl={{ span: 2 }}>
            <Button key="search" type="primary" id="address_confirm" style={{ marginTop: 29 }}>
              搜索
            </Button>
          </Col>
        </Row>
        <ProFormText hidden name="gps" id="gps" initialValue={currentRow?.gps || null} />
        <MapComponent form={editForm}></MapComponent>
      </ModalForm>

地图组件MapContainer.js

import React, { Component } from 'react';
import AmapLoader from '@amap/amap-jsapi-loader';
import './MapContainer.css';
import { ProForm, ProFormItem, ProFormText } from '@ant-design/pro-components';
import { Button, Col, Form, Input, message, Row } from 'antd';

window._AMapSecurityConfig = {
  securityJsCode: 'xxxxxxxxxxxxxx',
};

class MapComponent extends Component {
  constructor(props) {
    super(props);
  }

  onChangeGps(value) {
    this.props.form.setFieldValue('gps', value);
  }

  // 2.dom渲染成功后进行map对象的创建
  componentDidMount() {
    let that = this;
    AmapLoader.load({
      key: 'xxxxxxxxxxxx', // 申请好的Web端开发者Key,首次调用 load 时必填
      version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
      plugins: ['AMap.Map', 'AMap.Geocoder', 'AMap.Marker', 'AMap.LngLat', 'AMap.Circle'], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
    })
      .then((AMap) => {
        const map = new AMap.Map('container', {
          //设置地图容器id
          resizeEnable: true,
          zoom: 11,
        });
        let oldmarker = 1;
        AMap.plugin('AMap.Geocoder', function () {
          const geocoder = new AMap.Geocoder({
            city: '0371', //默认城市
          });

          //根据坐标获取地址
          function regeoCode() {
            let lnglat = document.getElementById('gps').value.split(',');
            //需要正确配置地图apikey才可以获取
            geocoder.getAddress(lnglat, function (status, result) {
              console.log(status);
              console.log(result);
              if (status === 'complete' && result.regeocode) {
                let address = result.regeocode.formattedAddress;
                document.getElementById('address').value = address;
              } else {
                layer.msg('根据经纬度查询地址失败');
              }
            });
          }

          function geoCode() {
            let address = document.getElementById('address').value;
            console.log(address);
            if (address) {
              geocoder.getLocation(address, function (status, result) {
                console.log(status);
                console.log(result);
                if (status === 'complete' && result.geocodes.length) {
                  let lnglat = result.geocodes[0].location;
                  let radius = document.getElementById('radius').value;
                  document.getElementById('gps').value = lnglat.lng + ',' + lnglat.lat;
                  that.onChangeGps(lnglat.lng + ',' + lnglat.lat);
                  addCircle();
                } else {
                  message.error('请输入有效的地址信息');
                }
              });
            }
          }

          document.getElementById('address_confirm').onclick = geoCode;

          addCircle();
        });

        function addCircle() {
          if (document.getElementById('gps').value) {
            let lnglat = document.getElementById('gps').value.split(',');
            let radius = document.getElementById('radius').value;
            console.log(lnglat);
            console.log(radius);
            map.clearMap();
            const circle = new AMap.Circle({
              center: new AMap.LngLat(lnglat[0], lnglat[1]), // 圆心位置
              radius: radius, //半径
              strokeColor: '#F33', //线颜色
              strokeOpacity: 1, //线透明度
              strokeWeight: 3, //线粗细度
              fillColor: '#ee2200', //填充颜色
              fillOpacity: 0.35, //填充透明度
            });
            map.add(circle);
            map.setFitView();
          }
        }
      })
      .catch((e) => {
        console.log(e);
      });
  }

  render() {
    // 1.初始化创建地图容器,div标签作为地图容器,同时为该div指定id属性;

    return (
      <div>
        <div id="container" className="map" style={{ height: '300px' }}></div>
      </div>
    );
  }
}
//导出地图组建类
export default MapComponent;

MapContainer.css文件没有改动

#container {
  width: 100%;
  margin: 0px;
  padding: 0px;
}

已上,就是AntDesignPro使用高德地图设置考勤区域的全部内容。

猜你喜欢

【AntDesignPro】Ant Design Pro学习记录—ModalForm的使用(二)
&nbsp;目录一、ModalForm高度设置二、ModalForm点击阴影背景,不隐藏弹框三、ProFormSelect联动四、ProFormText关联赋值一、ModalForm高度设置在modalProps中设置bodyStyle:{height:500,overflowY:&#39;scroll&#39;}编辑效果如下:编辑二、ModalForm点击阴影背景,不隐藏弹框同样在modalProps里面,配置maskClosable: false,就可以实现点击弹框外阴影,不隐藏弹框&lt;
发表于:2023-11-28 浏览:1194 TAG:
【React】使用React实现一个内容滑动组件
最近在做项目时遇到一个需求,需要让一个列表能够通过点击按钮进行滚动,每次都是一屏的距离,不足则结束。并且,这个列表项是在react-grid-layout中的某一个模块内。所以包裹这个列表的容器会随时发生变化。在完成这个组件后,通过这篇文章总结一下。UI/原型分析那么从上面的功能描述以及项目中的UI,我们可以分析得到这样一个假想图:我们需要实现一个容器来作为我们的可视区域,并且这个容器是可以伸缩的。列表内容如果超出容器的可视区域,那么就会被隐藏。需要左右都有按钮,来支持用户左右滑动内容来查看,每
发表于:2024-04-10 浏览:330 TAG:
【React】react面试题
React面试题文章目录React面试题一、react特性***React与Vue的区别*******1. Jsx的使用规范*******1.说说对 React 的理解?有哪些特性?DOM2.说说 Real DOM 和 Virtual DOM 的区别?优缺点?*******说说React中的虚拟dom?在虚拟dom计算的时候diff和key之间有什么关系*******3.说说React Jsx转换成真实DOM过程?4.说说你第mvc和mvvm的理解5.说说react中引入css的方式有哪几种?区
发表于:2023-12-05 浏览:1418 TAG:
【AntDesignPro】Ant Design Pro学习记录—ProTable的使用(一)
目录一、关于ProTable二、使用步骤1.新建页面2.修改接口3.接口调用4.数据显示和检索1)不同类型内容显示2)列表检索3)列表内容样式设置5.其它1)render的简单使用2)图片点击预览3)翻页总结前言因为项目需要,确定了Ant Design Pro框架来开发后台管理端,刚接触这套框架,而且配套的资料真的很少,只能基于官方demo和网上不完整的学习经验一次次尝试,终于有个像样的结果,记录一下研究学习的成果,也给需要的同学一些帮助。本次学习研究基于Ant Design Pro V5版本,
发表于:2023-11-28 浏览:836 TAG: #前端 #antd #AntDesignPro
【React】如何在 React 类中声明常量?
使用 react 开发应用程序时,有必要声明常量来存储在组件或应用程序的整个生命周期中保持不变的值。常量可以帮助提高代码可读性,提供管理共享值的中心位置,并增强可维护性。在本文中,我们将探讨如何在 react 类组件中声明常量。导入 React首先,我们假设您已经设置了 React 环境并且有一个可供使用的类组件。在声明常量之前,请确保您已导入必要的库。这包括导入 React,它是在 React 中构建用户界面的核心库。import&nbsp;React&nbsp;from&nbsp;&#39;
发表于:2024-04-16 浏览:302 TAG:
【AntDesignPro】Ant Design Pro学习记录—默认主题配色修改
&nbsp;版本:&nbsp;Ant Design Pro V5先参考下官网定制主题 - Ant Design再参考这篇文章antd pro 修改全局样式_tankpanv的博客-CSDN博客_antd修改全局样式最后自己实验:第一步,在config.ts文件中配置theme:&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&#39;primary-color&#39;:&nbsp;defaultSettings.primaryColor, &nbsp;&nbsp;},这种配置需
发表于:2023-11-28 浏览:786 TAG:
【AntDesignPro】Ant Design Pro学习记录—前后端一体化部署
目录前言一、系统配置二、ant design pro访问路径配置三、站点访问路径配置前言好长时间没记录了,使用ant design pro有一年了,期间陆续做了好几个项目,从陌生到熟练,还有好多钻研成果没记录,后续有时间陆续补上。之前几个项目一直是前后端分开部署的,需要配置两个站点域名访问,还要解决跨域session问题,这次把一体化部署记录一下。一、系统配置服务端用的LNMP,使用tp6框架,使用宝塔面板管理。tp站点先正常部署,步骤省略,见下图:配置网站目录和运行目录:&nbsp;编辑配置伪
发表于:2023-11-28 浏览:830 TAG:
【AntDesignPro】Ant Design Pro学习记录—搭建AntDesignPro脚手架
文章目录前言一、操作过程1.初始化2.完成后配置软连接3.继续执行4.进入应用5.安装依赖6.启动前言工作项目需要,使用了AntDesignPro开发,在此做一个学习研究记录。一、操作过程参考官网开始使用 - Ant Design Pro🏆 让中后台开发更简单 包含 table form 等多个组件。https://pro.ant.design/zh-CN/docs/getting-started在node.js npm yarn 环境配置好之后,按照官网操作运行1.初始化npm
发表于:2023-11-22 浏览:590 TAG: #前端 #antd #AntDesignPro
【AntDesignPro】Ant Design Pro学习记录—ModalForm的使用(一)
目录前言一、ModalForm销毁二、ModalForm编辑赋值三、ProFormUploadButton赋值四、其它总结前言使用了AntDesignPro,仿照TableList创建了自己的列表,列表添加编辑确成了困扰,添加编辑使用了ModalForm,有两个问题,一个使用后,页面数据无法清除,再点弹框还是原来的数据,第二个编辑的时候,初始数据赋值问题。AntDesignPro版本V5,开发工具VsCode。一、ModalForm销毁参考ant design的关闭ModalForm和Modal
发表于:2023-11-28 浏览:642 TAG:
【React】react页面加载远程css和js
在React中,您可以使用componentDidMount生命周期方法来动态加载远程CSS和JavaScript文件。代码如下import&nbsp;React,&nbsp;{&nbsp;Component&nbsp;}&nbsp;from&nbsp;&#39;react&#39;; &nbsp; class&nbsp;DynamicResources&nbsp;extends&nbsp;Component&nbsp;{ &nbsp;&nbsp;componentDidMount()&amp;nbs
发表于:2024-05-15 浏览:273 TAG: