index.vue 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. <template>
  2. <Dialog v-model="dialogVisible" title="部门选择" width="600">
  3. <el-row v-loading="formLoading">
  4. <el-col :span="24">
  5. <ContentWrap class="h-1/1">
  6. <el-tree
  7. ref="treeRef"
  8. :data="deptTree"
  9. :props="defaultProps"
  10. show-checkbox
  11. :check-strictly="checkStrictly"
  12. check-on-click-node
  13. default-expand-all
  14. highlight-current
  15. node-key="id"
  16. @check="handleCheck"
  17. />
  18. </ContentWrap>
  19. </el-col>
  20. </el-row>
  21. <template #footer>
  22. <el-button
  23. :disabled="formLoading || !selectedDeptIds?.length"
  24. type="primary"
  25. @click="submitForm"
  26. >
  27. 确 定
  28. </el-button>
  29. <el-button @click="dialogVisible = false">取 消</el-button>
  30. </template>
  31. </Dialog>
  32. </template>
  33. <script lang="ts" setup>
  34. import { defaultProps, handleTree } from '@/utils/tree'
  35. import * as DeptApi from '@/api/system/dept'
  36. defineOptions({ name: 'DeptSelectForm' })
  37. const emit = defineEmits<{
  38. confirm: [deptList: any[]]
  39. }>()
  40. const { t } = useI18n() // 国际化
  41. const message = useMessage() // 消息弹窗
  42. const props = defineProps({
  43. // 是否严格的遵循父子不互相关联
  44. checkStrictly: {
  45. type: Boolean,
  46. default: false
  47. },
  48. // 是否支持多选
  49. multiple: {
  50. type: Boolean,
  51. default: true
  52. }
  53. })
  54. const treeRef = ref()
  55. const deptTree = ref<Tree[]>([]) // 部门树形结构
  56. const selectedDeptIds = ref<number[]>([]) // 选中的部门 ID 列表
  57. const dialogVisible = ref(false) // 弹窗的是否展示
  58. const formLoading = ref(false) // 表单的加载中
  59. /** 打开弹窗 */
  60. const open = async (selectedList?: DeptApi.DeptVO[]) => {
  61. resetForm()
  62. formLoading.value = true
  63. try {
  64. // 加载部门列表
  65. const deptData = await DeptApi.getSimpleDeptList()
  66. deptTree.value = handleTree(deptData)
  67. } finally {
  68. formLoading.value = false
  69. }
  70. dialogVisible.value = true
  71. // 设置已选择的部门
  72. if (selectedList?.length) {
  73. await nextTick()
  74. const selectedIds = selectedList
  75. .map((dept) => dept.id)
  76. .filter((id): id is number => id !== undefined)
  77. selectedDeptIds.value = selectedIds
  78. treeRef.value?.setCheckedKeys(selectedIds)
  79. }
  80. }
  81. /** 处理选中状态变化 */
  82. const handleCheck = (data: any, checked: any) => {
  83. selectedDeptIds.value = treeRef.value.getCheckedKeys()
  84. if (!props.multiple && selectedDeptIds.value.length > 1) {
  85. // 单选模式下,只保留最后选择的节点
  86. const lastSelectedId = selectedDeptIds.value[selectedDeptIds.value.length - 1]
  87. selectedDeptIds.value = [lastSelectedId]
  88. treeRef.value.setCheckedKeys([lastSelectedId])
  89. }
  90. }
  91. /** 提交选择 */
  92. const submitForm = async () => {
  93. try {
  94. // 获取选中的完整部门数据
  95. const checkedNodes = treeRef.value.getCheckedNodes()
  96. message.success(t('common.updateSuccess'))
  97. dialogVisible.value = false
  98. emit('confirm', checkedNodes)
  99. } finally {
  100. }
  101. }
  102. /** 重置表单 */
  103. const resetForm = () => {
  104. deptTree.value = []
  105. selectedDeptIds.value = []
  106. if (treeRef.value) {
  107. treeRef.value.setCheckedKeys([])
  108. }
  109. }
  110. defineExpose({ open }) // 提供 open 方法,用于打开弹窗
  111. </script>