index.vue 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. <template>
  2. <el-cascader ref="cascader" v-model="selectedValues" :options="options" :props="cascaderProps"
  3. :placeholder="placeholder" :clearable="clearable" :disabled="disabled" :size="size" @change="handleChange"
  4. @expand-change="handleExpandChange" filterable />
  5. </template>
  6. <script>
  7. import { getLazyTree } from '@/api/base/region'
  8. export default {
  9. name: 'RegionCascader',
  10. props: {
  11. value: {
  12. type: [String, Array],
  13. default: ''
  14. },
  15. placeholder: {
  16. type: String,
  17. default: '请选择省/市/区'
  18. },
  19. clearable: {
  20. type: Boolean,
  21. default: true
  22. },
  23. disabled: {
  24. type: Boolean,
  25. default: false
  26. },
  27. size: {
  28. type: String,
  29. default: 'small'
  30. }
  31. },
  32. data() {
  33. return {
  34. options: [],
  35. selectedValues: [],
  36. initialValue: null, // 保存初始值
  37. cascaderProps: {
  38. value: 'value',
  39. label: 'title',
  40. children: 'children',
  41. lazy: true,
  42. lazyLoad: this.lazyLoad,
  43. checkStrictly: false
  44. }
  45. }
  46. },
  47. watch: {
  48. value: {
  49. handler(newVal) {
  50. if (typeof newVal === 'string' && newVal) {
  51. // 如果省份数据还没加载,先保存初始值
  52. if (this.options.length === 0) {
  53. this.initialValue = newVal
  54. } else {
  55. this.parseRegionName(newVal)
  56. }
  57. } else if (Array.isArray(newVal)) {
  58. this.selectedValues = [...newVal]
  59. } else {
  60. this.selectedValues = []
  61. }
  62. },
  63. immediate: true
  64. }
  65. },
  66. mounted() {
  67. this.loadProvinces().then(() => {
  68. // 省份数据加载完成后,处理初始值
  69. if (this.initialValue) {
  70. this.parseRegionName(this.initialValue).then(() => {
  71. this.initialValue = null
  72. })
  73. }
  74. })
  75. },
  76. methods: {
  77. /**
  78. * 解析regionName字符串,查找对应的代码路径
  79. * @param {string} regionName - 省市区名称,用空格分割
  80. */
  81. async parseRegionName(regionName) {
  82. if (!regionName) {
  83. this.selectedValues = []
  84. return
  85. }
  86. const regions = regionName.split(' ').filter(item => item.trim())
  87. if (regions.length === 0) {
  88. this.selectedValues = []
  89. return
  90. }
  91. try {
  92. // 确保省份数据已加载
  93. if (this.options.length === 0) {
  94. await this.loadProvinces()
  95. }
  96. const codes = []
  97. // 查找省级
  98. if (regions[0]) {
  99. const province = this.options.find(item => item.title === regions[0])
  100. if (province) {
  101. codes.push(province.value)
  102. // 查找市级
  103. if (regions[1]) {
  104. const cityRes = await getLazyTree(province.value)
  105. if (cityRes.data.success) {
  106. const city = cityRes.data.data.find(item => item.title === regions[1])
  107. if (city) {
  108. codes.push(city.value)
  109. // 查找区级
  110. if (regions[2]) {
  111. const districtRes = await getLazyTree(city.value)
  112. if (districtRes.data.success) {
  113. const district = districtRes.data.data.find(item => item.title === regions[2])
  114. if (district) {
  115. codes.push(district.value)
  116. }
  117. }
  118. }
  119. }
  120. }
  121. }
  122. }
  123. }
  124. this.selectedValues = codes
  125. } catch (error) {
  126. console.error('解析regionName失败:', error)
  127. this.selectedValues = []
  128. }
  129. },
  130. async loadProvinces() {
  131. try {
  132. const res = await getLazyTree('00')
  133. if (res.data.success) {
  134. this.options = res.data.data.map(item => ({
  135. ...item,
  136. leaf: false
  137. }))
  138. }
  139. } catch (error) {
  140. console.error('加载省级数据失败:', error)
  141. this.$message.error('加载省级数据失败')
  142. }
  143. },
  144. async lazyLoad(node, resolve) {
  145. const { level, value } = node
  146. try {
  147. // 如果是第三级(区级),直接返回空数组,不再加载子级
  148. if (level >= 3) {
  149. resolve([])
  150. return
  151. }
  152. const res = await getLazyTree(value)
  153. if (res.data.success) {
  154. const children = res.data.data.map(item => ({
  155. ...item,
  156. leaf: level >= 2 // 市级的子级(区级)设为叶子节点
  157. }))
  158. resolve(children)
  159. } else {
  160. resolve([])
  161. }
  162. } catch (error) {
  163. console.error('加载子级数据失败:', error)
  164. resolve([])
  165. }
  166. },
  167. /**
  168. * 选择改变事件
  169. * @param {Array} values - 选中的值数组
  170. */
  171. handleChange(values) {
  172. this.selectedValues = values || []
  173. // 获取选中的节点信息
  174. // const selectedNodes = this.$refs.cascader?.getCheckedNodes() || []
  175. const selectedNodes = this.$refs.cascader ? this.$refs.cascader.getCheckedNodes() : []
  176. let regionName = ''
  177. if (values && values.length > 0) {
  178. // 获取选中的节点信息
  179. const selectedNodes = this.$refs.cascader.getCheckedNodes()
  180. if (selectedNodes.length > 0) {
  181. const node = selectedNodes[0]
  182. regionName = node.pathLabels.join(' ')
  183. }
  184. }
  185. // 直接返回regionName作为组件的值,这样avue-crud可以正确验证
  186. this.$emit('input', regionName)
  187. this.$emit('change', {
  188. values,
  189. regionName,
  190. })
  191. },
  192. /**
  193. * 展开改变事件
  194. * @param {Array} activeValues - 当前展开的值
  195. */
  196. handleExpandChange(activeValues) {
  197. this.$emit('expand-change', activeValues)
  198. }
  199. },
  200. }
  201. </script>