吉安感知网项目-前端
shuishen
5 days ago 6e88705bd5b443a259b24c17c8a299765d059d96
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
<template>
  <el-tree-select
    class="gd-select"
    popper-class="gd-tree-select-popper"
    :model-value="modelValue"
    @update:model-value="handleChange"
    node-key="id"
    :default-expanded-keys="expandedKeys"
    :props="treeSelectProps"
    :placeholder="placeholder"
    :clearable="clearable"
    :filterable="filterable"
    :check-strictly="checkStrictly"
    lazy
    :load="loadRegionNode"
    :render-after-expand="false"
  />
</template>
 
<script setup>
import { ref, watch, onMounted } from 'vue'
import request from '@/axios'
 
// 懒加载获取区域节点数据
const regionLazyTreeApi = params => {
  return request({
    url: `/blade-system/region/lazy-tree`,
    method: 'get',
    params,
  })
}
 
// 定义组件属性
const props = defineProps({
  modelValue: {
    type: [String, Number],
    default: ''
  },
  placeholder: {
    type: String,
    default: '请选择'
  },
  clearable: {
    type: Boolean,
    default: true
  },
  filterable: {
    type: Boolean,
    default: true
  },
  checkStrictly: {
    type: Boolean,
    default: true
  }
})
 
// 定义组件事件
const emit = defineEmits(['update:modelValue', 'change'])
 
// 组件内部状态
const expandedKeys = ref([]) // 展开的节点
const regionNodeCache = ref(new Map()) // 缓存区域节点
 
// 树形选择器配置
const treeSelectProps = {
  value: 'id',
  label: 'name',
  children: 'children',
  // 判断叶子节点
  isLeaf: (data, node) => {
    return node.level >= 2
  }
}
 
// 处理值变化
function handleChange(value) {
  emit('update:modelValue', value)
  // 从缓存中获取区域名称
  const node = regionNodeCache.value.get(value)
  const areaName = node?.name || ''
  // 同时返回区域代码和区域名称
  emit('change', { code: value, name: areaName })
}
 
// 懒加载获取区域节点数据
async function loadRegionNode(node, resolve) {
  try {
    // 限制只加载两级,当前节点 level >= 1 时不加载子节点
    if (node.level >= 2) {
      resolve([])
      return
    }
 
    // 初始化加载时传递 code 参数,加载子节点时传递 parentCode 参数
    const params = node.data?.id ? { parentCode: node.data.id } : { code: '360800000000' }
    const parentCode = node.data?.id || '360800000000'
    const res = await regionLazyTreeApi(params)
    const nodes = res?.data?.data || []
 
    // 处理返回的节点数据
    const processedNodes = nodes.map(item => {
      const nodeId = item.id || item.value
      // 缓存节点及其父节点关系
      regionNodeCache.value.set(nodeId, {
        id: nodeId,
        name: item.name || item.title || item.label,
        parentId: parentCode,
        hasChildren: item.hasChildren || false
      })
 
      return {
        id: nodeId,
        name: item.name || item.title || item.label,
        hasChildren: item.hasChildren || false
      }
    })
 
    resolve(processedNodes)
  } catch (error) {
    console.error('获取区域数据失败:', error)
    resolve([])
  }
}
 
// 加载区域节点路径
async function loadRegionPath(regionCode) {
  if (!regionCode) return
 
  try {
    const path = []
    const queue = [{ code: '360800000000', currentPath: ['360800000000'] }]
    let found = false
 
    // 广度优先搜索,逐层加载节点直到找到目标节点
    while (queue.length > 0 && !found) {
      const { code, currentPath } = queue.shift()
 
      // 获取当前节点的子节点
      const res = await regionLazyTreeApi({ parentCode: code })
      const nodes = res?.data?.data || []
 
      for (const node of nodes) {
        const nodeId = node.id || node.value
 
        // 缓存节点及其父节点关系
        regionNodeCache.value.set(nodeId, {
          id: nodeId,
          name: node.name || node.title || node.label,
          parentId: code,
          hasChildren: node.hasChildren || false
        })
 
        // 检查是否找到目标节点
        if (nodeId === regionCode) {
          path.push(...currentPath, nodeId)
          found = true
          break
        }
 
        // 如果有子节点,加入队列继续搜索
        if (node.hasChildren) {
          queue.push({
            code: nodeId,
            currentPath: [...currentPath, nodeId]
          })
        }
      }
    }
 
    if (path.length > 0) {
      expandedKeys.value = path
    }
  } catch (error) {
    console.error('加载区域路径失败:', error)
  }
}
 
// 监听modelValue变化,当值变化时加载路径
watch(
  () => props.modelValue,
  async (newValue) => {
    if (newValue) {
      await loadRegionPath(String(newValue))
    } else {
      expandedKeys.value = []
    }
  },
  { immediate: true }
)
 
// 暴露方法给父组件
defineExpose({
  loadRegionPath
})
</script>
 
<style scoped lang="scss">
</style>