RegionSelection.vue 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. <template>
  2. <!-- 地区选择 -->
  3. <uv-picker
  4. ref="pickerRef"
  5. :columns="columns"
  6. keyName="name"
  7. @confirm="areaConfirm"
  8. @change="areaChange"
  9. >
  10. </uv-picker>
  11. </template>
  12. <script setup name="RegionSelection">
  13. import { computed, onMounted, ref, watch } from "vue";
  14. import { cnareaTreeLbs } from "@/api/index";
  15. const emit = defineEmits(["confirm"]);
  16. const props = defineProps({
  17. // 地区选择器层级, 默认3级
  18. // 1级 省
  19. // 2级 市
  20. // 3级 区县
  21. hierarchy: {
  22. type: Number,
  23. default: () => 3,
  24. },
  25. });
  26. const pickerRef = ref(null);
  27. const columnIndexs = ref([0, 0, 0]);
  28. const provinceList = ref([]);
  29. const municipalityNames = ["北京", "天津", "上海", "重庆"];
  30. const isMunicipality = (name) => municipalityNames.includes(String(name || ""));
  31. const getCnareaTreeLbs = () => {
  32. cnareaTreeLbs().then((res) => {
  33. if (res.code == 200) {
  34. provinceList.value = res.data?.children || [];
  35. initColumns();
  36. }
  37. });
  38. };
  39. const safeHierarchy = computed(() => {
  40. const n = Number(props.hierarchy);
  41. if (!Number.isFinite(n)) return 3;
  42. return Math.min(3, Math.max(1, n));
  43. });
  44. const selectedProvince = computed(() => {
  45. const provinces = provinceList.value || [];
  46. const pIndex = columnIndexs.value[0] || 0;
  47. return provinces[pIndex] || null;
  48. });
  49. const selectedCityList = computed(() => {
  50. return selectedProvince.value?.children || [];
  51. });
  52. const selectedMunicipalityCity = computed(() => {
  53. if (!selectedProvince.value) return null;
  54. if (!isMunicipality(selectedProvince.value.name)) return null;
  55. const cities = selectedCityList.value || [];
  56. if (cities.length !== 1) return null;
  57. return cities[0] || null;
  58. });
  59. const secondColumnList = computed(() => {
  60. if (!selectedProvince.value) return [];
  61. if (safeHierarchy.value === 1) return [];
  62. if (safeHierarchy.value === 2 && selectedMunicipalityCity.value) {
  63. return selectedMunicipalityCity.value.children || [];
  64. }
  65. return selectedCityList.value || [];
  66. });
  67. const thirdColumnList = computed(() => {
  68. if (safeHierarchy.value !== 3) return [];
  69. const p = selectedProvince.value;
  70. if (!p) return [];
  71. const cities = selectedCityList.value || [];
  72. const cIndex = columnIndexs.value[1] || 0;
  73. return cities[cIndex]?.children || [];
  74. });
  75. const initColumns = () => {
  76. const pIndex = 0;
  77. const cIndex = 0;
  78. columnIndexs.value = [pIndex, cIndex, 0];
  79. if (pickerRef.value?.setIndexs) {
  80. pickerRef.value.setIndexs(
  81. columnIndexs.value.slice(0, safeHierarchy.value),
  82. true
  83. );
  84. }
  85. };
  86. const columns = computed(() => {
  87. const provinces = provinceList.value || [];
  88. if (safeHierarchy.value === 1) return [provinces];
  89. if (safeHierarchy.value === 2) return [provinces, secondColumnList.value];
  90. return [provinces, selectedCityList.value || [], thirdColumnList.value];
  91. });
  92. // 地区选择器改变事件
  93. const areaChange = (e) => {
  94. const { columnIndex, index, indexs } = e || {};
  95. if (safeHierarchy.value === 1) return;
  96. if (columnIndex === 0) {
  97. const next = [index || 0, 0, 0];
  98. columnIndexs.value = next;
  99. pickerRef.value?.setIndexs?.(next.slice(0, safeHierarchy.value), true);
  100. return;
  101. }
  102. if (columnIndex === 1) {
  103. if (safeHierarchy.value === 2) {
  104. const next = [
  105. (indexs && indexs[0]) || columnIndexs.value[0] || 0,
  106. index || 0,
  107. 0,
  108. ];
  109. columnIndexs.value = next;
  110. pickerRef.value?.setIndexs?.(next.slice(0, safeHierarchy.value), true);
  111. return;
  112. }
  113. const next = [
  114. (indexs && indexs[0]) || columnIndexs.value[0] || 0,
  115. index || 0,
  116. 0,
  117. ];
  118. columnIndexs.value = next;
  119. pickerRef.value?.setIndexs?.(next.slice(0, safeHierarchy.value), true);
  120. }
  121. };
  122. // 地区选择器确认事件
  123. const areaConfirm = (e) => {
  124. let obj = {
  125. provinceName: undefined,
  126. provinceCode: undefined,
  127. cityName: undefined,
  128. cityCode: undefined,
  129. areaName: undefined,
  130. areaCode: undefined,
  131. };
  132. const values = e?.value || [];
  133. if (values.length > 0) {
  134. obj.provinceName = values[0]?.name;
  135. obj.provinceCode = values[0]?.id;
  136. if (safeHierarchy.value === 2) {
  137. if (isMunicipality(values[0]?.name) && selectedMunicipalityCity.value) {
  138. obj.cityName = selectedMunicipalityCity.value.name;
  139. obj.cityCode = selectedMunicipalityCity.value.id;
  140. obj.areaName = values[1]?.name;
  141. obj.areaCode = values[1]?.id;
  142. } else {
  143. obj.cityName = values[1]?.name;
  144. obj.cityCode = values[1]?.id;
  145. }
  146. } else if (safeHierarchy.value >= 3) {
  147. obj.cityName = values[1]?.name;
  148. obj.cityCode = values[1]?.id;
  149. obj.areaName = values[2]?.name;
  150. obj.areaCode = values[2]?.id;
  151. }
  152. }
  153. emit("confirm", obj);
  154. };
  155. const open = () => {
  156. // initColumns();
  157. pickerRef.value?.open?.();
  158. };
  159. onMounted(() => {
  160. getCnareaTreeLbs();
  161. });
  162. watch(
  163. () => props.hierarchy,
  164. () => {
  165. initColumns();
  166. }
  167. );
  168. defineExpose({
  169. open,
  170. });
  171. </script>
  172. <style>
  173. </style>