refactor(notification): 优化消息编辑页面用户选择功能

- 移除部门树的搜索框
- 默认展开部门树的所有节点
- 使用 InputTag 组件显示已选用户
- 限制显示的用户数量为 5 个
- 优化用户选择的逻辑,支持全选和单选
-重构代码,提高可维护性和可读性
This commit is contained in:
Kven 2025-02-10 23:58:45 +08:00
parent a9e39fd950
commit f5f436e90e
2 changed files with 44 additions and 122 deletions

View File

@ -33,9 +33,10 @@
]" ]"
> >
<a-input-tag <a-input-tag
v-model="formData.userIds" v-model="selectedNames"
placeholder='请选择用戶' placeholder='请选择用戶'
:value=formData.userIds :max-tag-count="5"
readonly
@click="queryDeptTree" @click="queryDeptTree"
/> />
</a-form-item> </a-form-item>
@ -143,27 +144,26 @@
@cancel="deptTreeCancel" @cancel="deptTreeCancel"
> >
<template #title>发送用户</template> <template #title>发送用户</template>
<div style="display: flex;height: 520px"> <div style="display: flex;">
<a-card style="margin-right: 10px;width: 30%"> <a-card style="margin-right: 10px;width: 30%">
<a-tree <a-tree
:data="deptTreeData" :data="deptTreeData"
:field-names="{ title: 'name', key: 'id', children: 'children' }" :field-names="{ title: 'name', key: 'id', children: 'children' }"
style="margin-bottom: 8px; max-width: 240px" style="margin-bottom: 8px; max-width: 240px"
@select="handleClickTree" @select="handleClickTree"
@check="handleCheckTree"
> >
</a-tree> </a-tree>
</a-card> </a-card>
<a-card style="flex: 1"> <a-card style="flex: 1">
<a-button type="primary" style="margin-bottom: 10px" @click="handleCheckAllUsers">全选</a-button> <a-button type="primary" style="margin-bottom: 10px" @click="handleCheckAllUsers">全选</a-button>
<a-table <a-table
:data="selectedDepartmentMembers" :data="renderData"
:columns="columns" :columns="columns"
style="height: 520px"> >
<template #id="{ record }"> <template #id="{ record }">
<a-checkbox v-model="selectedIds" :value="record.userId"> </a-checkbox> <a-checkbox v-model="selectedIds" :value="record.id"> </a-checkbox>
</template> </template>
<template #username="{ record }"> <template #name="{ record }">
{{ record.username }} {{ record.username }}
</template> </template>
</a-table> </a-table>
@ -183,7 +183,7 @@
import { CreateRecord } from '@/api/user'; import { CreateRecord } from '@/api/user';
import { FormInstance } from '@arco-design/web-vue/es/form'; import { FormInstance } from '@arco-design/web-vue/es/form';
import { Message } from '@arco-design/web-vue'; import { Message } from '@arco-design/web-vue';
import { useMessageStore } from '@/store'; import { useMessageStore, useUserStore } from '@/store';
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'; import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
import { IEditorConfig } from '@wangeditor/editor' import { IEditorConfig } from '@wangeditor/editor'
import '@wangeditor/editor/dist/css/style.css' import '@wangeditor/editor/dist/css/style.css'
@ -196,6 +196,7 @@
isCreate: Boolean, isCreate: Boolean,
}); });
// //
const userStore = useUserStore();
const deptVisible=ref(false); const deptVisible=ref(false);
const emit = defineEmits(['refresh']); const emit = defineEmits(['refresh']);
const modalTitle = computed(() => { const modalTitle = computed(() => {
@ -217,6 +218,8 @@
const isFullScreen = ref(false); const isFullScreen = ref(false);
const mode = 'default'; const mode = 'default';
const selectedIds= ref<number[]>([]); const selectedIds= ref<number[]>([]);
const selectedNames= ref<string[]>([]);
const toolbarConfig = { excludeKeys: ['uploadVideo', 'insertImage','insertVideo']} const toolbarConfig = { excludeKeys: ['uploadVideo', 'insertImage','insertVideo']}
const columns = computed<any[]>(()=>[ const columns = computed<any[]>(()=>[
{ {
@ -230,45 +233,6 @@
}, },
]) ])
// const fieIds = ref(
// {
// userId:{
// label: '',
// component: 'input',
// type:'text'
// },
// title:{
// label: '',
// component: 'input',
// type:'text'
// },
// remark:{
// label: '',
// component: 'input',
// type:'text'
// },
// sms:{
// label: '',
// component: 'switch',
// type:'switch'
// },
// email:{
// label: '',
// component:'switch',
// type:'switch'
// },
// attachmentIds:{
// label: '',
// component: 'input',
// type:'text'
// },
// richEditor:{
// label: '',
// component: 'input',
// type:'text'
// },
// },
// );
const deptTreeData = ref([ const deptTreeData = ref([
{ {
id: '1', id: '1',
@ -301,7 +265,6 @@
] ]
} }
]); ]);
const selectedDepartmentMembers: any = ref([]);
const renderData = ref<any[]>([]); const renderData = ref<any[]>([]);
const messageType = computed(() => [ const messageType = computed(() => [
{ {
@ -314,8 +277,8 @@
}, },
]); ]);
// //
const getDeptTree = async () => { const getDeptTree = async (deptId: number) => {
const res = await getAllDeptTree(1); const res = await getAllDeptTree(deptId || 0);
if (res.status === 200) { if (res.status === 200) {
deptTreeData.value = res.data; deptTreeData.value = res.data;
} }
@ -325,76 +288,26 @@
deptVisible.value = true; deptVisible.value = true;
} }
// 广 //
const getSelectedMembers = (treeData: any[], selectedKeys: number[]) => { const fetchData = async (deptId: number) => {
const queue:any = [...treeData]; try {
const selectedMembers: any[] = []; const res = await userStore.getUserList({
while (queue.length > 0) { deptId,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion });
const node = queue.shift()!; renderData.value = res.data.records;
if (selectedKeys.includes(node.id)) { console.log(renderData);
if (node.members) { } catch (err) {
selectedMembers.push(...node.members); // you can report use errorHandler or other
}
}
if (node.children) {
queue.push(...node.children);
}
} }
return selectedMembers; };
}
// //
const handleClickTree = (id: number[]) => { const handleClickTree = (id: number[]) => {
// '1' const [deptId] = id;
if (id[0] === 1 && id.length === 1) { fetchData(deptId);
// 广
const allMembers: any[] = [];
const queue:any = [...deptTreeData.value];
while (queue.length > 0) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const node = queue.shift()!;
if (node.members) {
allMembers.push(...node.members);
}
if (node.children) {
queue.push(...node.children);
}
}
selectedDepartmentMembers.value = allMembers;
renderData.value = selectedDepartmentMembers.value;
return;
}
const Members = getSelectedMembers(deptTreeData.value, id);
selectedDepartmentMembers.value = Members;
} }
//
const handleCheckTree = (id: number[]) => {
if (id[0] === 1 ) { // '1'
const allKeys: number[] = [];
const traverseTree = (node: any) => {
if (node.members) {
node.members.forEach((member: any) => {
allKeys.push(member.userId);
});
}
if (node.children) {
node.children.forEach((child: any) => {
traverseTree(child);
});
}
};
deptTreeData.value.forEach((node: any) => {
traverseTree(node);
});
selectedIds.value = allKeys;
} else {
const selectedKeys = getSelectedMembers(deptTreeData.value, id);
selectedIds.value = selectedKeys.map(item => item.userId);
}
};
// //
const handleClick = () => { const handleClick = () => {
@ -446,18 +359,26 @@
setVisible(false); setVisible(false);
}; };
const getNamesByIds = (ids: number[]) => {
return ids.map(id => renderData.value.find(dept => dept.id === id)?.username).filter(username => username !== undefined) as string[];
};
// //
const deptTreeSubmit = () => { const deptTreeSubmit = () => {
deptVisible.value = false; deptVisible.value = false;
formData.value.userIds = selectedIds.value; formData.value.userIds = selectedIds.value;
selectedNames.value = getNamesByIds(selectedIds.value);
console.log(selectedNames.value);
}; };
// //
const handleCheckAllUsers = () => { const handleCheckAllUsers = () => {
if(selectedIds.value.length ===0 ) { if(selectedIds.value.length ===0 ) {
handleCheckTree([1]); // renderData id
selectedIds.value = renderData.value.map(user => user.id);
} else { } else {
selectedIds.value = []; selectedIds.value = [];
} }
}; };
@ -468,7 +389,7 @@
deptVisible.value = false; deptVisible.value = false;
}; };
onMounted(async () => { onMounted(async () => {
await getDeptTree(); await getDeptTree(0);
}); });
</script> </script>

View File

@ -1,11 +1,12 @@
<template> <template>
<a-input-search <!-- <a-input-search-->
v-model="searchKey" <!-- v-model="searchKey"-->
placeholder="搜索" <!-- placeholder="搜索"-->
style="margin-bottom: 8px; max-width: 240px" <!-- style="margin-bottom: 8px; max-width: 240px"-->
/> <!-- />-->
<a-tree <a-tree
:data="treeData" :data="treeData"
:tree-default-expand-all="true"
:field-names="{ :field-names="{
key: 'id', key: 'id',
title: 'name', title: 'name',