selectLocation.vue 7.1 KB

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