SelectLocationDialog.vue 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. <template>
  2. <el-dialog
  3. :model-value="modelValue"
  4. title="选择存放点位"
  5. width="920px"
  6. align-center
  7. append-to-body
  8. destroy-on-close
  9. class="select-location-dialog"
  10. @update:model-value="emit('update:modelValue', $event)"
  11. @opened="handleOpened"
  12. @closed="handleClosed"
  13. >
  14. <div v-loading="loading" class="map-wrap">
  15. <div ref="mapRef" class="map-el"></div>
  16. <div v-if="!loading && regionCount === 0" class="map-empty">暂无区域数据</div>
  17. <div class="map-tip">点击地图放置存放位置</div>
  18. </div>
  19. <template #footer>
  20. <div class="dialog-footer">
  21. <el-button @click="close">取消</el-button>
  22. <el-button type="primary" @click="handleConfirm">确认</el-button>
  23. </div>
  24. </template>
  25. </el-dialog>
  26. </template>
  27. <script setup>
  28. import { getCurrentInstance, nextTick, ref } from "vue";
  29. import { ElMessage } from "element-plus";
  30. import { wktCastGeom } from "@/common/ol_common";
  31. import LocationSelectMap from "./locationSelectMap";
  32. const props = defineProps({
  33. modelValue: {
  34. type: Boolean,
  35. default: false,
  36. },
  37. farmId: {
  38. type: [String, Number],
  39. default: 101532,
  40. },
  41. /** 已选点位 WKT,编辑回显 */
  42. locationWkt: {
  43. type: String,
  44. default: "",
  45. },
  46. });
  47. const emit = defineEmits(["update:modelValue", "confirm"]);
  48. const { proxy } = getCurrentInstance();
  49. const mapRef = ref(null);
  50. const loading = ref(false);
  51. const regionCount = ref(0);
  52. let locationMap = null;
  53. const close = () => emit("update:modelValue", false);
  54. const handleOpened = async () => {
  55. await nextTick();
  56. if (!mapRef.value) return;
  57. if (!locationMap) {
  58. locationMap = new LocationSelectMap();
  59. }
  60. const initLocation =
  61. props.locationWkt || "POINT(113.61448114737868 23.585550924763083)";
  62. locationMap.init(mapRef.value, initLocation);
  63. await loadRegions();
  64. locationMap.updateSize();
  65. };
  66. const loadRegions = async () => {
  67. loading.value = true;
  68. regionCount.value = 0;
  69. try {
  70. const res = await proxy.VE_API.farm.blueRegionList({
  71. farmId: props.farmId,
  72. regionId: "",
  73. });
  74. const list = Array.isArray(res?.data) ? res.data : [];
  75. regionCount.value = list.length;
  76. locationMap?.setRegions(list);
  77. // 等 fit 完成后再放点,避免先出现在默认位置再消失
  78. await nextTick();
  79. requestAnimationFrame(() => {
  80. if (props.locationWkt) {
  81. try {
  82. const coord = wktCastGeom(props.locationWkt).getFirstCoordinate();
  83. locationMap?.setPoint(coord);
  84. } catch (e) {
  85. locationMap?.setPointToCenter();
  86. }
  87. } else {
  88. locationMap?.setPointToCenter();
  89. }
  90. });
  91. if (!list.length && res?.msg) {
  92. ElMessage.warning(res.msg);
  93. }
  94. } catch (e) {
  95. console.error(e);
  96. ElMessage.error("区域数据加载失败");
  97. } finally {
  98. loading.value = false;
  99. nextTick(() => locationMap?.updateSize());
  100. }
  101. };
  102. const handleConfirm = () => {
  103. const point = locationMap?.getPoint();
  104. if (!point) {
  105. ElMessage.warning("请在地图上选择存放点位");
  106. return;
  107. }
  108. emit("confirm", point);
  109. close();
  110. };
  111. const handleClosed = () => {
  112. locationMap?.destroy();
  113. locationMap = null;
  114. regionCount.value = 0;
  115. };
  116. </script>
  117. <style lang="scss" scoped>
  118. .map-wrap {
  119. position: relative;
  120. width: 100%;
  121. height: 520px;
  122. background: #d3d7d8;
  123. border-radius: 4px;
  124. overflow: hidden;
  125. cursor: pointer;
  126. }
  127. .map-el {
  128. width: 100%;
  129. height: 100%;
  130. }
  131. .map-empty {
  132. position: absolute;
  133. inset: 0;
  134. display: flex;
  135. align-items: center;
  136. justify-content: center;
  137. color: #999;
  138. pointer-events: none;
  139. z-index: 2;
  140. }
  141. .map-tip {
  142. position: absolute;
  143. left: 16px;
  144. bottom: 16px;
  145. z-index: 3;
  146. padding: 6px 12px;
  147. border-radius: 4px;
  148. background: rgba(0, 0, 0, 0.55);
  149. color: #fff;
  150. font-size: 13px;
  151. pointer-events: none;
  152. }
  153. .dialog-footer {
  154. display: flex;
  155. justify-content: center;
  156. gap: 16px;
  157. padding-bottom: 4px;
  158. }
  159. </style>
  160. <style lang="scss">
  161. .select-location-dialog {
  162. .el-dialog__body {
  163. padding: 12px 20px 8px;
  164. }
  165. }
  166. </style>