uni-areaCascadePicker.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. <template>
  2. <view class="addressPicker">
  3. <u-picker :show="shows" ref="uPicker" :defaultIndex="defaultIndex" :columns="columns" keyName="name"
  4. @change="changeHandler" @cancel="cancel" @confirm="confirm" @close="close"
  5. :closeOnClickOverlay="true"></u-picker>
  6. </view>
  7. </template>
  8. <script>
  9. import address from '@/utils/address.json'
  10. export default {
  11. props: {
  12. show: Boolean,
  13. defaultIndex: {
  14. type: Array,
  15. default: () => {
  16. return [0, 0, 0]
  17. },
  18. },
  19. defaultCodes: { // 改为接收标准6位码数组
  20. type: Array,
  21. default: () => ['110000', '110100', '110101'] // 默认北京东城区
  22. }
  23. },
  24. data() {
  25. return {
  26. shows: this.show,
  27. columns: [
  28. [],
  29. [],
  30. []
  31. ], // 省/市/区三级数据
  32. fullData: [] // 包含完整结构的缓存数据
  33. }
  34. },
  35. watch: {
  36. show(val) {
  37. this.shows = val
  38. if (val) this.initByCodes(this.defaultCodes)
  39. },
  40. defaultCodes: {
  41. immediate: true,
  42. handler(codes) {
  43. this.initByCodes(codes)
  44. }
  45. }
  46. },
  47. async created() {
  48. await this.initData()
  49. },
  50. methods: {
  51. // 初始化数据结构(含6位码处理)
  52. initData() {
  53. this.fullData = address.map(province => ({
  54. ...province,
  55. code: this.ensure6DigitCode(province.code),
  56. children: province.children.map(city => ({
  57. ...city,
  58. code: this.ensure6DigitCode(city.code),
  59. children: (city.children || []).map(area => ({
  60. ...area,
  61. code: this.ensure6DigitCode(area.code)
  62. }))
  63. }))
  64. }))
  65. // 初始化省级选项
  66. this.columns[0] = this.fullData.map(p => ({
  67. name: p.name,
  68. code: p.code
  69. }))
  70. this.initDefaultSelection();
  71. },
  72. initDefaultSelection() {
  73. if (this.defaultCodes && this.defaultCodes.length >= 3) {
  74. // 如果传入了defaultCodes,优先使用
  75. this.initByCodes(this.defaultCodes);
  76. } else {
  77. // 否则自动选择第一个省+第一个市+第一个区
  78. const firstProvince = this.fullData[0];
  79. const firstCity = firstProvince.children?.[0];
  80. const firstArea = firstCity?.children?.[0];
  81. this.columns[1] = firstProvince.children?.map(c => ({
  82. name: c.name,
  83. code: c.code
  84. })) || [];
  85. this.columns[2] = firstCity?.children?.map(a => ({
  86. name: a.name,
  87. code: a.code
  88. })) || [];
  89. // 设置Picker选中状态
  90. this.$nextTick(() => {
  91. this.$refs.uPicker?.setIndexs([0, 0, 0]);
  92. });
  93. }
  94. },
  95. // 根据6位码初始化选中状态
  96. initByCodes(codes) {
  97. if (!codes || codes.length < 3) return
  98. // 1. 查找省级索引
  99. const provIndex = this.fullData.findIndex(
  100. p => p.code === codes[0]
  101. )
  102. if (provIndex === -1) return
  103. // 2. 设置市级数据
  104. const cities = this.fullData[provIndex].children
  105. this.columns[1] = cities.map(c => ({
  106. name: c.name,
  107. code: c.code
  108. }))
  109. // 3. 查找市级索引
  110. const cityIndex = cities.findIndex(
  111. c => c.code === codes[1]
  112. )
  113. if (cityIndex === -1) return
  114. // 4. 设置区级数据
  115. const areas = cities[cityIndex].children
  116. this.columns[2] = areas.map(a => ({
  117. name: a.name,
  118. code: a.code
  119. }))
  120. },
  121. // 确保6位行政区划码
  122. ensure6DigitCode(code) {
  123. if (!code) return ''
  124. if (code.length === 2) return code + '0000'
  125. if (code.length === 4) return code + '00'
  126. return code // 6位或9位码保持不变
  127. },
  128. // 选择变化事件(适配6位码)
  129. changeHandler(e) {
  130. const {
  131. columnIndex,
  132. index
  133. } = e
  134. if (columnIndex === 0) {
  135. // 省份变化
  136. const cities = this.fullData[index].children
  137. this.columns[1] = cities.map(c => ({
  138. name: c.name,
  139. code: c.code
  140. }))
  141. this.columns[2] = cities[0]?.children.map(a => ({
  142. name: a.name,
  143. code: a.code
  144. })) || []
  145. this.$refs.uPicker.setColumnValues(1, this.columns[1])
  146. this.$refs.uPicker.setColumnValues(2, this.columns[2])
  147. } else if (columnIndex === 1) {
  148. // 城市变化
  149. const areas = this.fullData[e.indexs[0]].children[index].children
  150. this.columns[2] = areas.map(a => ({
  151. name: a.name,
  152. code: a.code
  153. }))
  154. this.$refs.uPicker.setColumnValues(2, this.columns[2])
  155. }
  156. },
  157. cancel() {
  158. this.$emit('cancel')
  159. },
  160. close() {
  161. this.$emit('close')
  162. },
  163. confirm(e) {
  164. const selected = e.value
  165. this.$emit('confirm', {
  166. names: selected.map(i => i.name),
  167. codes: selected.map(i => i.code), // 标准6位码
  168. fullAddress: selected.map(i => i.name).join('-')
  169. })
  170. }
  171. }
  172. }
  173. </script>
  174. <style lang="scss" scoped>
  175. </style>