Skip to content

Commit 5ade6bc

Browse files
committed
refactor: 优化通知公告用户选择部分代码
1 parent 4cd4e51 commit 5ade6bc

File tree

5 files changed

+105
-107
lines changed

5 files changed

+105
-107
lines changed

src/apis/common/common.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ export function listMenuTree(query: { description: string }) {
1818
return http.get<TreeNodeData[]>(`${BASE_URL}/tree/menu`, query)
1919
}
2020

21+
/** @desc 查询用户列表 */
22+
export function listUserDict(query?: { status: number }) {
23+
return http.get<LabelValueState[]>(`${BASE_URL}/dict/user`, query)
24+
}
25+
2126
/** @desc 查询角色列表 */
2227
export function listRoleDict(query?: { name: string, status: number }) {
2328
return http.get<LabelValueState[]>(`${BASE_URL}/dict/role`, query)

src/apis/system/user.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ const BASE_URL = '/system/user'
99
export function listUser(query: T.UserPageQuery) {
1010
return http.get<PageRes<T.UserResp[]>>(`${BASE_URL}`, query)
1111
}
12+
13+
/** @desc 查询所有用户列表 */
1214
export function listAllUser(query: Partial<T.UserPageQuery>) {
1315
return http.get<T.UserResp[]>(`${BASE_URL}/list`, query)
1416
}

src/components/UserSelect/component/UserSelectContent.vue

Lines changed: 86 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,14 @@
11
<template>
22
<div class="container">
33
<a-row :gutter="16">
4-
<a-col :span="24" :md="5" class="section">
5-
<a-input v-model="searchKey" placeholder="请输入部门名称" allow-clear>
6-
<template #prefix>
7-
<icon-search />
8-
</template>
9-
</a-input>
10-
<a-tree
11-
ref="treeRef"
12-
:data="treeData"
13-
block-node
14-
@select="handleDeptSelect"
15-
/>
16-
</a-col>
17-
18-
<a-col :span="24" :md="14" class="section">
4+
<a-col :span="24" :md="18" class="section">
195
<GiTable
206
v-model:selectedKeys="selectedKeys"
21-
style="min-height: 600px;"
227
row-key="id"
238
:data="dataList"
249
:columns="tableColumns"
2510
:loading="loading"
26-
:scroll="{ x: '100%', y: '100%' }"
11+
:scroll="{ x: '100%', y: '100%', minWidth: 1000 }"
2712
:pagination="pagination"
2813
:disabled-tools="['size', 'fullscreen', 'setting', 'refresh']"
2914
:row-selection="{ type: props.multiple ? 'checkbox' : 'radio', showCheckedAll: true }"
@@ -34,16 +19,19 @@
3419
<template #top>
3520
<div>
3621
<a-space class="mt-5">
37-
<a-input v-model="queryForm.description" placeholder="用户名/昵称/描述" />
38-
<a-button @click="search">
39-
<template #icon>
40-
<icon-search />
41-
</template>
42-
</a-button>
43-
<a-button @click="onRefresh">
44-
<template #icon>
45-
<icon-refresh />
46-
</template>
22+
<a-input v-model="queryForm.description" placeholder="用户名/昵称/描述" allow-clear @change="search" />
23+
<a-tree-select
24+
v-model="queryForm.deptId"
25+
:data="deptList"
26+
placeholder="请选择所属部门"
27+
allow-clear
28+
allow-search
29+
:filter-tree-node="filterDeptOptions"
30+
@change="search"
31+
/>
32+
<a-button @click="reset">
33+
<template #icon><icon-refresh /></template>
34+
<template #default>重置</template>
4735
</a-button>
4836
</a-space>
4937
</div>
@@ -52,7 +40,7 @@
5240
已选中{{ selectedKeys.length }}条记录(可跨页)
5341
</template>
5442
<template v-else>
55-
未选中任何项目
43+
未选中任何用户
5644
</template>
5745
<template v-if="selectedKeys.length > 0" #action>
5846
<a-link @click="onClearSelected">清空</a-link>
@@ -63,12 +51,18 @@
6351
<template #status="{ record }">
6452
<GiCellStatus :status="record.status" />
6553
</template>
54+
<template #gender="{ record }">
55+
<GiCellGender :gender="record.gender" />
56+
</template>
6657
</GiTable>
6758
</a-col>
6859

69-
<a-col :span="24" :md="5" class="section">
60+
<a-col :span="24" :md="6" class="section">
7061
<a-card title="已选用户">
7162
<a-table :columns="rightColumn" :data="selectedData">
63+
<template #nickname="{ record }">
64+
{{ record.nickname }}({{ record.username }})
65+
</template>
7266
<template #action="{ record }">
7367
<a-button @click="handleDeleteSelectUser(record)">
7468
<icon-delete />
@@ -85,8 +79,10 @@
8579
import type { TreeNodeData } from '@arco-design/web-vue'
8680
import { useDept } from '@/hooks/app'
8781
import { useTable } from '@/hooks'
88-
import { listAllUser, listUser } from '@/apis'
82+
import { type UserQuery, listAllUser, listUser } from '@/apis'
8983
import type { UserItem, UserSelectPropType } from '@/components/UserSelect/type'
84+
import type { TableInstanceColumns } from '@/components/GiTable/type'
85+
import { isMobile } from '@/utils'
9086
9187
const props = withDefaults(defineProps<UserSelectPropType & { selectedUsers: string | string[] }>(), {
9288
multiple: false,
@@ -95,95 +91,88 @@ const props = withDefaults(defineProps<UserSelectPropType & { selectedUsers: str
9591
9692
const emit = defineEmits(['update:selectedUsers'])
9793
98-
// 查询表单引用
99-
const queryForm = ref({ description: '' })
94+
// 表格列定义
95+
const tableColumns: TableInstanceColumns[] = [
96+
{
97+
title: '昵称',
98+
dataIndex: 'nickname',
99+
slotName: 'nickname',
100+
minWidth: 140,
101+
ellipsis: true,
102+
tooltip: true,
103+
fixed: !isMobile() ? 'left' : undefined,
104+
},
105+
{ title: '用户名', dataIndex: 'username', slotName: 'username', minWidth: 140, ellipsis: true, tooltip: true },
106+
{ title: '状态', slotName: 'status', align: 'center' },
107+
{ title: '性别', dataIndex: 'gender', slotName: 'gender', align: 'center' },
108+
{ title: '所属部门', dataIndex: 'deptName', ellipsis: true, tooltip: true, minWidth: 180 },
109+
{ title: '角色', dataIndex: 'roleNames', minWidth: 160, slotName: 'roleNames' },
110+
{ title: '手机号', dataIndex: 'phone', minWidth: 170, ellipsis: true, tooltip: true },
111+
{ title: '邮箱', dataIndex: 'email', minWidth: 170, ellipsis: true, tooltip: true },
112+
{ title: '系统内置', slotName: 'isSystem', width: 100, align: 'center', show: false },
113+
{ title: '描述', dataIndex: 'description', minWidth: 130, ellipsis: true, tooltip: true },
114+
{ title: '创建人', dataIndex: 'createUserString', width: 140, ellipsis: true, tooltip: true, show: false },
115+
{ title: '创建时间', dataIndex: 'createTime', width: 180 },
116+
{ title: '修改人', dataIndex: 'updateUserString', width: 140, ellipsis: true, tooltip: true, show: false },
117+
{ title: '修改时间', dataIndex: 'updateTime', width: 180, show: false },
118+
]
100119
101-
// 部门树引用
102-
const treeRef = ref()
103-
const selectedKeys = ref<string[]>([])
104-
const selectedDeptId = ref<string>('')
105-
const selectedData = ref<any[]>([])
120+
// 右侧已选用户列定义
121+
const rightColumn = [
122+
{ title: '用户', dataIndex: 'nickname', slotName: 'nickname', minWidth: 140, ellipsis: true, tooltip: true },
123+
{ title: '操作', dataIndex: 'action', slotName: 'action' },
124+
]
106125
126+
// 查询表单
127+
const queryForm = reactive<UserQuery>({
128+
sort: ['t1.createTime,desc'],
129+
})
130+
131+
// 用户列表
107132
const { tableData: dataList, loading, pagination, search } = useTable(
108-
(page) => listUser({ ...queryForm.value, deptId: selectedDeptId.value, sort: [], ...page }),
133+
(page) => listUser({ ...queryForm, ...page }),
109134
{ immediate: false, formatResult: (data) => data.map((i) => ({ ...i, disabled: false })) },
110135
)
111136
112-
// 刷新表单
113-
const onRefresh = () => {
114-
queryForm.value.description = ''
137+
// 重置
138+
const reset = () => {
139+
queryForm.description = undefined
140+
queryForm.deptId = undefined
115141
search()
116142
}
117143
118-
// 使用 useDept 钩子获取部门列表数据
144+
const treeRef = ref()
145+
// 部门列表
119146
const { deptList, getDeptList } = useDept({
120147
onSuccess: () => {
121148
nextTick(() => treeRef.value?.expandAll(true))
122149
},
123150
})
124151
125-
// 部门树过滤函数
126-
const deptTreeSearch = (keyword: string, data: TreeNodeData[]): TreeNodeData[] => {
127-
return data
128-
.map((item) => ({
129-
...item,
130-
children: item.children ? deptTreeSearch(keyword, item.children) : [],
131-
}))
132-
.filter(
133-
(item) =>
134-
item.title?.toLowerCase().includes(keyword.toLowerCase()) || item.children?.length,
135-
)
136-
}
137-
138-
// 过滤树数据
139-
const searchKey = ref('')
140-
const treeData = computed(() => {
141-
return searchKey.value ? deptTreeSearch(searchKey.value, deptList.value) : deptList.value
142-
})
143-
144-
// 表格列定义
145-
const tableColumns = [
146-
{ title: '昵称', dataIndex: 'nickname' },
147-
{ title: '部门', dataIndex: 'deptName' },
148-
{ title: '角色', dataIndex: 'roleNames' },
149-
{ title: '手机号', dataIndex: 'phone' },
150-
{ title: '邮箱', dataIndex: 'email' },
151-
{ title: '状态', dataIndex: 'status', slotName: 'status' },
152-
]
153-
154-
// 右侧已选用户列定义
155-
const rightColumn = [
156-
{ title: '昵称', dataIndex: 'nickname' },
157-
{ title: '操作', dataIndex: 'action', slotName: 'action' },
158-
]
159-
160-
// 处理部门选择
161-
const handleDeptSelect = (keys: Array<any>) => {
162-
selectedDeptId.value = keys[0] || ''
163-
search()
152+
// 过滤部门
153+
const filterDeptOptions = (searchKey: string, nodeData: TreeNodeData) => {
154+
if (nodeData.title) {
155+
return nodeData.title.toLowerCase().includes(searchKey.toLowerCase())
156+
}
157+
return false
164158
}
165159
160+
const selectedKeys = ref<string[]>([])
161+
const selectedData = ref<any[]>([])
166162
const emitSelectedUsers = () => {
167163
emit('update:selectedUsers', selectedKeys.value)
168164
}
169-
// 从选中列表中移除用户
170-
const handleDeleteSelectUser = (user: UserItem) => {
171-
selectedData.value = selectedData.value.filter((item) => item.id !== user.id)
172-
selectedKeys.value = selectedData.value.map((item) => item.id)
173-
emitSelectedUsers()
174-
}
175-
176165
// 行选择事件
177166
const onRowSelect = (rowKeys: string[], rowKey: string, record: UserItem) => {
178167
selectedData.value = props.multiple
179168
? rowKeys.includes(rowKey)
180169
? [...selectedData.value, record]
181170
: selectedData.value.filter((item) => item.id !== rowKey)
182171
: [record]
183-
184172
selectedKeys.value = selectedData.value.map((item) => item.id)
185173
emitSelectedUsers()
186174
}
175+
187176
// 全选事件
188177
const onTableSelectAll = (checked: boolean) => {
189178
selectedData.value = checked
@@ -193,6 +182,13 @@ const onTableSelectAll = (checked: boolean) => {
193182
emitSelectedUsers()
194183
}
195184
185+
// 从选中列表中移除用户
186+
const handleDeleteSelectUser = (user: UserItem) => {
187+
selectedData.value = selectedData.value.filter((item) => item.id !== user.id)
188+
selectedKeys.value = selectedData.value.map((item) => item.id)
189+
emitSelectedUsers()
190+
}
191+
196192
// 清空所有选中数据
197193
const onClearSelected = () => {
198194
selectedData.value = []
@@ -208,7 +204,7 @@ const init = (selectUsers: string[]) => {
208204
// admin的id是number 不是string 类型 所以处理一下
209205
listAllUser({ userIds: selectUsers }).then((dataList) => {
210206
selectedData.value = dataList.data.map((data) => {
211-
return { ...data, id: `${data.id}` }
207+
return { ...data, id: data.id }
212208
})
213209
})
214210
}

src/components/UserSelect/index.vue

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33
<div style="display: flex;">
44
<a-select
55
v-model="selectedUsers"
6-
:allow-clear="true"
7-
:multiple="props.multiple"
6+
:options="userList"
87
:max-tag-count="4"
9-
:field-names="{ value: 'id', label: 'nickname' }"
10-
:options="options"
8+
:multiple="props.multiple"
9+
:allow-clear="true"
1110
@change="handleSelectChange"
1211
/>
1312
<a-tooltip content="选择用户">
@@ -39,7 +38,7 @@
3938
<script setup lang="ts">
4039
import { useWindowSize } from '@vueuse/core'
4140
import UserSelectContent from './component/UserSelectContent.vue'
42-
import { type UserResp, listAllUser } from '@/apis'
41+
import { listUserDict } from '@/apis'
4342
import type { UserSelectPropType } from '@/components/UserSelect/type'
4443
4544
const props = withDefaults(defineProps<UserSelectPropType>(), {
@@ -49,11 +48,11 @@ const props = withDefaults(defineProps<UserSelectPropType>(), {
4948
5049
const emit = defineEmits(['update:value'])
5150
52-
const visible = ref<boolean>(false) // 控制弹窗显示的状态
5351
const { width } = useWindowSize() // 获取窗口的宽度,用于设置弹窗宽度
54-
const options = ref<UserResp[]>([]) // 保存用户选项列表
52+
const visible = ref<boolean>(false) // 控制弹窗显示的状态
53+
const userList = ref([]) // 保存用户选项列表
5554
const userSelectContentRef = ref() // 引用 UserSelectContent 组件实例
56-
const selectedUsers = ref<string[]>([]) // 保存已选择的用户
55+
const selectedUsers = ref([]) // 保存已选择的用户
5756
// 打开用户选择弹窗
5857
const onOpen = () => {
5958
visible.value = true
@@ -85,15 +84,10 @@ const handleModalOk = () => {
8584
8685
// 组件挂载后初始化用户列表
8786
onMounted(async () => {
88-
const { data } = await listAllUser({}) // 获取所有用户
89-
options.value = data.map((user) => {
90-
user.id = String(user.id)
91-
user.disabled = false // 初始化时设置用户未被禁用
92-
return user
93-
})
94-
87+
const { data } = await listUserDict() // 获取所有用户
88+
userList.value = data
9589
// 初始化选择的用户
96-
selectedUsers.value = Array.isArray(props.value) ? props.value : props.value.split(',')
90+
selectedUsers.value = Array.isArray(props.value) ? props.value : props.value?.split(',')
9791
})
9892
</script>
9993

src/components/UserSelect/type.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
export interface UserSelectPropType {
22
multiple: boolean
3-
value: string | string[]
3+
value?: string[]
44
}
5+
56
export interface UserItem {
67
id: string
78
nickname: string

0 commit comments

Comments
 (0)