feat(@vben/web-antd): 项目成员管理改 Drawer + 分页 + 增量
从 Modal 多选改为 Drawer 分页表,更接近"成员管理"语义: - 原 assign-user-form.vue 重写为 Drawer + Vxe 分页表 - 新增 add-user-modal.vue 子弹窗用于添加用户(过滤已是成员) - 每行一个"移除"popConfirm 按钮,调 removeProjectUser 单删 - 顶部 keyword 搜索,按 username/nickname/mobile 模糊 - 底部提示:超管不在此列表(后端已过滤) - data.ts 新增 useProjectMemberGridColumns - api 新增 getProjectUserPage / addProjectUsers / removeProjectUser - project/index.vue 接入点改 useVbenDrawer Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
<script lang="ts" setup>
|
||||
import type { SystemUserApi } from '#/api/system/user';
|
||||
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
|
||||
import { message, Select, Spin } from 'ant-design-vue';
|
||||
|
||||
import { getSimpleUserList } from '#/api/system/user';
|
||||
import { addProjectUsers } from '#/api/system/user-project';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
interface AddUserModalData {
|
||||
projectId: number;
|
||||
projectName?: string;
|
||||
excludedUserIds: number[];
|
||||
}
|
||||
|
||||
const emit = defineEmits(['success']);
|
||||
|
||||
const allUsers = ref<SystemUserApi.User[]>([]);
|
||||
const selectedUserIds = ref<number[]>([]);
|
||||
const loading = ref(false);
|
||||
const currentData = ref<AddUserModalData | null>(null);
|
||||
|
||||
/** 可选项:全量用户 - 已是成员的用户 */
|
||||
const selectOptions = computed(() => {
|
||||
const excluded = new Set(currentData.value?.excludedUserIds ?? []);
|
||||
return allUsers.value
|
||||
.filter((u) => u.id && !excluded.has(u.id))
|
||||
.map((u) => ({
|
||||
value: u.id,
|
||||
label: `${u.nickname || u.username}(${u.username})`,
|
||||
}));
|
||||
});
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
async onConfirm() {
|
||||
if (!currentData.value?.projectId) return;
|
||||
if (selectedUserIds.value.length === 0) {
|
||||
message.warning('请至少选择一个用户');
|
||||
return;
|
||||
}
|
||||
modalApi.lock();
|
||||
try {
|
||||
await addProjectUsers({
|
||||
projectId: currentData.value.projectId,
|
||||
userIds: selectedUserIds.value,
|
||||
});
|
||||
message.success($t('ui.actionMessage.operationSuccess'));
|
||||
await modalApi.close();
|
||||
emit('success');
|
||||
} finally {
|
||||
modalApi.unlock();
|
||||
}
|
||||
},
|
||||
async onOpenChange(isOpen: boolean) {
|
||||
if (!isOpen) {
|
||||
allUsers.value = [];
|
||||
selectedUserIds.value = [];
|
||||
currentData.value = null;
|
||||
return;
|
||||
}
|
||||
const data = modalApi.getData<AddUserModalData>();
|
||||
if (!data) return;
|
||||
currentData.value = data;
|
||||
loading.value = true;
|
||||
try {
|
||||
allUsers.value = await getSimpleUserList();
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal
|
||||
:title="
|
||||
currentData?.projectName
|
||||
? `添加用户到项目 - ${currentData.projectName}`
|
||||
: '添加用户'
|
||||
"
|
||||
class="w-[560px]"
|
||||
>
|
||||
<Spin :spinning="loading">
|
||||
<div class="px-4 py-2">
|
||||
<div class="mb-2 text-sm">选择要加入项目的用户(已在项目中的用户会自动过滤)</div>
|
||||
<Select
|
||||
v-model:value="selectedUserIds"
|
||||
mode="multiple"
|
||||
placeholder="请选择用户"
|
||||
:options="selectOptions"
|
||||
:filter-option="
|
||||
(input: string, option: any) =>
|
||||
option.label.toLowerCase().includes(input.toLowerCase())
|
||||
"
|
||||
show-search
|
||||
allow-clear
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
</Spin>
|
||||
</Modal>
|
||||
</template>
|
||||
Reference in New Issue
Block a user