index.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. <template>
  2. <div class="flex flex-wrap">
  3. <el-select v-model="selectedValue" filterable remote reserve-keyword :placeholder="placeholder"
  4. :remote-method="debouncedRemoteMethod" :loading="loading" :multiple="multiple" :disabled="disabled"
  5. :style="{ width: width }" :multiple-limit="max" clearable>
  6. <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
  7. </el-select>
  8. </div>
  9. </template>
  10. <script lang="ts" setup>
  11. import { onMounted, ref, watch, defineProps, defineEmits, onUnmounted } from 'vue'
  12. import { debounce } from 'lodash-es'
  13. import { listUser, getUser } from "@/api/system/user"
  14. import { unref } from 'vue'
  15. interface ListItem {
  16. value: string
  17. label: string
  18. }
  19. // 定义组件属性
  20. const props = defineProps<{
  21. modelValue: string | string[]
  22. multiple?: boolean
  23. disabled?: boolean
  24. width?: string
  25. max?: number
  26. placeholder?: string
  27. }>()
  28. // 定义组件事件
  29. const emits = defineEmits(['update:modelValue'])
  30. const options = ref<ListItem[]>([])
  31. const loading = ref(false)
  32. const selectedValue = ref<string | string[]>(props.modelValue)
  33. // 根据用户ID列表获取用户信息
  34. const fetchUsersByIds = async (userIds: string[]) => {
  35. if (!userIds || userIds.length === 0) return []
  36. try {
  37. // 使用Promise.all并行获取每个用户的信息
  38. const userPromises = userIds.map(userId => getUser(userId))
  39. const userResponses = await Promise.all(userPromises)
  40. return userResponses.map((response: any) => ({
  41. value: response.data.userId,
  42. label: response.data.nickName
  43. }))
  44. } catch (error) {
  45. console.error('获取用户信息失败:', error)
  46. return []
  47. }
  48. }
  49. // 远程搜索方法
  50. const remoteMethod = async (query: string) => {
  51. if (query) {
  52. loading.value = true
  53. try {
  54. // 调用远程接口获取数据
  55. const response = await listUser({ nickName: query })
  56. // 假设接口返回的数据结构为 { data: [...] },根据实际情况调整
  57. options.value = response.rows.map((item) => ({
  58. value: item.userId, // 根据实际接口返回字段调整
  59. label: item.nickName // 根据实际接口返回字段调整
  60. }))
  61. } catch (error) {
  62. console.error('远程搜索出错:', error)
  63. } finally {
  64. loading.value = false
  65. }
  66. } else {
  67. options.value = []
  68. }
  69. }
  70. // 防抖处理远程搜索
  71. const debouncedRemoteMethod = debounce(remoteMethod, 300)
  72. // 标记是否正在初始化回显,避免循环更新
  73. const isInitializing = ref(false)
  74. // 监听modelValue变化,有值时执行回显逻辑
  75. watch(() => props.modelValue, async (newValue, oldValue) => {
  76. // 只有当值从无到有或值发生变化时才执行回显
  77. if (newValue && newValue.length > 0 && newValue !== oldValue) {
  78. isInitializing.value = true
  79. try {
  80. const userIds = Array.isArray(newValue) ? newValue : [newValue]
  81. const userOptions = await fetchUsersByIds(userIds)
  82. options.value = userOptions
  83. // 设置选中值,但不触发更新事件
  84. selectedValue.value = newValue
  85. } finally {
  86. isInitializing.value = false
  87. }
  88. }
  89. }, { immediate: true })
  90. // 监听选中值变化并触发更新事件
  91. watch(selectedValue, (newValue) => {
  92. // 只有在非初始化状态下才触发更新事件
  93. if (!isInitializing.value) {
  94. emits('update:modelValue', newValue)
  95. }
  96. })
  97. // 组件销毁时清空数据
  98. onUnmounted(() => {
  99. options.value = []
  100. selectedValue.value = props.multiple ? [] : ''
  101. emits('update:modelValue', selectedValue.value)
  102. })
  103. </script>
  104. <style scoped lang="scss">
  105. .flex {
  106. width: 100%;
  107. }
  108. </style>