Map-select.vue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. <template>
  2. <div class="map-wrapper">
  3. <div id="map-container"></div>
  4. <div class="search-box">
  5. <el-autocomplete
  6. v-model="keyword"
  7. :fetch-suggestions="handleSearch"
  8. :trigger-on-focus="false"
  9. clearable
  10. placeholder="填写城市+关键字搜索"
  11. @select="handleSelect"
  12. class="width400"
  13. />
  14. <el-input v-model="location.longitude" placeholder="点击地图选择经度" maxlength="15" readonly class="width150" style="margin: 0 5px"></el-input>
  15. <el-input v-model="location.latitude" placeholder="点击地图选择纬度" maxlength="15" readonly class="width400"></el-input>
  16. </div>
  17. </div>
  18. </template>
  19. <script setup>
  20. import AMapLoader from '@amap/amap-jsapi-loader';
  21. import { computed, onMounted, ref, shallowRef, watch } from 'vue';
  22. import { storeToRefs } from 'pinia';
  23. import { useThemeConfig } from '@/stores/themeConfig';
  24. import { getCurrentCityConfig } from '@/utils/appConfig';
  25. const storesThemeConfig = useThemeConfig();
  26. const { themeConfig } = storeToRefs(storesThemeConfig);
  27. // 获取布局配置信息
  28. const getThemeConfig = computed(() => {
  29. return themeConfig.value;
  30. });
  31. window._AMapSecurityConfig = {
  32. securityJsCode: import.meta.env.VITE_AMAP_SECURITYJSCODE,
  33. };
  34. const props = defineProps({
  35. modelValue: {
  36. type: Object,
  37. default() {
  38. return {};
  39. },
  40. },
  41. });
  42. const emit = defineEmits(['update:modelValue']);
  43. const map = shallowRef(null);
  44. // 地点
  45. // const location = computed({
  46. // get() {
  47. // return props.modelValue;
  48. // },
  49. // set(val) {
  50. // emit('update:modelValue', val);
  51. // },
  52. // });
  53. const location = ref(props.modelValue);
  54. watch(location, (val) => {
  55. if (val.longitude && val.latitude) {
  56. drawMarker();
  57. }
  58. });
  59. const keyword = ref('');
  60. let placeSearch, AMapObj, marker, geocoder;
  61. const { cityAbbr, locationCenter } = getCurrentCityConfig();
  62. const initMap = () => {
  63. AMapLoader.load({
  64. key: import.meta.env.VITE_AMAP_KEY, // 申请好的Web端Key,首次调用 load 时必填
  65. version: '2.0',
  66. }).then((AMap) => {
  67. AMapObj = AMap;
  68. map.value = new AMap.Map('map-container', {
  69. center: locationCenter,
  70. });
  71. // 添加点击事件
  72. map.value.on('click', onMapClick);
  73. if (location.value.longitude) {
  74. drawMarker();
  75. }
  76. AMap.plugin(['AMap.ToolBar', 'AMap.Scale', 'AMap.Geolocation', 'AMap.PlaceSearch', 'AMap.Geocoder'], () => {
  77. // 缩放条
  78. const toolbar = new AMap.ToolBar();
  79. // 比例尺
  80. const scale = new AMap.Scale();
  81. // 定位
  82. const geolocation = new AMap.Geolocation({
  83. enableHighAccuracy: true, //是否使用高精度定位,默认:true
  84. timeout: 10000, //超过10秒后停止定位,默认:5s
  85. position: 'RT', //定位按钮的停靠位置
  86. buttonOffset: new AMap.Pixel(10, 20), //定位按钮与设置的停靠位置的偏移量,默认:Pixel(10, 20)
  87. zoomToAccuracy: true, //定位成功后是否自动调整地图视野到定位点
  88. });
  89. geocoder = new AMap.Geocoder({
  90. city: cityAbbr,
  91. });
  92. map.value.addControl(geolocation);
  93. map.value.addControl(toolbar);
  94. map.value.addControl(scale);
  95. placeSearch = new AMap.PlaceSearch({
  96. map: map.value,
  97. city: '',
  98. pageSize: 30, // 单页显示结果条数
  99. pageIndex: 1, // 页码
  100. citylimit: false, // 是否强制限制在设置的城市内搜索
  101. autoFitView: true,
  102. });
  103. if (getThemeConfig.value.isIsDark) {
  104. const styleName = 'amap://styles/' + 'dark';
  105. map.value.setMapStyle(styleName);
  106. } else {
  107. const styleName = 'amap://styles/' + 'normal';
  108. map.value.setMapStyle(styleName);
  109. }
  110. });
  111. });
  112. };
  113. onMounted(() => {
  114. initMap();
  115. });
  116. // 搜索地图
  117. const handleSearch = (queryString, cb) => {
  118. placeSearch.search(queryString, (status, result) => {
  119. if (result && typeof result === 'object' && result.poiList) {
  120. const list = result.poiList.pois;
  121. list.forEach((item) => {
  122. item.value = item.name;
  123. item.label = item.name;
  124. });
  125. cb(list);
  126. } else {
  127. cb([]);
  128. }
  129. });
  130. };
  131. // 点击地图
  132. const onMapClick = (e) => {
  133. const { lng, lat } = e.lnglat;
  134. // 逆地理编码
  135. geocoder.getAddress([lng, lat], (status, result) => {
  136. if (status === 'complete' && result.info === 'OK') {
  137. const { addressComponent, formattedAddress } = result.regeocode;
  138. let { city, province, district, township, adcode } = addressComponent;
  139. if (!city) {
  140. // 直辖市
  141. city = province;
  142. }
  143. location.value = {
  144. longitude: lng,
  145. latitude: lat,
  146. formattedAddress,
  147. zone: [province, city, district, township],
  148. adcode,
  149. };
  150. keyword.value = formattedAddress;
  151. emit('update:modelValue', location.value);
  152. }
  153. });
  154. };
  155. // 点击搜索项
  156. const handleSelect = (item) => {
  157. console.log(item);
  158. const { pname, cityname, adname, address, name, adcode } = item;
  159. const { lng, lat } = item.location;
  160. location.value = {
  161. longitude: lng,
  162. latitude: lat,
  163. adcode,
  164. formattedAddress: address,
  165. zone: [pname, cityname, adname, ''],
  166. name,
  167. };
  168. emit('update:modelValue', location.value);
  169. map.value.setZoomAndCenter(16, [lng, lat]);
  170. };
  171. // 绘制地点marker
  172. const drawMarker = (val) => {
  173. const { longitude, latitude, formattedAddress } = location.value || val;
  174. if (marker) {
  175. marker.setMap(null);
  176. }
  177. marker = new AMapObj.Marker({
  178. position: new AMapObj.LngLat(longitude, latitude),
  179. anchor: 'bottom-center',
  180. });
  181. map.value.add(marker);
  182. map.value.setCenter([longitude, latitude]);
  183. keyword.value = formattedAddress;
  184. };
  185. defineExpose({
  186. location,
  187. });
  188. </script>
  189. <style lang="scss" scoped>
  190. .map-wrapper {
  191. position: relative;
  192. width: 100%;
  193. height: 400px;
  194. #map-container {
  195. width: 100%;
  196. height: 100%;
  197. }
  198. .search-box {
  199. position: absolute;
  200. top: 10px;
  201. left: 10px;
  202. z-index: 1;
  203. display: flex;
  204. align-items: center;
  205. }
  206. }
  207. </style>