feat(amis&amis-editor): 地理位置选择器功能完善和强化 close #8802 (#8834)

* fix(amis): 地理位置选择组件/只读模式,不展示地图控件,不支持位置选择操作

* feat(amis): Location地理选择组件增加autoSelectCurrentLoc和onlySelectCurrentLoc配置项

* docs(amis): 补充地理选择组件的新增配置说明

* feat(amis-editor): Location地理选择组件增加autoSelectCurrentLoc和onlySelectCurrentLoc可视化配置

* fix(amis-editor): 完善Location地理选择组件的placeholder配置

* docs(amis): 增加Location地理选择组件Schema属性说明
This commit is contained in:
刘丹 2023-11-21 17:35:06 +08:00 committed by GitHub
parent 29cb3b4ea1
commit ef48b59d13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 108 additions and 93 deletions

View File

@ -60,5 +60,7 @@ order: 30
| vendor | 'baidu' | 'baidu' \| 'gaode' | 地图厂商,目前只实现了百度地图和高德地图 |
| ak | `string` | 无 | 百度/高德地图的 ak |
| clearable | `boolean` | false | 输入框是否可清空 |
| placeholder | `string` | '请选择位置' | 默认提示 |
| coordinatesType | `string` | 'bd09' | 默为百度/高德坐标,可设置为'gcj02', 高德地图不支持坐标转换 |
| placeholder | `string` | '请选择位置' | 默认提示 |
| autoSelectCurrentLoc | `boolean` | false | 是否自动选中当前地理位置 |
| onlySelectCurrentLoc | `boolean` | false | 是否限制只能选中当前地理位置设置为true后可用于充当定位组件 |
| coordinatesType | `string` | 'bd09' | 默为百度/高德坐标,可设置为'gcj02', 高德地图不支持坐标转换 |

View File

@ -1,4 +1,4 @@
import {EditorNodeType, getSchemaTpl} from 'amis-editor-core';
import {EditorNodeType, getSchemaTpl, tipedLabel} from 'amis-editor-core';
import {registerEditorPlugin} from 'amis-editor-core';
import {BasePlugin, BaseEventContext} from 'amis-editor-core';
import {ValidatorTag} from '../../validator';
@ -82,11 +82,30 @@ export class LocationControlPlugin extends BasePlugin {
{label: '国测局坐标', value: 'gcj02'}
]
},
getSchemaTpl('switch', {
name: 'autoSelectCurrentLoc',
label: tipedLabel(
'自动选择',
'开启后,自动选中用户当前的地理位置'
)
}),
getSchemaTpl('switch', {
name: 'onlySelectCurrentLoc',
label: tipedLabel(
'只读模式',
'开启后,只能使用当前地理位置,不可选择其他地理位置'
)
}),
getSchemaTpl('clearable'),
getSchemaTpl('labelRemark'),
getSchemaTpl('remark'),
getSchemaTpl('placeholder'),
getSchemaTpl('placeholder', {
visibleOn: '!onlySelectCurrentLoc'
}),
getSchemaTpl('placeholder', {
name: 'getLocationPlaceholder',
visibleOn: 'onlySelectCurrentLoc'
}),
getSchemaTpl('description')
]
},

View File

