index.vue 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. <template>
  2. <el-cascader
  3. v-model="selectedValue"
  4. :options="options"
  5. :props="cascaderProps"
  6. :placeholder="placeholder"
  7. :disabled="disabled"
  8. :style="{ width: width }"
  9. filterable
  10. clearable
  11. collapse-tags
  12. collapse-tags-tooltip
  13. separator="/"
  14. @change="handleChange"
  15. @clear="handleClear"
  16. />
  17. </template>
  18. <script lang="ts" setup>
  19. import { ref, watch, computed, onMounted, nextTick } from 'vue'
  20. import { treePosition } from '@/api/system/position'
  21. const props = defineProps<{
  22. modelValue: any
  23. disabled?: boolean
  24. width?: string
  25. placeholder?: string
  26. }>()
  27. const emits = defineEmits(['update:modelValue', 'change'])
  28. const options = ref<any[]>([])
  29. const loading = ref(false)
  30. const selectedValue = ref<any[]>([])
  31. const dataLoaded = ref(false)
  32. const placeholder = computed(() => props.placeholder || '请选择安装位置')
  33. const cascaderProps = {
  34. value: 'code',
  35. label: 'name',
  36. children: 'children',
  37. expandTrigger: 'hover' as const
  38. }
  39. const loadData = async () => {
  40. if (dataLoaded.value) return
  41. loading.value = true
  42. try {
  43. const response = await treePosition()
  44. options.value = response.data || []
  45. dataLoaded.value = true
  46. // 等待DOM更新后再设置选中值
  47. await nextTick()
  48. await nextTick()
  49. if (props.modelValue) {
  50. updateSelectedValue(props.modelValue)
  51. }
  52. } catch (error) {
  53. console.error('获取位置列表失败:', error)
  54. } finally {
  55. loading.value = false
  56. }
  57. }
  58. const updateSelectedValue = (value: any) => {
  59. if (value && typeof value === 'object') {
  60. const obj = value as any
  61. selectedValue.value = [obj.terminlCode, obj.regionalCode, obj.channelCode].filter(Boolean)
  62. } else {
  63. selectedValue.value = []
  64. }
  65. }
  66. const findNodeByCode = (nodes: any[], code: string): any | null => {
  67. for (const node of nodes) {
  68. if (node.code === code) {
  69. return node
  70. }
  71. if (node.children && node.children.length > 0) {
  72. const found = findNodeByCode(node.children, code)
  73. if (found) return found
  74. }
  75. }
  76. return null
  77. }
  78. const handleChange = (value: any) => {
  79. console.log(value,"value")
  80. if (!value || value.length === 0) {
  81. selectedValue.value = []
  82. emits('update:modelValue', null)
  83. emits('change', null)
  84. return
  85. }
  86. const terminal = findNodeByCode(options.value, value[0])
  87. const region = value[1] ? findNodeByCode(options.value, value[1]) || (terminal?.children?.find((c: any) => c.code === value[1])) : null
  88. const channel = value[2] ? (region?.children?.find((c: any) => c.code === value[2])) : null
  89. const result = {
  90. terminlCode: value[0] || '',
  91. terminlName: terminal?.name || '',
  92. regionalCode: value[1] || '',
  93. regionalName: region?.name || '',
  94. channelCode: value[2] || '',
  95. channelName: channel?.name || ''
  96. }
  97. emits('update:modelValue', result)
  98. emits('change', result)
  99. }
  100. const handleClear = () => {
  101. selectedValue.value = []
  102. emits('update:modelValue', null)
  103. emits('change', null)
  104. }
  105. watch(() => props.modelValue, async (newValue) => {
  106. if (newValue) {
  107. if (!dataLoaded.value) {
  108. await loadData()
  109. } else {
  110. await nextTick()
  111. updateSelectedValue(newValue)
  112. }
  113. }
  114. }, { deep: true, immediate: true })
  115. watch(() => options.value, (newOptions) => {
  116. if (newOptions.length > 0 && props.modelValue) {
  117. nextTick(() => {
  118. updateSelectedValue(props.modelValue)
  119. })
  120. }
  121. }, { immediate: false })
  122. onMounted(() => {
  123. loadData()
  124. })
  125. </script>
  126. <style scoped>
  127. </style>