| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- <template>
- <a-drawer
- v-model:visible="props.visible"
- title="选择可见成员"
- placement="right"
- width="50%"
- :footer="null"
- @close="handleCancel"
- >
- <!-- 左侧:树状结构成员列表 -->
- <div class="left-panel">
- <a-input-search
- v-model:value="searchValue"
- placeholder="输入部门或成员名称"
- style="margin-bottom: 16px"
- @search="onSearch"
- />
- <a-tree
- v-if="treeData.length > 0"
- :tree-data="filteredTreeData"
- :field-names="{ key: 'id', title: 'name', children: 'children' }"
- :checked-keys="checkedKeys"
- :expanded-keys="expandedKeys"
- :auto-expand-parent="autoExpandParent"
- checkable
- show-icon
- @check="onCheck"
- @expand="onExpand"
- >
- <template #title="{ name, avatar }">
- <span style="display: inline-flex; align-items: center">
- <a-avatar :src="avatar" size="small" style="margin-right: 8px" />
- {{ name }}
- </span>
- </template>
- <template #switcherIcon="{ expanded }">
- <caret-down-outlined v-if="expanded" />
- <caret-right-outlined v-else />
- </template>
- </a-tree>
- </div>
- <!-- 右侧:已选择成员列表 -->
- <div class="right-panel">
- <div class="header">
- <span>已选 {{ selectedUsers.length }} / 30</span>
- <a-button type="link" @click="clearSelection">清空</a-button>
- </div>
- <a-list item-layout="horizontal" :data-source="selectedUsers">
- <template #renderItem="{ item }">
- <a-list-item>
- <a-list-item-meta>
- <template #avatar>
- <a-avatar :src="item.avatar" />
- </template>
- <template #title>
- <a>{{ item.name }}</a>
- </template>
- <template #description>
- <span>{{ item.department }}</span>
- </template>
- </a-list-item-meta>
- <template #actions>
- <a @click="removeUser(item)">删除</a>
- </template>
- </a-list-item>
- </template>
- </a-list>
- </div>
- <!-- 底部按钮 -->
- <template #footer>
- <a-space>
- <a-button @click="handleCancel">取消</a-button>
- <a-button type="primary" @click="handleOk">确定</a-button>
- </a-space>
- </template>
- </a-drawer>
- </template>
- <script setup>
- import { ref, reactive, computed, onMounted } from 'vue'
- import resourceAuditApi from '@/api/resourceAudit.js'
- import { Modal, Input, Tree, List, Avatar, Button } from 'ant-design-vue'
- const emit = defineEmits(['close', 'confirm'])
- // const visible = ref(true)
- const props = defineProps({
- visible: {
- type: Boolean,
- default: false
- },
- userRelateIds: {
- type: Array,
- default: () => {}
- }
- })
- const searchValue = ref('')
- const treeData = ref([
- {
- id: '1',
- name: '组织1',
- children: [
- {
- id: '1-1',
- name: '张小刚',
- avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
- isLeaf: true
- },
- {
- id: '1-2',
- name: '李小红',
- avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
- isLeaf: true
- }
- ]
- },
- {
- id: '2',
- name: '组织2',
- children: [
- {
- id: '2-1',
- name: '研发部',
- children: [
- {
- id: '2-1-1',
- name: '王小明',
- avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
- isLeaf: true
- }
- ]
- }
- ]
- }
- ])
- watch(
- () => props.userRelateIds,
- (newVal) => {
- if (newVal) {
- console.log(newVal, 'props.userRelateIds')
- checkedKeys.value = newVal
- // selectedUsers.value = flatTree(treeData.value)
- // .filter((node) => newVal.includes(node.id))
- // .map((node) => ({ id: node.id, name: node.name }))
- }
- },
- { deep: true }
- )
- const selectedKeys = ref([])
- const selectedUsers = ref([])
- const checkedKeys = ref([])
- const expandedKeys = ref([]) // 默认展开第一层
- const autoExpandParent = ref(true)
- const filteredTreeData = computed(() => {
- const filterFn = (node) => {
- // 保留匹配节点及其所有祖先节点
- if (node.name.includes(searchValue.value)) return true
- if (node.children) {
- const hasMatchingChild = node.children.some(filterFn)
- if (hasMatchingChild) return true
- }
- return false
- }
- return treeData.value.filter(filterFn)
- })
- // 替换原来的onSelect方法
- const onCheck = (checkedKeysValue, { checked, node, checkedNodes }) => {
- // 过滤掉非叶子节点
- const leafNodes = checkedNodes.filter((node) => node.isLeaf&& node.infoType=="user")
- checkedKeys.value = leafNodes.map((node) => node.id)
- selectedUsers.value = leafNodes.map((node) => ({
- id: node.id,
- name: node.name
- // 可选: 保留部门信息
- // department: findDepartmentName(node.id, treeData.value)
- }))
- }
- // 查找部门名称的辅助函数
- const findDepartmentName = (id, nodes) => {
- for (const node of nodes) {
- if (node.children) {
- const found = node.children.find((child) => child.id === id)
- if (found) return node.name
- const result = findDepartmentName(id, node.children)
- if (result) return result
- }
- }
- return ''
- }
- const onExpand = (keys) => {
- // console.log(keys, 'onExpand')
- expandedKeys.value = keys
- autoExpandParent.value = false
- }
- const onSearch = (value) => {
- searchValue.value = value
- }
- const augmentNode = (node) => {
- if (node.children) {
- node.isLeaf = false // 有children的节点标记为非叶子节点
- node.children.forEach((child) => augmentNode(child))
- } else {
- node.isLeaf = true // 无children的节点标记为叶子节点
- }
- }
- const getOrgUserTreeRespectively = () => {
- resourceAuditApi
- .orgUserTreeSelector()
- .then((res) => {
- if (res?.data) {
- console.log(res.data, 'getOrgUserTreeRespectively')
- res.data.forEach((root) => augmentNode(root))
- // if (treeData.value.length > 0 && treeData.value[0]?.id) {
- // expandedKeys.value = [treeData.value[0].id]
- // }
- treeData.value = res.data
- }
- })
- .catch((err) => {
- console.log(err)
- })
- }
- const clearSelection = () => {
- selectedKeys.value = []
- selectedUsers.value = []
- checkedKeys.value = []
- }
- const removeUser = (user) => {
- const index = selectedUsers.value.findIndex((u) => u.id === user.id)
- if (index !== -1) {
- selectedUsers.value.splice(index, 1)
- selectedKeys.value = selectedUsers.value.map((u) => u.id)
- checkedKeys.value = selectedUsers.value.map((u) => u.id)
- }
- // selectedUsers.value = selectedUsers.value.filter((u) => u.id !== user.id)
- // checkedKeys.value = selectedUsers.value.map((u) => u.id)
- }
- const showModal = () => {
- visible.value = true
- }
- const handleOk = () => {
- console.log('Selected Users:', selectedUsers.value, checkedKeys.value)
- emit('confirm', checkedKeys.value)
- }
- const handleCancel = () => {
- emit('close')
- }
- onMounted(() => {
- getOrgUserTreeRespectively()
- // if (props.userRelateIds) {
- // checkedKeys.value = props.userRelateIds // 直接赋值给树组件的checkedKeys
- // }
- })
- </script>
- <style scoped>
- .left-panel,
- .right-panel {
- display: inline-block;
- vertical-align: top;
- width: 48%;
- height: calc(100vh - 200px);
- overflow-y: auto;
- padding: 0 10px;
- }
- .right-panel {
- border-left: 1px solid #f0f0f0;
- }
- .header {
- display: flex;
- justify-content: space-between;
- margin-bottom: 16px;
- }
- .ant-tree-switcher {
- width: 24px;
- height: 24px;
- line-height: 24px;
- }
- .ant-tree-switcher-icon {
- font-size: 12px;
- transition: transform 0.3s;
- }
- .ant-tree-switcher_close .ant-tree-switcher-icon {
- transform: rotate(-90deg);
- }
- </style>
|