AreaPickerCustommer.vue 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. <!-- components/AreaPicker.vue -->
  2. <template>
  3. <view>
  4. <!-- 地区选择器 -->
  5. <u-picker
  6. :show="show"
  7. :columns="areaColumns"
  8. keyName="label"
  9. @confirm="handleConfirm"
  10. @cancel="handleCancel"
  11. @change="handleChange"
  12. ref="pickerRef"
  13. ></u-picker>
  14. </view>
  15. </template>
  16. <script setup>
  17. import { ref, watch, nextTick, onMounted, reactive, defineProps, defineEmits } from 'vue';
  18. import { getProvinces, getCities, getDistricts } from '@/utils/area-data.js';
  19. // 定义props
  20. const props = defineProps({
  21. show: {
  22. type: Boolean,
  23. default: false
  24. }
  25. });
  26. // 定义emits
  27. const emit = defineEmits(['update:show', 'confirm']);
  28. // 响应式数据
  29. const areaColumns = reactive([[], [], []]);
  30. const pickerRef = ref(null);
  31. const isUpdating = ref(false); // 防止重复更新
  32. // 初始化数据
  33. const initAreaData = () => {
  34. // 获取省份数据
  35. const provinces = getProvinces();
  36. areaColumns[0] = provinces;
  37. // 获取第一个省份的城市
  38. if (provinces.length > 0) {
  39. const cities = getCities(provinces[0].value);
  40. areaColumns[1] = cities;
  41. // 获取第一个城市的区县
  42. if (cities.length > 0) {
  43. const districts = getDistricts(cities[0].value);
  44. areaColumns[2] = districts;
  45. }
  46. }
  47. };
  48. // 处理选择器变化
  49. const handleChange = (e) => {
  50. if (isUpdating.value) return; // 防止重复更新
  51. const valueIndex = e.indexs; // 获取索引数组
  52. console.log('选择器变化 - 索引:', valueIndex);
  53. // 省份变化 (第一列)
  54. if (valueIndex[0] !== undefined) {
  55. isUpdating.value = true;
  56. // 通过索引获取省份对象
  57. const province = areaColumns[0][valueIndex[0]];
  58. console.log('选择了省份:', province);
  59. if (province) {
  60. // 获取城市数据
  61. const cities = getCities(province.value);
  62. areaColumns[1] = cities;
  63. // 检查城市索引是否超出范围
  64. let cityIndex = valueIndex[1] || 0;
  65. if (cityIndex >= cities.length) {
  66. cityIndex = 0; // 超出范围则重置为0
  67. }
  68. // 获取区县数据
  69. let districts = [];
  70. if (cities.length > 0) {
  71. // 使用调整后的城市索引获取区县数据
  72. const selectedCity = cities[cityIndex];
  73. if (selectedCity) {
  74. districts = getDistricts(selectedCity.value);
  75. } else if (cities.length > 0) {
  76. // 如果选中的城市不存在,使用第一个城市
  77. districts = getDistricts(cities[0].value);
  78. }
  79. } else {
  80. // 直辖市情况:直接使用省份code获取区县
  81. districts = getDistricts(province.value);
  82. }
  83. areaColumns[2] = districts;
  84. // 检查区县索引是否超出范围
  85. let districtIndex = valueIndex[2] || 0;
  86. if (districtIndex >= districts.length) {
  87. districtIndex = 0; // 超出范围则重置为0
  88. }
  89. // 更新选择器位置
  90. nextTick(() => {
  91. if (pickerRef.value && pickerRef.value.setIndexes) {
  92. // 重置城市和区县索引(市超出则重置为0,区超出也重置为0)
  93. pickerRef.value.setIndexes([valueIndex[0], cityIndex, districtIndex]);
  94. }
  95. isUpdating.value = false;
  96. });
  97. } else {
  98. isUpdating.value = false;
  99. }
  100. return; // 省份变化处理后直接返回,避免城市变化逻辑执行
  101. }
  102. // 城市变化 (第二列)
  103. if (valueIndex[1] !== undefined && areaColumns[1].length > 0) {
  104. isUpdating.value = true;
  105. // 检查城市索引是否超出范围
  106. let cityIndex = valueIndex[1];
  107. if (cityIndex >= areaColumns[1].length) {
  108. cityIndex = 0; // 超出范围则重置为0
  109. }
  110. // 通过索引获取城市对象
  111. const city = areaColumns[1][cityIndex];
  112. if (city) {
  113. // 获取区县数据
  114. const districts = getDistricts(city.value);
  115. areaColumns[2] = districts;
  116. // 检查区县索引是否超出范围
  117. let districtIndex = valueIndex[2] || 0;
  118. if (districtIndex >= districts.length) {
  119. districtIndex = 0; // 超出范围则重置为0
  120. }
  121. // 更新选择器位置
  122. nextTick(() => {
  123. if (pickerRef.value && pickerRef.value.setIndexes) {
  124. // 获取当前的省份索引
  125. const currentIndexes = pickerRef.value.getIndexes ? pickerRef.value.getIndexes() : [0, 0, 0];
  126. const provinceIndex = currentIndexes[0];
  127. // 设置索引:省份保持当前,城市使用调整后的索引,区县使用调整后的索引
  128. pickerRef.value.setIndexes([provinceIndex, cityIndex, districtIndex]);
  129. }
  130. isUpdating.value = false;
  131. });
  132. } else {
  133. isUpdating.value = false;
  134. }
  135. }
  136. };
  137. // 确认选择
  138. const handleConfirm = (e) => {
  139. const areaData = e.value;
  140. // 根据选中的对象获取值
  141. const province = areaData[0];
  142. const city = areaData[1] !== undefined ? areaData[1] : { label: '', value: '' };
  143. const district = areaData[2] !== undefined ? areaData[2] : { label: '', value: '' };
  144. const result = {
  145. province: {
  146. name: province.label,
  147. code: province.value
  148. },
  149. city: city.label ? {
  150. name: city.label,
  151. code: city.value
  152. } : null,
  153. district: district.label ? {
  154. name: district.label,
  155. code: district.value
  156. } : null,
  157. fullAddress: province.label + (city.label ? ' ' + city.label : '') + (district.label ? ' ' + district.label : '')
  158. };
  159. console.log('确认选择:', result);
  160. emit('confirm', result);
  161. emit('update:show', false);
  162. };
  163. // 取消选择
  164. const handleCancel = () => {
  165. emit('update:show', false);
  166. };
  167. // 组件挂载时初始化数据
  168. onMounted(() => {
  169. console.log('AreaPicker 组件已挂载');
  170. initAreaData();
  171. });
  172. // 监听显示状态
  173. watch(() => props.show, (newVal) => {
  174. console.log('show 状态变化:', newVal);
  175. if (newVal) {
  176. // 每次显示时重新初始化数据
  177. initAreaData();
  178. // 延迟设置选择器位置,确保DOM已更新
  179. setTimeout(() => {
  180. if (pickerRef.value && pickerRef.value.setIndexes) {
  181. pickerRef.value.setIndexes([0, 0, 0]);
  182. }
  183. }, 100);
  184. }
  185. });
  186. </script>