locationSearch.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. <template>
  2. <el-select class="location-search" v-model="locationVal" filterable remote clearable reserve-keyword :placeholder="$t('搜索位置')"
  3. :remote-method="remoteMethod" :loading="loading" @change="handleSearchRes" popper-class="location-search-popper"
  4. :class="customClass" @clear="handleClear">
  5. <el-option v-for="(item, index) in locationOptions.list" :key="index" :label="item.title"
  6. :value="{ value: item.point, item }">
  7. <span>{{ item.title }}</span>
  8. <span class="sub-title">{{ item.province }}{{ item.city }}{{ item.district }}</span>
  9. </el-option>
  10. <template #prefix>
  11. <el-icon><Search /></el-icon>
  12. </template>
  13. </el-select>
  14. </template>
  15. <script setup>
  16. import { ref, reactive } from "vue";
  17. import { transformFromGCJToWGS } from "@/utils/WSCoordinate.js";
  18. const MAP_KEY = "CZLBZ-LJICQ-R4A5J-BN62X-YXCRJ-GNBUT";
  19. const props = defineProps({
  20. userLocation: {
  21. type: String,
  22. default: "113.61702297075017,23.584863449735067",
  23. },
  24. customClass: {
  25. type: String,
  26. default: "",
  27. },
  28. });
  29. const emit = defineEmits(["change"]);
  30. const locationVal = ref(null);
  31. const locationOptions = reactive({
  32. list: [],
  33. });
  34. const loading = ref(false);
  35. const remoteMethod = async (keyword) => {
  36. if (keyword) {
  37. locationOptions.list = [];
  38. loading.value = true;
  39. const params = {
  40. key: MAP_KEY,
  41. keyword,
  42. location: props.userLocation,
  43. };
  44. await VE_API.old_mini_map.getCtiyList({ word: keyword }).then(({ data }) => {
  45. if (data && data.length) {
  46. data.forEach((item) => {
  47. item.point = item.location.lat + "," + item.location.lng;
  48. locationOptions.list.push(item);
  49. });
  50. }
  51. });
  52. VE_API.old_mini_map.search(params).then(({ data }) => {
  53. loading.value = false;
  54. data.forEach((item) => {
  55. item.point = item.location.lat + "," + item.location.lng;
  56. locationOptions.list.push(item);
  57. });
  58. });
  59. } else {
  60. locationOptions.list = [];
  61. }
  62. };
  63. const handleSearchRes = (v) => {
  64. if (!v) return;
  65. const parts = v.value.split(",");
  66. let { latitude, longitude } = transformFromGCJToWGS(parseFloat(parts[0]), parseFloat(parts[1]));
  67. const coordinateArray = [longitude, latitude];
  68. emit("change", {
  69. coordinateArray,
  70. point: `POINT (${coordinateArray[0]} ${coordinateArray[1]})`,
  71. address: v.item?.title || v.item?.address,
  72. pointAddress: v.item?.province + v.item?.city + v.item?.district,
  73. city: v.item?.city + v.item?.district || '',
  74. item: v.item,
  75. });
  76. };
  77. const handleClear = () => {
  78. emit("change", {
  79. coordinateArray: null,
  80. point: null,
  81. address: null,
  82. });
  83. locationVal.value = null;
  84. locationOptions.list = [];
  85. loading.value = false;
  86. };
  87. </script>
  88. <style lang="scss">
  89. .location-search {
  90. .el-select__wrapper {
  91. background: rgba(0, 0, 0, 0.3);
  92. box-shadow: none;
  93. border-radius: 25px;
  94. border: 1px solid rgba(255, 255, 255, 0.4);
  95. }
  96. .el-select__placeholder{
  97. color: rgba(255, 255, 255, 0.7);
  98. }
  99. .el-select__input {
  100. color: rgba(255, 255, 255, 0.7);
  101. }
  102. }
  103. .location-search-popper {
  104. .el-select-dropdown__list {
  105. max-width: 96vw;
  106. overflow-x: auto;
  107. }
  108. .sub-title {
  109. padding-left: 6px;
  110. font-size: 12px;
  111. color: #ccc;
  112. }
  113. }
  114. </style>