feat(邮箱邀请): 邮箱邀请重复提示&组织/项目成员邮箱邀请
This commit is contained in:
parent
6b896dabc4
commit
6f86483461
|
@ -171,7 +171,9 @@ const transform: AxiosTransform = {
|
|||
throw new Error(e as unknown as string);
|
||||
}
|
||||
checkStatus(response?.status, msg, response?.data?.code, errorMessageMode);
|
||||
return Promise.reject(response?.data?.message || error);
|
||||
return Promise.reject(
|
||||
response?.config?.requestOptions?.isReturnNativeResponse ? response?.data : response?.data?.message || error
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
EditProjectMemberUrl,
|
||||
GetProjectMemberListUrl,
|
||||
ProjectMemberCommentOptions,
|
||||
ProjectMemberInviteUrl,
|
||||
ProjectMemberList,
|
||||
ProjectMemberOptions,
|
||||
ProjectUserGroupUrl,
|
||||
|
@ -14,7 +15,12 @@ import {
|
|||
|
||||
import { ReviewUserItem } from '@/models/caseManagement/caseReview';
|
||||
import type { CommonList, TableQueryParams } from '@/models/common';
|
||||
import type { ActionProjectMember, ProjectMemberItem } from '@/models/projectManagement/projectAndPermission';
|
||||
import type {
|
||||
ActionProjectMember,
|
||||
InviteMemberParams,
|
||||
ProjectMemberItem,
|
||||
ProjectUserOption,
|
||||
} from '@/models/projectManagement/projectAndPermission';
|
||||
|
||||
// 获取项目成员列表
|
||||
export function getProjectMemberList(data: TableQueryParams) {
|
||||
|
@ -46,7 +52,7 @@ export function removeProjectMember(projectId: string, userId: string) {
|
|||
|
||||
// 获取用户组下拉
|
||||
export function getProjectUserGroup(projectId: string) {
|
||||
return MSR.get({ url: ProjectUserGroupUrl, params: projectId });
|
||||
return MSR.get<ProjectUserOption[]>({ url: ProjectUserGroupUrl, params: projectId });
|
||||
}
|
||||
|
||||
// 项目成员下拉选项
|
||||
|
@ -65,3 +71,8 @@ export function getProjectMemberCommentOptions(projectId: string, keyword?: stri
|
|||
params: { keyword },
|
||||
});
|
||||
}
|
||||
|
||||
// 邀请成员
|
||||
export function inviteMember(data: InviteMemberParams) {
|
||||
return MSR.post({ url: ProjectMemberInviteUrl, data }, { isReturnNativeResponse: true });
|
||||
}
|
||||
|
|
|
@ -8,11 +8,18 @@ import {
|
|||
getProjectListUrl,
|
||||
getUserGroupList,
|
||||
getUserList,
|
||||
inviteOrgMemberUrl,
|
||||
UpdateMemberUrl,
|
||||
} from '@/api/requrls/setting/member';
|
||||
|
||||
import type { CommonList, TableQueryParams } from '@/models/common';
|
||||
import type { AddOrUpdateMemberModel, BatchAddProjectModel, LinkItem, MemberItem } from '@/models/setting/member';
|
||||
import type {
|
||||
AddOrUpdateMemberModel,
|
||||
BatchAddProjectModel,
|
||||
InviteOrgMemberParams,
|
||||
LinkItem,
|
||||
MemberItem,
|
||||
} from '@/models/setting/member';
|
||||
// 获取成员列表
|
||||
export function getMemberList(data: TableQueryParams) {
|
||||
return MSR.post<CommonList<MemberItem>>({ url: GetMemberListUrl, data });
|
||||
|
@ -48,3 +55,7 @@ export function getUser(organizationId: string, keyword: string) {
|
|||
export function getProjectList(organizationId: string, keyword?: string) {
|
||||
return MSR.get<LinkItem[]>({ url: `${getProjectListUrl}/${organizationId}`, params: { keyword } });
|
||||
}
|
||||
// 添加到用户组
|
||||
export function inviteOrgMember(data: InviteOrgMemberParams) {
|
||||
return MSR.post({ url: inviteOrgMemberUrl, data }, { isReturnNativeResponse: true });
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ export function getSystemProjects() {
|
|||
|
||||
// 邀请用户
|
||||
export function inviteUser(data: InviteUserParams) {
|
||||
return MSR.post({ url: InviteUserUrl, data });
|
||||
return MSR.post({ url: InviteUserUrl, data }, { isReturnNativeResponse: true });
|
||||
}
|
||||
|
||||
// 用户注册
|
||||
|
|
|
@ -8,3 +8,5 @@ export const ProjectUserGroupUrl = '/project/member/get-role/option';
|
|||
export const ProjectMemberOptions = '/project/member/get-member/option';
|
||||
export const ProjectMemberList = '/project/get-member/option';
|
||||
export const ProjectMemberCommentOptions = '/project/member/comment/user-option'; // 项目成员-@成员下拉列表
|
||||
// 项目成员-邀请成员
|
||||
export const ProjectMemberInviteUrl = '/project/member/invite';
|
||||
|
|
|
@ -12,4 +12,7 @@ export const getUserGroupList = '/organization/user/role/list';
|
|||
export const getUserList = '/organization/not-exist/user/list';
|
||||
// 获取弹窗里边的穿梭项目列表
|
||||
export const getProjectListUrl = '/organization/project/list';
|
||||
export const getSystemProjectListUrl = '/system/project/list'; // 获取系统项目列表
|
||||
// 获取系统项目列表
|
||||
export const getSystemProjectListUrl = '/system/project/list';
|
||||
// 邀请组织成员
|
||||
export const inviteOrgMemberUrl = '/organization/user/invite';
|
||||
|
|
|
@ -180,7 +180,7 @@
|
|||
label: t('personal.switchOrg'),
|
||||
icon: () => (
|
||||
<MsIcon
|
||||
type="icon-icon_switch_outlined1"
|
||||
type="icon-icon_switch_outlined"
|
||||
class={isActiveSwitchOrg.value ? 'text-[rgb(var(--primary-5))]' : 'text-[var(--color-text-4)]'}
|
||||
/>
|
||||
),
|
||||
|
@ -434,7 +434,7 @@
|
|||
clearTimeout(mouseEnterTimer);
|
||||
}}
|
||||
>
|
||||
<MsIcon type="icon-icon_switch_outlined1" class="text-[var(--color-text-4)]" />
|
||||
<MsIcon type="icon-icon_switch_outlined" class="text-[var(--color-text-4)]" />
|
||||
</div>
|
||||
))
|
||||
: ''}
|
||||
|
|
|
@ -61,3 +61,10 @@ export interface AddProjectMember {
|
|||
userIds: string[] | string;
|
||||
roleIds: string[] | string;
|
||||
}
|
||||
|
||||
export interface InviteMemberParams {
|
||||
inviteEmails: string[];
|
||||
userRoleIds: string[];
|
||||
organizationId: string;
|
||||
projectId: string;
|
||||
}
|
||||
|
|
|
@ -58,3 +58,9 @@ export interface LinkItem {
|
|||
disabled?: boolean;
|
||||
}
|
||||
export type LinkList = LinkItem[];
|
||||
|
||||
export interface InviteOrgMemberParams {
|
||||
inviteEmails: string[];
|
||||
userRoleIds: string[];
|
||||
organizationId: string;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
<a-button v-permission="['PROJECT_USER:READ+ADD']" class="mr-3" type="primary" @click="addMember">
|
||||
{{ t('project.member.addMember') }}
|
||||
</a-button>
|
||||
<a-button v-permission="['PROJECT_USER:READ+INVITE']" type="outline" class="mr-3" @click="inviteVisible = true">
|
||||
{{ t('system.user.emailInvite') }}
|
||||
</a-button>
|
||||
</div>
|
||||
<div>
|
||||
<a-select v-model="roleIds" @change="changeSelect">
|
||||
|
@ -90,6 +93,7 @@
|
|||
:current-select-count="batchParams.currentSelectCount"
|
||||
@add-user-group="addUserGroup"
|
||||
/>
|
||||
<inviteModal v-model:visible="inviteVisible" :user-group-options="userGroupOptions" range="project"></inviteModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -103,6 +107,7 @@
|
|||
import MsBatchModal from '@/components/business/ms-batch-modal/index.vue';
|
||||
import MsRemoveButton from '@/components/business/ms-remove-button/MsRemoveButton.vue';
|
||||
import AddMemberModal from './addMemberModal.vue';
|
||||
import inviteModal from '@/views/setting/system/components/inviteModal.vue';
|
||||
|
||||
import {
|
||||
addOrUpdateProjectMember,
|
||||
|
@ -306,6 +311,7 @@
|
|||
loadList();
|
||||
resetSelector();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
|
@ -433,6 +439,8 @@
|
|||
editProjectMember(record);
|
||||
};
|
||||
|
||||
const inviteVisible = ref(false);
|
||||
|
||||
onBeforeMount(async () => {
|
||||
await initOptions();
|
||||
initData();
|
||||
|
|
|
@ -7,8 +7,17 @@
|
|||
class="mr-3"
|
||||
type="primary"
|
||||
@click="addOrEditMember('add')"
|
||||
>{{ t('organization.member.addMember') }}</a-button
|
||||
>
|
||||
{{ t('organization.member.addMember') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
v-permission="['ORGANIZATION_MEMBER:READ+INVITE']"
|
||||
type="outline"
|
||||
class="mr-3"
|
||||
@click="inviteVisible = true"
|
||||
>
|
||||
{{ t('system.user.emailInvite') }}
|
||||
</a-button>
|
||||
</div>
|
||||
<a-input-search
|
||||
v-model="keyword"
|
||||
|
@ -114,6 +123,11 @@
|
|||
@add-project="addProjectOrAddUserGroup"
|
||||
@add-user-group="addProjectOrAddUserGroup"
|
||||
/>
|
||||
<inviteModal
|
||||
v-model:visible="inviteVisible"
|
||||
:user-group-options="userGroupOptions"
|
||||
range="organization"
|
||||
></inviteModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -133,6 +147,7 @@
|
|||
import MSBatchModal from '@/components/business/ms-batch-modal/index.vue';
|
||||
import MsRemoveButton from '@/components/business/ms-remove-button/MsRemoveButton.vue';
|
||||
import AddMemberModal from './components/addMemberModal.vue';
|
||||
import inviteModal from '@/views/setting/system/components/inviteModal.vue';
|
||||
|
||||
import {
|
||||
addOrUpdate,
|
||||
|
@ -149,7 +164,7 @@
|
|||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import type { TableQueryParams } from '@/models/common';
|
||||
import type { AddOrUpdateMemberModel, BatchAddProjectModel, LinkList, MemberItem } from '@/models/setting/member';
|
||||
import type { AddOrUpdateMemberModel, LinkList, MemberItem } from '@/models/setting/member';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
||||
const tableStore = useTableStore();
|
||||
|
@ -293,6 +308,7 @@
|
|||
initData();
|
||||
resetSelector();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
deleteLoading.value = false;
|
||||
|
@ -380,6 +396,7 @@
|
|||
initData();
|
||||
resetSelector();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
record.showUserSelect = false;
|
||||
|
@ -448,6 +465,8 @@
|
|||
}
|
||||
};
|
||||
|
||||
const inviteVisible = ref(false);
|
||||
|
||||
onBeforeMount(() => {
|
||||
initData();
|
||||
getLinkList();
|
||||
|
|
|
@ -16,9 +16,10 @@
|
|||
<template #second>
|
||||
<div class="p-[16px]">
|
||||
<div class="flex flex-row items-center justify-between">
|
||||
<a-tooltip :content="currentUserGroupItem.name">
|
||||
<div class="one-line-text max-w-[300px] font-medium">{{ currentUserGroupItem.name }}</div>
|
||||
</a-tooltip>
|
||||
<a-radio-group v-if="couldShowUser && couldShowAuth" v-model="currentTable" class="ml-[14px]" type="button">
|
||||
<a-radio v-if="couldShowAuth" value="auth">{{ t('system.userGroup.auth') }}</a-radio>
|
||||
<a-radio v-if="couldShowUser" value="user">{{ t('system.userGroup.user') }}</a-radio>
|
||||
</a-radio-group>
|
||||
<div class="flex items-center">
|
||||
<a-input-search
|
||||
v-if="currentTable === 'user'"
|
||||
|
@ -29,15 +30,6 @@
|
|||
@search="handleSearch"
|
||||
@clear="() => handleSearch('')"
|
||||
></a-input-search>
|
||||
<a-radio-group
|
||||
v-if="couldShowUser && couldShowAuth"
|
||||
v-model="currentTable"
|
||||
class="ml-[14px]"
|
||||
type="button"
|
||||
>
|
||||
<a-radio v-if="couldShowAuth" value="auth">{{ t('system.userGroup.auth') }}</a-radio>
|
||||
<a-radio v-if="couldShowUser" value="user">{{ t('system.userGroup.user') }}</a-radio>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-[16px]">
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
>
|
||||
<a-form ref="inviteFormRef" class="overflow-hidden rounded-[4px]" :model="emailForm" layout="vertical">
|
||||
<a-form-item
|
||||
id="emailInviteInput"
|
||||
field="emails"
|
||||
:label="t('system.user.inviteEmail')"
|
||||
:rules="[{ required: true, message: t('system.user.createUserEmailNotNull') }]"
|
||||
|
@ -54,17 +55,28 @@
|
|||
|
||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||
|
||||
import { inviteMember } from '@/api/modules/project-management/projectMember';
|
||||
import { inviteOrgMember } from '@/api/modules/setting/member';
|
||||
import { inviteUser } from '@/api/modules/setting/user';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
|
||||
import { ProjectUserOption } from '@/models/projectManagement/projectAndPermission';
|
||||
import type { SystemRole } from '@/models/setting/user';
|
||||
|
||||
const appStore = useAppStore();
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean;
|
||||
userGroupOptions: SystemRole[];
|
||||
}>();
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
visible: boolean;
|
||||
userGroupOptions: (SystemRole | ProjectUserOption)[];
|
||||
range?: 'system' | 'organization' | 'project';
|
||||
}>(),
|
||||
{
|
||||
range: 'system',
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits(['update:visible']);
|
||||
|
||||
|
@ -95,7 +107,13 @@
|
|||
() => props.userGroupOptions,
|
||||
(arr) => {
|
||||
if (arr.length) {
|
||||
emailForm.value.userGroup = arr.filter((e: SystemRole) => e.selected === true).map((e: SystemRole) => e.id);
|
||||
if (props.range === 'system') {
|
||||
emailForm.value.userGroup = (arr as SystemRole[]).filter((e) => e.selected === true).map((e) => e.id);
|
||||
} else if (props.range === 'project') {
|
||||
emailForm.value.userGroup = ['project_member'];
|
||||
} else if (props.range === 'organization') {
|
||||
emailForm.value.userGroup = ['org_member'];
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -104,9 +122,34 @@
|
|||
inviteVisible.value = false;
|
||||
inviteFormRef.value?.resetFields();
|
||||
emailForm.value.emails = [];
|
||||
emailForm.value.userGroup = props.userGroupOptions
|
||||
.filter((e: SystemRole) => e.selected === true)
|
||||
.map((e: SystemRole) => e.id);
|
||||
if (props.range === 'system') {
|
||||
emailForm.value.userGroup = (props.userGroupOptions as SystemRole[])
|
||||
.filter((e) => e.selected === true)
|
||||
.map((e) => e.id);
|
||||
} else if (props.range === 'project') {
|
||||
emailForm.value.userGroup = ['project_member'];
|
||||
} else if (props.range === 'organization') {
|
||||
emailForm.value.userGroup = ['org_member'];
|
||||
}
|
||||
}
|
||||
|
||||
function handleInviteError(error: any) {
|
||||
if (error?.messageDetail) {
|
||||
try {
|
||||
const errEmails = JSON.parse(error.messageDetail);
|
||||
if (Array.isArray(errEmails)) {
|
||||
const inputEmails = document.getElementById('emailInviteInput')?.querySelectorAll('.arco-input-tag-tag');
|
||||
inputEmails?.forEach((input) => {
|
||||
if (errEmails.includes(input.textContent)) {
|
||||
input.setAttribute('style', 'border-color: rgb(var(--danger-6))');
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (_error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(_error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function emailInvite() {
|
||||
|
@ -114,14 +157,30 @@
|
|||
if (!errors) {
|
||||
try {
|
||||
inviteLoading.value = true;
|
||||
await inviteUser({
|
||||
inviteEmails: emailForm.value.emails,
|
||||
userRoleIds: emailForm.value.userGroup,
|
||||
});
|
||||
if (props.range === 'project') {
|
||||
await inviteMember({
|
||||
inviteEmails: emailForm.value.emails,
|
||||
userRoleIds: emailForm.value.userGroup,
|
||||
projectId: appStore.currentProjectId,
|
||||
organizationId: appStore.currentOrgId,
|
||||
});
|
||||
} else if (props.range === 'organization') {
|
||||
await inviteOrgMember({
|
||||
inviteEmails: emailForm.value.emails,
|
||||
userRoleIds: emailForm.value.userGroup,
|
||||
organizationId: appStore.currentOrgId,
|
||||
});
|
||||
} else {
|
||||
await inviteUser({
|
||||
inviteEmails: emailForm.value.emails,
|
||||
userRoleIds: emailForm.value.userGroup,
|
||||
});
|
||||
}
|
||||
Message.success(t('system.user.inviteSuccess'));
|
||||
inviteVisible.value = false;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
// eslint-disable-next-line no-console
|
||||
handleInviteError(error);
|
||||
} finally {
|
||||
inviteLoading.value = false;
|
||||
}
|
|
@ -19,7 +19,7 @@
|
|||
{{ t('system.user.emailInvite') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
v-permission="['SYSTEM_USER:READ+IMPORT', 'SYSTEM_USER_ROLE:READ']"
|
||||
v-permission.all="['SYSTEM_USER:READ+IMPORT', 'SYSTEM_USER_ROLE:READ']"
|
||||
class="mr-3"
|
||||
type="outline"
|
||||
@click="showImportModal"
|
||||
|
@ -309,8 +309,8 @@
|
|||
import MsBatchForm from '@/components/business/ms-batch-form/index.vue';
|
||||
import type { FormItemModel } from '@/components/business/ms-batch-form/types';
|
||||
import MsSelect from '@/components/business/ms-select';
|
||||
import inviteModal from '../components/inviteModal.vue';
|
||||
import batchModal from './components/batchModal.vue';
|
||||
import inviteModal from './components/inviteModal.vue';
|
||||
|
||||
import {
|
||||
batchCreateUser,
|
||||
|
@ -367,6 +367,7 @@
|
|||
title: 'system.user.tableColumnPhone',
|
||||
dataIndex: 'phone',
|
||||
showDrag: true,
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
title: 'system.user.tableColumnOrg',
|
||||
|
|
Loading…
Reference in New Issue