@ -38,6 +38,8 @@ interface MapPickerProps {
city?: string;
};
onChange?: (value: any) => void;
autoSelectCurrentLoc?: boolean;
onlySelectCurrentLoc?: boolean;
}
interface LocationItem {
@ -109,6 +111,7 @@ export class BaiduMapPicker extends React.Component<
@autobind
async initMap() {
const autoSelectCurrentLoc = this.props.autoSelectCurrentLoc ?? false;
const map = new BMap.Map(this.mapRef.current, {
enableMapClick: false
});
@ -137,11 +140,14 @@ export class BaiduMapPicker extends React.Component<
const geolocationControl = new BMap.GeolocationControl();
geolocationControl.addEventListener('locationSuccess', (e: any) => {
this.getLocations(e.point);
this.getLocations(e.point, autoSelectCurrentLoc);
});
map.addControl(geolocationControl);
map.addEventListener('click', (e: any) => {
if (this.props.onlySelectCurrentLoc) {
return;
}
this.getLocations(e.point, true);
});
@ -187,7 +193,8 @@ export class BaiduMapPicker extends React.Component<
value ? this.getLocations(point) : geolocationControl.location();
}
getLocations(point: any, select?: boolean) {
@autobind
getLocations(point: any, selectCurrentLoc?: boolean) {
const map = this.map;
map.clearOverlays();
@ -231,7 +238,7 @@ export class BaiduMapPicker extends React.Component<
locs
},
() => {
if (!select) {
if (!selectCurrentLoc) {
return;
}
@ -318,7 +325,7 @@ export class BaiduMapPicker extends React.Component<
});
var local = new BMap.LocalSearch(this.map, {
//智能搜索
// 智能搜索
onSearchComplete: () => {
const results = local.getResults();
const poi = results.getPoi(0);
@ -334,20 +341,23 @@ export class BaiduMapPicker extends React.Component<
render() {
const {classnames: cx} = this.props;
const onlySelectCurrentLoc = this.props.onlySelectCurrentLoc ?? false;
const {locIndex, locs, inputValue, sugs} = this.state;
const hasSug = Array.isArray(sugs) && sugs.length;
return (
<div className={cx('MapPicker')}>
<div className={cx('MapPicker-search TextControl-control')}>
<div className={cx('TextControl-input')}>
<input
onChange={this.handleChange}
value={inputValue}
placeholder="搜索地点"
/>
{!onlySelectCurrentLoc && (
<div className={cx('MapPicker-search TextControl-control')}>
<div className={cx('TextControl-input')}>
<input
onChange={this.handleChange}
value={inputValue}
placeholder="搜索地点"
/>
</div>
</div>
</div>
)}
<div
ref={this.mapRef}
@ -361,23 +371,36 @@ export class BaiduMapPicker extends React.Component<
invisible: hasSug
})}
>
{locs.map((item, index) => (
{!onlySelectCurrentLoc &&
locs.map((item, index) => (
<div
onClick={this.handleSelect}
key={index}
data-index={index}
className={cx('MapPicker-item')}
>
<div className={cx('MapPicker-itemTitle')}>{item.title}</div>
<div className={cx('MapPicker-itemDesc')}>{item.address}</div>
{locIndex === index ? (
<Icon icon="success" className="icon" />
) : null}
</div>
))}
{onlySelectCurrentLoc && locs.length > 0 && (
<div
onClick={this.handleSelect}
key={index}
data-index={index}
key="locs-current"
data-index={0}
className={cx('MapPicker-item')}
>
<div className={cx('MapPicker-itemTitle')}>{item.title}</div>
<div className={cx('MapPicker-itemDesc')}>{item.address}</div>
{locIndex === index ? (
<Icon icon="success" className="icon" />
) : null}
<div className={cx('MapPicker-itemTitle')}>{locs[0].title}</div>
<div className={cx('MapPicker-itemDesc')}>{locs[0].address}</div>
{locIndex === 0 ? <Icon icon="success" className="icon" /> : null}
</div>
))}
)}
</div>
{hasSug ? (
{hasSug && !onlySelectCurrentLoc ? (
<div className={cx('MapPicker-sug')}>
{sugs.map(item => (
<div

View File

@ -14,6 +14,7 @@ export interface LocationProps extends ThemeProps, LocaleProps {
vendor: 'baidu' | 'gaode' | 'tenxun';
coordinatesType: 'bd09' | 'gcj02';
placeholder: string;
getLocationPlaceholder: string;
clearable: boolean;
ak: string;
value?: {
@ -27,6 +28,8 @@ export interface LocationProps extends ThemeProps, LocaleProps {
popoverClassName?: string;
onChange: (value: any) => void;
popOverContainer?: any;
autoSelectCurrentLoc?: boolean;
onlySelectCurrentLoc?: boolean;
}
export interface LocationState {
@ -40,6 +43,7 @@ export class LocationPicker extends React.Component<
> {
static defaultProps = {
placeholder: 'LocationPicker.placeholder',
getLocationPlaceholder: 'LocationPicker.getLocation',
clearable: false
};
domRef: React.RefObject<HTMLDivElement> = React.createRef();
@ -155,12 +159,15 @@ export class LocationPicker extends React.Component<
popoverClassName,
disabled,
placeholder,
getLocationPlaceholder,
clearable,
popOverContainer,
vendor,
coordinatesType,
ak,
mobileUI
mobileUI,
autoSelectCurrentLoc,
onlySelectCurrentLoc
} = this.props;
const __ = this.props.translate;
const {isFocused, isOpened} = this.state;
@ -173,6 +180,8 @@ export class LocationPicker extends React.Component<
ak={ak}
value={value}
coordinatesType={coordinatesType}
autoSelectCurrentLoc={autoSelectCurrentLoc}
onlySelectCurrentLoc={onlySelectCurrentLoc}
onChange={this.handleChange}
/>
);
@ -213,7 +222,7 @@ export class LocationPicker extends React.Component<
<span className={cx('LocationPicker-value')}>{value.address}</span>
) : (
<span className={cx('LocationPicker-placeholder')}>
{__(placeholder)}
{__(onlySelectCurrentLoc ? getLocationPlaceholder : placeholder)}
</span>
)}
@ -242,6 +251,8 @@ export class LocationPicker extends React.Component<
ak={ak}
value={value}
coordinatesType={coordinatesType}
autoSelectCurrentLoc={autoSelectCurrentLoc}
onlySelectCurrentLoc={onlySelectCurrentLoc}
onChange={this.handleTempChange}
/>
) : (
@ -268,6 +279,8 @@ export class LocationPicker extends React.Component<
ak={ak}
value={value}
coordinatesType={coordinatesType}
autoSelectCurrentLoc={autoSelectCurrentLoc}
onlySelectCurrentLoc={onlySelectCurrentLoc}
onChange={this.handleChange}
/>
) : (

View File

@ -188,6 +188,8 @@ register('de-DE', {
'loading': 'Wird geladen...',
'loadingFailed': 'Das Laden ist fehlgeschlagen',
'LocationPicker.placeholder': 'Wählen Sie einen Ort',
'LocationPicker.getLocation':
'Klicken Sie hier, um Standortinformationen zu erhalten',
'Month.placeholder': 'Wählen Sie einen Monat',
'Nav.sourceError': 'Fehler beim Abrufen des Links',
'networkError':

View File

@ -180,6 +180,7 @@ register('en-US', {
'loading': 'Loading',
'loadingFailed': 'Loading failed',
'LocationPicker.placeholder': 'Pick location',
'LocationPicker.getLocation': 'Click to obtain location information',
'Month.placeholder': 'Select a month',
'Nav.sourceError': 'Fetch link error',
'networkError': 'Network error or missing CORS configuration',

View File

@ -185,6 +185,7 @@ register('zh-CN', {
'loading': '加载中',
'loadingFailed': '加载失败',
'LocationPicker.placeholder': '请选择位置',
'LocationPicker.getLocation': '点击获取位置信息',
'Month.placeholder': '请选择月份',
'Nav.sourceError': '获取链接错误',
'networkError': '网络错误,可能是未配置跨域 CORS',

View File

@ -29,6 +29,23 @@ export interface LocationControlSchema extends FormBaseControlSchema {
* ak
*/
ak?: string;
/**
*
*/
autoSelectCurrentLoc?: boolean;
/**
*
*
*/
onlySelectCurrentLoc?: boolean;
/**
*
* placeholder
*/
getLocationPlaceholder?: string;
}
export interface LocationControlProps
@ -51,33 +68,6 @@ export class LocationControl extends React.Component<LocationControlProps> {
coordinatesType: 'bd09'
};
domRef: React.RefObject<HTMLDivElement> = React.createRef();
state = {
isOpened: false
};
@autobind
close() {
this.setState({
isOpened: false
});
}
@autobind
open() {
this.setState({
isOpened: true
});
}
@autobind
handleClick() {
this.state.isOpened ? this.close() : this.open();
}
@autobind
getParent() {
return this.domRef.current?.parentElement;
}
@autobind
getTarget() {
@ -85,14 +75,7 @@ export class LocationControl extends React.Component<LocationControlProps> {
}
renderStatic(displayValue = '-') {
const {
classnames: cx,
value,
vendor,
ak,
coordinatesType,
popOverContainer
} = this.props;
const {classnames: cx, value} = this.props;
const __ = this.props.translate;
if (!value) {
@ -107,35 +90,6 @@ export class LocationControl extends React.Component<LocationControlProps> {
ref={this.domRef}
>
<span>{value.address}</span>
<a
className={cx('LocationPicker-toggler', 'ml-1')}
onClick={this.handleClick}
>
<Icon icon="location" className="icon" />
</a>
<Overlay
target={this.getTarget}
container={popOverContainer || this.getParent}
rootClose={false}
show={this.state.isOpened}
>
<PopOver
className={cx('LocationPicker-popover')}
onHide={this.close}
overlay
style={{width: this.getTarget()?.offsetWidth}}
>
{vendor === 'baidu' ? (
<BaiduMapPicker
ak={ak}
value={value}
coordinatesType={coordinatesType}
/>
) : (
<Alert2>{__('{{vendor}} 地图控件不支持', {vendor})}</Alert2>
)}
</PopOver>
</Overlay>
</div>
);
}