@cqsjjb/jjb-react-admin-component 3.3.0-beta.3 → 3.3.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AMap/index.js +238 -113
- package/package.json +1 -1
package/AMap/index.js
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState, useCallback } from 'react';
|
|
2
2
|
import { Button, Col, message, Modal, Result, Row } from 'antd';
|
|
3
|
-
import './index.less';
|
|
4
3
|
const _A_MAP_SEARCH_ = '_A_MAP_SEARCH_';
|
|
5
4
|
const _A_MAP_DEFAULT_POINT_ = {
|
|
6
5
|
lng: 116.397437,
|
|
7
6
|
lat: 39.909148
|
|
8
7
|
};
|
|
9
|
-
|
|
8
|
+
export default function AMap({
|
|
10
9
|
lng: propLng,
|
|
11
10
|
lat: propLat,
|
|
12
11
|
title = '高德地图',
|
|
13
12
|
width = 700,
|
|
14
13
|
onOk,
|
|
15
14
|
onCancel
|
|
16
|
-
})
|
|
15
|
+
}) {
|
|
17
16
|
const [lng, setLng] = useState(_A_MAP_DEFAULT_POINT_.lng);
|
|
18
17
|
const [lat, setLat] = useState(_A_MAP_DEFAULT_POINT_.lat);
|
|
19
|
-
const GL = useRef(null);
|
|
18
|
+
const GL = useRef(null);
|
|
20
19
|
const mapRef = useRef(null);
|
|
21
20
|
const markerRef = useRef(null);
|
|
22
21
|
const autoRef = useRef(null);
|
|
@@ -26,78 +25,136 @@ const AMap = ({
|
|
|
26
25
|
message.error('未导入高德地图文件,生成地图失败!').then(() => null);
|
|
27
26
|
return;
|
|
28
27
|
}
|
|
29
|
-
|
|
30
|
-
const initLat = propLat || _A_MAP_DEFAULT_POINT_.lat;
|
|
31
|
-
setLng(initLng);
|
|
32
|
-
setLat(initLat);
|
|
28
|
+
let mounted = true;
|
|
33
29
|
|
|
34
|
-
//
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
zoom: 18,
|
|
38
|
-
viewMode: '3D'
|
|
39
|
-
});
|
|
40
|
-
mapRef.current = map;
|
|
30
|
+
// 保证传入的初始值是 number(避免 NaN)
|
|
31
|
+
const initLng = Number(propLng) || _A_MAP_DEFAULT_POINT_.lng;
|
|
32
|
+
const initLat = Number(propLat) || _A_MAP_DEFAULT_POINT_.lat;
|
|
41
33
|
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
34
|
+
// 等待容器可见且尺寸非 0(Modal 动画或隐藏态时常为 0)
|
|
35
|
+
const waitForVisible = (el, timeout = 3000) => new Promise(resolve => {
|
|
36
|
+
const start = Date.now();
|
|
37
|
+
function check() {
|
|
38
|
+
if (!el) return resolve(false);
|
|
39
|
+
const r = el.getBoundingClientRect();
|
|
40
|
+
if (r.width > 0 && r.height > 0) return resolve(true);
|
|
41
|
+
if (Date.now() - start > timeout) return resolve(false);
|
|
42
|
+
requestAnimationFrame(check);
|
|
43
|
+
}
|
|
44
|
+
check();
|
|
45
|
+
});
|
|
46
|
+
async function init() {
|
|
47
|
+
if (!GL.current) {
|
|
48
|
+
console.warn('AMap container ref not ready');
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const visible = await waitForVisible(GL.current, 3000);
|
|
52
|
+
if (!visible) {
|
|
53
|
+
// 继续也可,但记录一下。多数情况下等待后再 init 能解决 Pixel(NaN, 0)
|
|
54
|
+
console.warn('AMap container still not visible before init (proceeding anyway).');
|
|
51
55
|
}
|
|
52
|
-
|
|
53
|
-
// 工具条(放大缩小)
|
|
54
|
-
try {
|
|
55
|
-
map.addControl(new window.AMap.ToolBar({
|
|
56
|
-
position: 'RT'
|
|
57
|
-
}));
|
|
58
|
-
} catch (e) {}
|
|
59
|
-
|
|
60
|
-
// 定位控件
|
|
61
56
|
try {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
showButton: true
|
|
57
|
+
const map = new window.AMap.Map(GL.current, {
|
|
58
|
+
center: [initLng, initLat],
|
|
59
|
+
zoom: 18,
|
|
60
|
+
viewMode: '3D'
|
|
67
61
|
});
|
|
68
|
-
map
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
62
|
+
mapRef.current = map;
|
|
63
|
+
|
|
64
|
+
// 保证 state 与实际中心一致
|
|
65
|
+
setLng(initLng);
|
|
66
|
+
setLat(initLat);
|
|
67
|
+
|
|
68
|
+
// 插件加载、控件创建都做容错
|
|
69
|
+
window.AMap.plugin(['AMap.Scale', 'AMap.ToolBar', 'AMap.Geolocation', 'AMap.AutoComplete', 'AMap.PlaceSearch', 'AMap.Geocoder'], () => {
|
|
70
|
+
try {
|
|
71
|
+
map.addControl(new window.AMap.Scale());
|
|
72
|
+
} catch (e) {
|
|
73
|
+
// 某些构建/版本中可能不存在
|
|
74
|
+
console.warn('Scale control failed', e);
|
|
72
75
|
}
|
|
73
|
-
|
|
74
|
-
|
|
76
|
+
try {
|
|
77
|
+
map.addControl(new window.AMap.ToolBar({
|
|
78
|
+
position: 'RT'
|
|
79
|
+
}));
|
|
80
|
+
} catch (e) {
|
|
81
|
+
console.warn('ToolBar control failed', e);
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
// 使用合法角落(RB/RT/LB/LT),不要自定义 'BT'
|
|
85
|
+
const geolocation = new window.AMap.Geolocation({
|
|
86
|
+
position: 'RB',
|
|
87
|
+
offset: new window.AMap.Pixel(Number(20), Number(20)),
|
|
88
|
+
showCircle: false,
|
|
89
|
+
showButton: true
|
|
90
|
+
});
|
|
91
|
+
map.addControl(geolocation);
|
|
75
92
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
93
|
+
// 正确的回调签名 (status, result)
|
|
94
|
+
geolocation.getCurrentPosition((status, result) => {
|
|
95
|
+
if (status !== 'complete') {
|
|
96
|
+
// 不做致命处理,但提示
|
|
97
|
+
message.error('未知原因,定位失败!');
|
|
98
|
+
} else {
|
|
99
|
+
// 如果需要可以从 result.position 取值
|
|
100
|
+
try {
|
|
101
|
+
const pos = result && result.position;
|
|
102
|
+
if (pos) {
|
|
103
|
+
const px = typeof pos.getLng === 'function' ? pos.getLng() : pos.lng;
|
|
104
|
+
const py = typeof pos.getLat === 'function' ? pos.getLat() : pos.lat;
|
|
105
|
+
if (!Number.isNaN(Number(px)) && !Number.isNaN(Number(py))) {
|
|
106
|
+
setLng(Number(px));
|
|
107
|
+
setLat(Number(py));
|
|
108
|
+
map.setCenter([Number(px), Number(py)]);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} catch (e) {
|
|
112
|
+
// 忽略
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
} catch (e) {
|
|
117
|
+
console.warn('Geolocation init failed', e);
|
|
118
|
+
}
|
|
81
119
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
120
|
+
// 初始 marker 放置
|
|
121
|
+
try {
|
|
122
|
+
markerRef.current = new window.AMap.Marker({
|
|
123
|
+
position: [initLng, initLat],
|
|
124
|
+
map
|
|
125
|
+
});
|
|
126
|
+
} catch (e) {
|
|
127
|
+
console.warn('Marker init failed', e);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// AutoComplete + PlaceSearch
|
|
131
|
+
try {
|
|
132
|
+
placeSearchRef.current = new window.AMap.PlaceSearch({
|
|
133
|
+
map
|
|
134
|
+
});
|
|
135
|
+
autoRef.current = new window.AMap.AutoComplete({
|
|
136
|
+
input: document.getElementById(_A_MAP_SEARCH_)
|
|
137
|
+
});
|
|
138
|
+
autoRef.current.on && autoRef.current.on('select', e => {
|
|
139
|
+
// e.poi 里可能是 AMap.LngLat 实例 / 对象 / 数组,做兼容处理
|
|
140
|
+
const poi = e && e.poi ? e.poi : null;
|
|
141
|
+
let loc = poi && (poi.location || poi.lnglat) || e && (e.location || e.lnglat) || null;
|
|
142
|
+
let foundLng = null;
|
|
143
|
+
let foundLat = null;
|
|
144
|
+
if (loc) {
|
|
145
|
+
if (typeof loc.getLng === 'function' && typeof loc.getLat === 'function') {
|
|
146
|
+
// AMap.LngLat 实例
|
|
147
|
+
foundLng = Number(loc.getLng());
|
|
148
|
+
foundLat = Number(loc.getLat());
|
|
149
|
+
} else if (typeof loc.lng === 'number' && typeof loc.lat === 'number') {
|
|
150
|
+
foundLng = Number(loc.lng);
|
|
151
|
+
foundLat = Number(loc.lat);
|
|
152
|
+
} else if (Array.isArray(loc)) {
|
|
153
|
+
foundLng = Number(loc[0]);
|
|
154
|
+
foundLat = Number(loc[1]);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (foundLng != null && foundLat != null && !Number.isNaN(foundLng) && !Number.isNaN(foundLat)) {
|
|
101
158
|
setLng(foundLng);
|
|
102
159
|
setLat(foundLat);
|
|
103
160
|
map.setCenter([foundLng, foundLat]);
|
|
@@ -109,86 +166,155 @@ const AMap = ({
|
|
|
109
166
|
map
|
|
110
167
|
});
|
|
111
168
|
}
|
|
169
|
+
} else {
|
|
170
|
+
// 兜底:用 placeSearch 搜索 name(如果有)
|
|
171
|
+
const name = poi && (poi.name || poi.address) || e && (e.info || e.name);
|
|
172
|
+
if (name && placeSearchRef.current && placeSearchRef.current.search) {
|
|
173
|
+
placeSearchRef.current.search(name, (status, result) => {
|
|
174
|
+
// placeSearch 回调再处理,这里保持原有逻辑或按需增强
|
|
175
|
+
if (status === 'complete' && result && result.poiList && result.poiList.pois && result.poiList.pois.length > 0) {
|
|
176
|
+
const p = result.poiList.pois[0];
|
|
177
|
+
const loc2 = p.location || p.lnglat;
|
|
178
|
+
let x = null,
|
|
179
|
+
y = null;
|
|
180
|
+
if (loc2) {
|
|
181
|
+
if (typeof loc2.getLng === 'function') {
|
|
182
|
+
x = Number(loc2.getLng());
|
|
183
|
+
y = Number(loc2.getLat());
|
|
184
|
+
} else if (typeof loc2.lng === 'number') {
|
|
185
|
+
x = Number(loc2.lng);
|
|
186
|
+
y = Number(loc2.lat);
|
|
187
|
+
} else if (Array.isArray(loc2)) {
|
|
188
|
+
x = Number(loc2[0]);
|
|
189
|
+
y = Number(loc2[1]);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (!Number.isNaN(x) && !Number.isNaN(y)) {
|
|
193
|
+
setLng(x);
|
|
194
|
+
setLat(y);
|
|
195
|
+
map.setCenter([x, y]);
|
|
196
|
+
if (markerRef.current) markerRef.current.setPosition([x, y]);else markerRef.current = new window.AMap.Marker({
|
|
197
|
+
position: [x, y],
|
|
198
|
+
map
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
}
|
|
112
204
|
}
|
|
113
|
-
}
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
|
|
205
|
+
});
|
|
206
|
+
} catch (e) {
|
|
207
|
+
console.warn('AutoComplete / PlaceSearch init failed', e);
|
|
208
|
+
}
|
|
117
209
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
210
|
+
// 点击选点
|
|
211
|
+
try {
|
|
212
|
+
map.on && map.on('click', e => {
|
|
213
|
+
const lnglat = e && e.lnglat;
|
|
214
|
+
if (!lnglat) return;
|
|
215
|
+
let clickLng = null;
|
|
216
|
+
let clickLat = null;
|
|
217
|
+
if (typeof lnglat.getLng === 'function') {
|
|
218
|
+
clickLng = Number(lnglat.getLng());
|
|
219
|
+
clickLat = Number(lnglat.getLat());
|
|
220
|
+
} else {
|
|
221
|
+
clickLng = Number(lnglat.lng || Array.isArray(lnglat) && lnglat[0]);
|
|
222
|
+
clickLat = Number(lnglat.lat || Array.isArray(lnglat) && lnglat[1]);
|
|
223
|
+
}
|
|
224
|
+
if (Number.isNaN(clickLng) || Number.isNaN(clickLat)) return;
|
|
225
|
+
setLng(clickLng);
|
|
226
|
+
setLat(clickLat);
|
|
227
|
+
if (markerRef.current) {
|
|
228
|
+
markerRef.current.setPosition([clickLng, clickLat]);
|
|
229
|
+
} else {
|
|
230
|
+
markerRef.current = new window.AMap.Marker({
|
|
231
|
+
position: [clickLng, clickLat],
|
|
232
|
+
map
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
} catch (e) {
|
|
237
|
+
console.warn('map.on click failed', e);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
} catch (err) {
|
|
241
|
+
console.error('AMap init error', err);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
init();
|
|
137
245
|
|
|
138
246
|
// cleanup
|
|
139
247
|
return () => {
|
|
248
|
+
mounted = false;
|
|
140
249
|
try {
|
|
141
250
|
if (mapRef.current) {
|
|
142
251
|
mapRef.current.destroy();
|
|
143
252
|
mapRef.current = null;
|
|
144
253
|
}
|
|
145
|
-
} catch (e) {
|
|
254
|
+
} catch (e) {
|
|
255
|
+
// ignore
|
|
256
|
+
}
|
|
146
257
|
markerRef.current = null;
|
|
147
258
|
autoRef.current = null;
|
|
148
259
|
placeSearchRef.current = null;
|
|
149
260
|
};
|
|
150
261
|
}, [propLng, propLat]);
|
|
151
262
|
|
|
152
|
-
|
|
263
|
+
// 重置、确认等操作(同样做 number guard)
|
|
153
264
|
const onResetMap = useCallback(() => {
|
|
154
265
|
const map = mapRef.current;
|
|
155
266
|
if (!map) return;
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
markerRef.current
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
267
|
+
const x = Number(_A_MAP_DEFAULT_POINT_.lng);
|
|
268
|
+
const y = Number(_A_MAP_DEFAULT_POINT_.lat);
|
|
269
|
+
setLng(x);
|
|
270
|
+
setLat(y);
|
|
271
|
+
try {
|
|
272
|
+
map.setCenter([x, y]);
|
|
273
|
+
if (markerRef.current) {
|
|
274
|
+
markerRef.current.setPosition([x, y]);
|
|
275
|
+
} else {
|
|
276
|
+
markerRef.current = new window.AMap.Marker({
|
|
277
|
+
position: [x, y],
|
|
278
|
+
map
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
} catch (e) {
|
|
282
|
+
console.warn('reset map failed', e);
|
|
166
283
|
}
|
|
167
284
|
}, []);
|
|
168
|
-
|
|
169
|
-
/** 确认操作(逆地理编码) */
|
|
170
285
|
const handleOk = useCallback(() => {
|
|
171
286
|
if (!mapRef.current) return;
|
|
172
|
-
// 确保
|
|
287
|
+
// 确保 lng/lat 是 number
|
|
288
|
+
const x = Number(lng);
|
|
289
|
+
const y = Number(lat);
|
|
290
|
+
if (Number.isNaN(x) || Number.isNaN(y)) {
|
|
291
|
+
onOk && onOk({
|
|
292
|
+
lng,
|
|
293
|
+
lat,
|
|
294
|
+
comp: undefined,
|
|
295
|
+
compText: undefined
|
|
296
|
+
});
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
173
299
|
window.AMap.plugin('AMap.Geocoder', () => {
|
|
174
300
|
try {
|
|
175
301
|
const geocoder = new window.AMap.Geocoder();
|
|
176
|
-
geocoder.getAddress([
|
|
302
|
+
geocoder.getAddress([x, y], (status, result) => {
|
|
177
303
|
let comp;
|
|
178
304
|
if (status === 'complete' && result && result.regeocode) {
|
|
179
305
|
comp = result.regeocode.addressComponent;
|
|
180
306
|
}
|
|
181
307
|
onOk && onOk({
|
|
182
|
-
lng,
|
|
183
|
-
lat,
|
|
308
|
+
lng: x,
|
|
309
|
+
lat: y,
|
|
184
310
|
comp,
|
|
185
311
|
compText: comp && [comp.province, comp.city, comp.district, comp.township, comp.street, comp.streetNumber].filter(Boolean).join('') || undefined
|
|
186
312
|
});
|
|
187
313
|
});
|
|
188
314
|
} catch (e) {
|
|
189
315
|
onOk && onOk({
|
|
190
|
-
lng,
|
|
191
|
-
lat,
|
|
316
|
+
lng: x,
|
|
317
|
+
lat: y,
|
|
192
318
|
comp: undefined,
|
|
193
319
|
compText: undefined
|
|
194
320
|
});
|
|
@@ -242,5 +368,4 @@ const AMap = ({
|
|
|
242
368
|
status: "error",
|
|
243
369
|
title: "\u52A0\u8F7D\u5730\u56FE\u5931\u8D25\uFF0C\u7F3A\u5C11\u5FC5\u8981\u7684\u6587\u4EF6\uFF01"
|
|
244
370
|
}));
|
|
245
|
-
}
|
|
246
|
-
export default AMap;
|
|
371
|
+
}
|