2026-04-23 15:48:43 +08:00
|
|
|
|
<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(() => {
|
2026-04-23 20:25:19 +08:00
|
|
|
|
const excluded = new Set(currentData.value?.excludedUserIds);
|
2026-04-23 15:48:43 +08:00
|
|
|
|
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">
|
2026-04-23 20:25:19 +08:00
|
|
|
|
<div class="mb-2 text-sm">
|
|
|
|
|
|
选择要加入项目的用户(已在项目中的用户会自动过滤)
|
|
|
|
|
|
</div>
|
2026-04-23 15:48:43 +08:00
|
|
|
|
<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>
|