index.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. <template>
  2. <Dialog v-model="dialogVisible" title="人员选择" width="800">
  3. <el-row class="gap2" v-loading="formLoading">
  4. <el-col :span="6">
  5. <ContentWrap class="h-1/1">
  6. <el-tree
  7. ref="treeRef"
  8. :data="deptTree"
  9. :expand-on-click-node="false"
  10. :props="defaultProps"
  11. default-expand-all
  12. highlight-current
  13. node-key="id"
  14. @node-click="handleNodeClick"
  15. />
  16. </ContentWrap>
  17. </el-col>
  18. <el-col :span="17">
  19. <el-transfer
  20. v-model="selectedUserIdList"
  21. :titles="['未选', '已选']"
  22. filterable
  23. filter-placeholder="搜索成员"
  24. :data="transferUserList"
  25. :props="{ label: 'nickname', key: 'id' }"
  26. />
  27. </el-col>
  28. </el-row>
  29. <template #footer>
  30. <el-button
  31. :disabled="formLoading || !selectedUserIdList?.length"
  32. type="primary"
  33. @click="submitForm"
  34. >
  35. 确 定
  36. </el-button>
  37. <el-button @click="dialogVisible = false">取 消</el-button>
  38. </template>
  39. </Dialog>
  40. </template>
  41. <script lang="ts" setup>
  42. import { defaultProps, findTreeNode, handleTree } from '@/utils/tree'
  43. import * as DeptApi from '@/api/system/dept'
  44. import * as UserApi from '@/api/system/user'
  45. defineOptions({ name: 'UserSelectForm' })
  46. const emit = defineEmits<{
  47. confirm: [id: any, userList: any[]]
  48. }>()
  49. const { t } = useI18n() // 国际
  50. const message = useMessage() // 消息弹窗
  51. const deptTree = ref<Tree[]>([]) // 部门树形结构化
  52. const userList = ref<UserApi.UserVO[]>([]) // 所有用户列表
  53. const filteredUserList = ref<UserApi.UserVO[]>([]) // 当前部门过滤后的用户列表
  54. const selectedUserIdList: any = ref([]) // 选中的用户列表
  55. const dialogVisible = ref(false) // 弹窗的是否展示
  56. const formLoading = ref(false) // 表单的加载中
  57. const activityId = ref()
  58. /** 计算属性:合并已选择的用户和当前部门过滤后的用户 */
  59. const transferUserList = computed(() => {
  60. // 1.1 获取所有已选择的用户
  61. const selectedUsers = userList.value.filter((user: any) =>
  62. selectedUserIdList.value.includes(user.id)
  63. )
  64. // 1.2 获取当前部门过滤后的未选择用户
  65. const filteredUnselectedUsers = filteredUserList.value.filter(
  66. (user: any) => !selectedUserIdList.value.includes(user.id)
  67. )
  68. // 2. 合并并去重
  69. return [...selectedUsers, ...filteredUnselectedUsers]
  70. })
  71. /** 打开弹窗 */
  72. const open = async (id: number, selectedList?: any[]) => {
  73. activityId.value = id
  74. resetForm()
  75. // 加载部门、用户列表
  76. deptTree.value = handleTree(await DeptApi.getSimpleDeptList())
  77. userList.value = await UserApi.getSimpleUserList()
  78. // 初始状态下,过滤列表等于所有用户列表
  79. filteredUserList.value = [...userList.value]
  80. selectedUserIdList.value = selectedList?.map((item: any) => item.id) || []
  81. dialogVisible.value = true
  82. }
  83. /** 获取部门过滤后的用户列表 */
  84. const getUserList = async (deptId?: number) => {
  85. formLoading.value = true
  86. try {
  87. // @ts-ignore
  88. // TODO @芋艿:替换到 simple List 暂不支持 deptId 过滤
  89. // TODO @Zqqq:这个,可以使用前端过滤么?通过 deptList 获取到 deptId 子节点,然后去 userList
  90. const data = await UserApi.getUserPage({ pageSize: 100, pageNo: 1, deptId })
  91. // 更新过滤后的用户列表
  92. filteredUserList.value = data.list
  93. } finally {
  94. formLoading.value = false
  95. }
  96. }
  97. /** 提交选择 */
  98. const submitForm = async () => {
  99. try {
  100. message.success(t('common.updateSuccess'))
  101. dialogVisible.value = false
  102. // 从所有用户列表中筛选出已选择的用户
  103. const emitUserList = userList.value.filter((user: any) =>
  104. selectedUserIdList.value.includes(user.id)
  105. )
  106. // 发送操作成功的事件
  107. emit('confirm', activityId.value, emitUserList)
  108. } finally {
  109. }
  110. }
  111. /** 重置表单 */
  112. const resetForm = () => {
  113. deptTree.value = []
  114. userList.value = []
  115. filteredUserList.value = []
  116. selectedUserIdList.value = []
  117. }
  118. /** 处理部门被点击 */
  119. const handleNodeClick = (row: { [key: string]: any }) => {
  120. getUserList(row.id)
  121. }
  122. defineExpose({ open }) // 提供 open 方法,用于打开弹窗
  123. </script>
  124. <style lang="scss" scoped>
  125. :deep() {
  126. .el-transfer {
  127. display: flex;
  128. }
  129. .el-transfer__buttons {
  130. display: flex !important;
  131. flex-direction: column-reverse;
  132. justify-content: center;
  133. gap: 20px;
  134. .el-transfer__button:nth-child(2) {
  135. margin: 0;
  136. }
  137. }
  138. }
  139. </style>