Skip to content

Commit

Permalink
fix: 修复用户选择器bug
Browse files Browse the repository at this point in the history
  • Loading branch information
MoChou committed Nov 8, 2024
1 parent 5ade6bc commit 233bd62
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 54 deletions.
105 changes: 70 additions & 35 deletions src/components/UserSelect/component/UserSelectContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
:columns="tableColumns"
:loading="loading"
:scroll="{ x: '100%', y: '100%', minWidth: 1000 }"
style="max-height: 600px"
:pagination="pagination"
:disabled-tools="['size', 'fullscreen', 'setting', 'refresh']"
:row-selection="{ type: props.multiple ? 'checkbox' : 'radio', showCheckedAll: true }"
Expand All @@ -30,7 +31,9 @@
@change="search"
/>
<a-button @click="reset">
<template #icon><icon-refresh /></template>
<template #icon>
<icon-refresh />
</template>
<template #default>重置</template>
</a-button>
</a-space>
Expand Down Expand Up @@ -59,7 +62,7 @@

<a-col :span="24" :md="6" class="section">
<a-card title="已选用户">
<a-table :columns="rightColumn" :data="selectedData">
<a-table :columns="rightColumn" :data="selectedData" :pagination="paginationOptions">
<template #nickname="{ record }">
{{ record.nickname }}({{ record.username }})
</template>
Expand All @@ -78,9 +81,9 @@
<script setup lang="ts">
import type { TreeNodeData } from '@arco-design/web-vue'
import { useDept } from '@/hooks/app'
import { useTable } from '@/hooks'
import { type UserQuery, listAllUser, listUser } from '@/apis'
import type { UserItem, UserSelectPropType } from '@/components/UserSelect/type'
import { type Options, useTable } from '@/hooks'
import { type UserQuery, type UserResp, listAllUser, listUser } from '@/apis'
import type { UserSelectPropType } from '@/components/UserSelect/type'
import type { TableInstanceColumns } from '@/components/GiTable/type'
import { isMobile } from '@/utils'
Expand Down Expand Up @@ -127,6 +130,11 @@ const rightColumn = [
const queryForm = reactive<UserQuery>({
sort: ['t1.createTime,desc'],
})
// 定义分页器参数
const paginationOptions: Options = {
defaultPageSize: 10,
defaultSizeOptions: [10, 20, 30, 40, 50],
}
// 用户列表
const { tableData: dataList, loading, pagination, search } = useTable(
Expand Down Expand Up @@ -157,65 +165,92 @@ const filterDeptOptions = (searchKey: string, nodeData: TreeNodeData) => {
return false
}
const selectedKeys = ref<string[]>([])
const selectedData = ref<any[]>([])
const allUsers = ref<UserResp[]>() // 用于存储所有用户信息
const selectedKeys = ref<string[]>([]) // 使用 Array 来存储选中的 id
const selectedData = ref<Set<UserResp>>(new Set()) // 使用 Set 来存储选中的用户对象
const emitSelectedUsers = () => {
emit('update:selectedUsers', selectedKeys.value)
}
// 行选择事件
const onRowSelect = (rowKeys: string[], rowKey: string, record: UserItem) => {
selectedData.value = props.multiple
? rowKeys.includes(rowKey)
? [...selectedData.value, record]
: selectedData.value.filter((item) => item.id !== rowKey)
: [record]
selectedKeys.value = selectedData.value.map((item) => item.id)
const onRowSelect = (rowKeys: string[], rowKey: string, record: UserResp) => {
if (props.multiple) {
// 多选
if (rowKeys.includes(rowKey)) {
// 包含 选中
selectedData.value.add(record)
selectedKeys.value?.push(rowKey)
} else {
// 不包含 去除
selectedData.value.delete(record)
selectedKeys.value?.splice(selectedKeys.value?.indexOf(rowKey), 1)
}
} else {
// 单选
selectedData.value.clear()
selectedKeys.value = []
if (rowKeys.includes(rowKey)) {
// 包含 选中
selectedData.value.add(record)
selectedKeys.value?.push(rowKey)
}
}
emitSelectedUsers()
}
// 全选事件
const onTableSelectAll = (checked: boolean) => {
selectedData.value = checked
? [...selectedData.value, ...dataList.value.filter((item) => !selectedKeys.value.includes(item.id))]
: []
selectedKeys.value = selectedData.value.map((item) => item.id)
if (checked) {
// 选中
dataList.value.forEach((item) => {
selectedData.value.add(item)
selectedKeys.value?.push(item.id)
})
} else {
// 取消选中
dataList.value.forEach((item) => {
selectedData.value.delete(item)
selectedKeys.value?.splice(selectedKeys.value?.indexOf(item.id), 1)
})
}
emitSelectedUsers()
}
// 从选中列表中移除用户
const handleDeleteSelectUser = (user: UserItem) => {
selectedData.value = selectedData.value.filter((item) => item.id !== user.id)
selectedKeys.value = selectedData.value.map((item) => item.id)
const handleDeleteSelectUser = (user: UserResp) => {
selectedData.value.delete(user)
selectedKeys.value?.splice(selectedKeys.value?.indexOf(user.id), 1)
emitSelectedUsers()
}
// 清空所有选中数据
const onClearSelected = () => {
selectedData.value = []
selectedData.value.clear()
selectedKeys.value = []
emitSelectedUsers()
}
// 初始化函数
const init = (selectUsers: string[]) => {
const init = async (selectUsers: string[]) => {
getDeptList()
search()
// 获取所有用户数据
const { data } = await listAllUser({})
allUsers.value = data
// 过滤已选择的用户
if (selectUsers && selectUsers.length > 0) {
// admin的id是number 不是string 类型 所以处理一下
listAllUser({ userIds: selectUsers }).then((dataList) => {
selectedData.value = dataList.data.map((data) => {
return { ...data, id: data.id }
})
})
if (props.multiple) {
selectedData.value = new Set(allUsers.value.filter((item) => selectUsers.includes(item.id)))
selectedKeys.value = Array.from(selectedData.value).map((user) => user.id)
} else {
selectedData.value = new Set(allUsers.value.filter((item) => selectUsers[0] === item.id))
selectedKeys.value = Array.from(selectedData.value).map((user) => user.id)
}
}
}
watch(() => props.selectedUsers, (newValue) => {
const newSelectedKeys = Array.isArray(newValue) ? newValue : [newValue]
selectedKeys.value = newSelectedKeys.filter(Boolean)
selectedData.value = dataList.value.filter((item) => selectedKeys.value.includes(item.id))
}, { immediate: true })
defineExpose({ init, onClearSelected })
</script>

Expand Down
30 changes: 12 additions & 18 deletions src/components/UserSelect/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,19 @@ import { useWindowSize } from '@vueuse/core'
import UserSelectContent from './component/UserSelectContent.vue'
import { listUserDict } from '@/apis'
import type { UserSelectPropType } from '@/components/UserSelect/type'
import type { LabelValueState } from '@/types/global'
const props = withDefaults(defineProps<UserSelectPropType>(), {
multiple: false, // 是否支持多选
value: '',
value: [], // 单选时默认值为空数组
})
const emit = defineEmits(['update:value'])
const { width } = useWindowSize() // 获取窗口的宽度,用于设置弹窗宽度
const visible = ref<boolean>(false) // 控制弹窗显示的状态
const userList = ref([]) // 保存用户选项列表
const userList = ref<LabelValueState[]>([]) // 保存用户选项列表
const userSelectContentRef = ref() // 引用 UserSelectContent 组件实例
const selectedUsers = ref([]) // 保存已选择的用户
const selectedUsers = ref<string[]>([]) // 保存已选择的用户
// 打开用户选择弹窗
const onOpen = () => {
visible.value = true
Expand All @@ -66,7 +66,13 @@ const emitDataChange = () => {
// 处理用户选择变更事件
const handleSelectChange = (value: any) => {
selectedUsers.value = props.multiple ? value : [...value]
if (props.multiple) {
// 多选模式下,selectedUsers 应该是一个数组
selectedUsers.value = value
} else {
// 单选模式下,selectedUsers 只应保存一个值
selectedUsers.value = value ? [value] : []
}
emitDataChange() // 每次选择变化时发出更新事件
}
Expand All @@ -90,15 +96,3 @@ onMounted(async () => {
selectedUsers.value = Array.isArray(props.value) ? props.value : props.value?.split(',')
})
</script>

<style scoped>
:deep(.arco-input-append) {
padding: 0;
.arco-btn {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border: 1px solid transparent;
}
}
</style>
2 changes: 1 addition & 1 deletion src/components/UserSelect/type.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export interface UserSelectPropType {
multiple: boolean
value?: string[]
value: string[] | string
}

export interface UserItem {
Expand Down

0 comments on commit 233bd62

Please sign in to comment.