selectLocation.vue 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. <template>
  2. <div class="select-location">
  3. <custom-header :name="headerName"></custom-header>
  4. <div class="select-location-content">
  5. <div class="search-bar">
  6. <location-search
  7. class="location-search"
  8. :user-location="userLocation"
  9. @change="handleLocationChange"
  10. />
  11. </div>
  12. <div class="map-container" ref="mapContainer"></div>
  13. <div class="locate-btn" @click="handleLocate">
  14. <img class="locate-icon" src="@/assets/img/map/map-icon.png" alt="" />
  15. </div>
  16. </div>
  17. <div class="custom-bottom-fixed-btns">
  18. <div class="bottom-btn primary-btn" @click="handleSubmit">确认点位</div>
  19. </div>
  20. </div>
  21. </template>
  22. <script setup>
  23. import { onMounted, onUnmounted, ref } from "vue";
  24. import { useRouter, useRoute } from "vue-router";
  25. import { useStore } from "vuex";
  26. import { ElMessage } from "element-plus";
  27. import customHeader from "@/components/customHeader.vue";
  28. import locationSearch from "@/components/pageComponents/locationSearch.vue";
  29. import SelectLocationMap, { mapLocation, POINT_ICON } from "./map/selectLocationMap.js";
  30. import { convertPointToArray } from "@/utils/index";
  31. const SESSION_KEY_RESIDENT = "ENTRY_RESIDENT_LOCATION";
  32. const SESSION_KEY_GROWTH = "GROWTH_REPORT_LOCATION";
  33. /** 默认定位:河北宁晋县 */
  34. const DEFAULT_POINT = "POINT(114.91863572509733 37.67702031436258)";
  35. const DEFAULT_USER_LOCATION = "114.91863572509733,37.67702031436258";
  36. const MAP_KEY = "CZLBZ-LJICQ-R4A5J-BN62X-YXCRJ-GNBUT";
  37. const router = useRouter();
  38. const route = useRoute();
  39. const store = useStore();
  40. const mapContainer = ref(null);
  41. const isPlantPoint = route.query.pointType === "plant";
  42. const fromGrowthReport = route.query.from === "growth_report";
  43. const fromService = route.query.from === "entry_service";
  44. const headerName = fromGrowthReport ? "切换位置" : fromService ? "选择位置" : "选择种植点位";
  45. const sessionKey = fromGrowthReport ? SESSION_KEY_GROWTH : SESSION_KEY_RESIDENT;
  46. const iconSrc =
  47. route.query.iconType && POINT_ICON[route.query.iconType]
  48. ? POINT_ICON[route.query.iconType]
  49. : isPlantPoint
  50. ? POINT_ICON.plant
  51. : POINT_ICON.resident;
  52. const userLocation = ref(
  53. store.state.home.miniUserLocation || localStorage.getItem("MINI_USER_LOCATION") || DEFAULT_USER_LOCATION
  54. );
  55. /** 搜索选中时带出的区县编码、地区名 */
  56. const selectedAdcode = ref("");
  57. const selectedRegion = ref("");
  58. const selectLocationMap = new SelectLocationMap({
  59. iconSrc,
  60. onMapClick: () => {
  61. selectedAdcode.value = "";
  62. selectedRegion.value = "";
  63. },
  64. });
  65. function getDefaultPoint() {
  66. if (route.query.mapCenter) return route.query.mapCenter;
  67. return (
  68. localStorage.getItem("MINI_USER_LOCATION_POINT") ||
  69. store.state.home.miniUserLocationPoint ||
  70. DEFAULT_POINT
  71. );
  72. }
  73. function toPointWkt(coordinate) {
  74. const lng = Number(coordinate[0]);
  75. const lat = Number(coordinate[1]);
  76. return `POINT(${lng} ${lat})`;
  77. }
  78. async function fetchAdcodeByCoordinate(coordinate) {
  79. if (!coordinate?.length) return { adcode: "", region: "" };
  80. try {
  81. const { result } = await VE_API.old_mini_map.location({
  82. key: MAP_KEY,
  83. location: `${coordinate[1]},${coordinate[0]}`,
  84. });
  85. const adcode = result?.ad_info?.adcode;
  86. const region =
  87. result?.ad_info?.district ||
  88. result?.ad_info?.city ||
  89. result?.address_component?.district ||
  90. result?.address_component?.city ||
  91. "";
  92. return {
  93. adcode: adcode != null && adcode !== "" ? String(adcode) : "",
  94. region: region || "",
  95. };
  96. } catch {
  97. return { adcode: "", region: "" };
  98. }
  99. }
  100. onMounted(() => {
  101. const point = getDefaultPoint();
  102. selectLocationMap.initMap(point, mapContainer.value);
  103. });
  104. onUnmounted(() => {
  105. selectLocationMap.clearLayer();
  106. });
  107. const handleLocationChange = (payload) => {
  108. if (!payload?.coordinateArray) {
  109. selectedAdcode.value = "";
  110. selectedRegion.value = "";
  111. return;
  112. }
  113. selectedAdcode.value = payload.adcode ? String(payload.adcode) : "";
  114. selectedRegion.value =
  115. payload.item?.district || payload.item?.city || payload.city || "";
  116. selectLocationMap.setMapPosition(payload.coordinateArray);
  117. };
  118. const handleLocate = () => {
  119. selectedAdcode.value = "";
  120. selectedRegion.value = "";
  121. const point =
  122. localStorage.getItem("MINI_USER_LOCATION_POINT") ||
  123. store.state.home.miniUserLocationPoint ||
  124. DEFAULT_POINT;
  125. const coordinate = convertPointToArray(point).map(Number);
  126. selectLocationMap.setMapPosition(coordinate);
  127. };
  128. const handleSubmit = async () => {
  129. const coordinate = mapLocation.data;
  130. if (!coordinate) {
  131. ElMessage.warning(
  132. fromGrowthReport || fromService ? "请选择位置" : isPlantPoint ? "请选择种植点位" : "请选择常驻点位"
  133. );
  134. return;
  135. }
  136. const point = toPointWkt(coordinate);
  137. let adcode = selectedAdcode.value;
  138. let region = selectedRegion.value;
  139. if (!adcode || !region) {
  140. const meta = await fetchAdcodeByCoordinate(coordinate);
  141. adcode = adcode || meta.adcode;
  142. region = region || meta.region;
  143. }
  144. sessionStorage.setItem(
  145. sessionKey,
  146. JSON.stringify({
  147. point,
  148. coordinate: [Number(coordinate[0]), Number(coordinate[1])],
  149. adcode: adcode || "",
  150. region: region || "",
  151. })
  152. );
  153. router.back();
  154. };
  155. </script>
  156. <style lang="scss" scoped>
  157. .select-location {
  158. width: 100%;
  159. height: 100vh;
  160. overflow: hidden;
  161. background: #fff;
  162. display: flex;
  163. flex-direction: column;
  164. .select-location-content {
  165. position: relative;
  166. flex: 1;
  167. overflow: hidden;
  168. .search-bar {
  169. position: absolute;
  170. top: 12px;
  171. left: 12px;
  172. right: 12px;
  173. z-index: 2;
  174. }
  175. .map-container {
  176. width: 100%;
  177. height: 100%;
  178. }
  179. .locate-btn {
  180. position: absolute;
  181. right: 12px;
  182. bottom: 40px;
  183. z-index: 2;
  184. width: 32px;
  185. height: 32px;
  186. display: flex;
  187. align-items: center;
  188. justify-content: center;
  189. background: #fff;
  190. border-radius: 8px;
  191. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  192. .locate-icon {
  193. width: 16px;
  194. height: 18px;
  195. }
  196. }
  197. }
  198. .custom-bottom-fixed-btns {
  199. position: relative;
  200. background: #fff;
  201. box-shadow: 2px 2px 5px 0px rgba(0, 0, 0, 0.4);
  202. .bottom-btn {
  203. padding: 0 30px;
  204. height: 40px;
  205. line-height: 40px;
  206. font-size: 14px;
  207. border-radius: 25px;
  208. }
  209. .primary-btn {
  210. background: #2199f8;
  211. color: #fff;
  212. }
  213. }
  214. }
  215. </style>