diff --git a/docs/blocks/administrative-select.md b/docs/blocks/administrative-select.md new file mode 100644 index 00000000..af08f257 --- /dev/null +++ b/docs/blocks/administrative-select.md @@ -0,0 +1,30 @@ +--- +toc: false +order: 3 +nav: + title: 区块 + path: /blocks + order: 4 +--- + +## 城市联级选择器 + +### 介绍 + +用于快速查找中国省/市/县行政区域并快速定位的控件,基于 Ant Design 中的 [Cascader](https://ant-design.antgroup.com/components/cascader-cn#api) 组件封装而成 + +### 代码演示 + +#### 默认示例 + + + +### API + +| 参数 | 说明 | 类型 | 默认值 | +| --- | --- | --- | --- | +| autoFit | 是否控制地图自动平移到选项对应行政区域 | `boolean` | `true` | +| enableBoundary | 是否在地图上展示行政区域边界 | `boolean` | `true` | +| boundaryLayer | 边界线图层属性,可参考 [LineLayerProps](https://larkmap.antv.antgroup.com/components/layers/base-layers/line-layer#api) | `Omit` | `--` | + +其他参数可以参照 [Ant Design 5.0 Cascader](https://ant-design.antgroup.com/components/cascader-cn#api) diff --git a/docs/blocks/administrative-select/administrative-select.tsx b/docs/blocks/administrative-select/administrative-select.tsx new file mode 100644 index 00000000..10c7fae3 --- /dev/null +++ b/docs/blocks/administrative-select/administrative-select.tsx @@ -0,0 +1,156 @@ +import type { LineLayerProps } from '@antv/larkmap'; +import { LineLayer, useScene } from '@antv/larkmap'; +import type { Feature, MultiLineString } from '@turf/turf'; +import { bbox, featureCollection, multiLineString } from '@turf/turf'; +import type { CascaderProps } from 'antd'; +import { Cascader, message } from 'antd'; +import React, { useEffect, useState } from 'react'; + +export interface AdministrativeSelectProps + extends Omit, + Partial> { + /** + * 是否平移 + */ + autoFit?: boolean; + /** + * 是否显示边界 + */ + enableBoundary?: boolean; + /** + * layer属性 + */ + boundaryLayer?: Omit; +} + +/** + * 将获取的行政区域雷彪转换为 Cascader 的 options + * @param list + * @returns + */ +const getCascadeData = (list: any[]) => { + list.sort((a: { adcode: number }, b: { adcode: number }) => { + return +a.adcode - +b.adcode; + }); + if (list.length) { + return list.map((item: any) => { + const { name, districts, adcode } = item; + return { + adcode, + value: adcode, + label: name, + children: getCascadeData(districts), + }; + }); + } else { + return []; + } +}; + +export const AdministrativeSelect: React.FC = ({ + enableBoundary, + autoFit, + boundaryLayer, + value: originValue, + onChange, + ...props +}) => { + const [districtFeature, setDistrictFeature] = useState | null>(null); + const scene = useScene(); + const [options, setOptions] = useState(); + const [value, setValue] = useState(originValue); + + useEffect(() => { + setValue(originValue); + }, [originValue]); + + useEffect(() => { + fetch( + 'https://restapi.amap.com/v3/config/district?key=98d10f05a2da96697313a2ce35ebf1a2&keywords=中华人民共和国&subdistrict=3&extensions=base', + ) + .then((res) => res.json()) + .then((res) => { + setOptions(getCascadeData(res.districts[0].districts)); + }); + }, []); + + // 当选项发生改变时,更新围栏数据 + useEffect(() => { + if (value) { + const name = value[value.length - 1]; + fetch( + `https://restapi.amap.com/v3/config/district?keywords=${name}&subdistrict=0&key=98d10f05a2da96697313a2ce35ebf1a2&extensions=all`, + ) + .then((res) => res.json()) + .then((res) => { + if (res.status === '1' && res.districts?.length && scene) { + const positions: number[][][] = []; + res.districts.forEach((district: any) => { + (district.polyline as string).split('|').forEach((chunk) => { + positions.push(chunk.split(';').map((item) => item.split(',').map((num) => +num))); + }); + }); + + const feature = multiLineString(positions); + setDistrictFeature(feature); + if (autoFit) { + const [lng1, lat1, lng2, lat2] = bbox(feature); + scene.fitBounds([ + [lng1, lat1], + [lng2, lat2], + ]); + } + } + }) + .catch(() => { + message.error('围栏数据请求失败'); + }); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [value]); + + return ( + <> + { + setValue(newValue); + // @ts-ignore + onChange?.(newValue, option); + if (!value) { + setDistrictFeature(null); + } + }} + multiple={false} + {...props} + /> + {enableBoundary && ( + + )} + + ); +}; + +AdministrativeSelect.defaultProps = { + placeholder: '可选择省/市/县', + expandTrigger: 'hover', + allowClear: true, + changeOnSelect: true, + enableBoundary: true, + autoFit: true, + showSearch: true, + boundaryLayer: { + shape: 'line', + color: '#ff0000', + size: 2, + style: { + opacity: 0.8, + }, + }, +}; diff --git a/docs/blocks/administrative-select/demos/default.tsx b/docs/blocks/administrative-select/demos/default.tsx new file mode 100644 index 00000000..63b7a5db --- /dev/null +++ b/docs/blocks/administrative-select/demos/default.tsx @@ -0,0 +1,23 @@ +import type { LarkMapProps } from '@antv/larkmap'; +import { CustomControl, LarkMap } from '@antv/larkmap'; +import React from 'react'; +import { AdministrativeSelect } from '../administrative-select'; + +const config: LarkMapProps = { + mapType: 'Gaode', + mapOptions: { + style: 'light', + center: [120.210792, 30.246026], + zoom: 9, + }, +}; + +export default () => { + return ( + + + + + + ); +};