feat(设置): 系统&组织-成员抽屉列表增加用户组列
This commit is contained in:
parent
d80ba71338
commit
e2429d0c94
|
@ -42,6 +42,7 @@ export interface AddOrUpdateMemberModel {
|
|||
memberIds?: string[];
|
||||
userRoleIds?: string[];
|
||||
projectIds?: string[];
|
||||
memberId?: string;
|
||||
}
|
||||
// 添加组织成员到项目
|
||||
export interface BatchAddProjectModel {
|
||||
|
|
|
@ -151,6 +151,7 @@
|
|||
const protocols = allProtocolList.value.filter((item) => !val.includes(item as string));
|
||||
setLocalStorage(props.protocolKey, protocols);
|
||||
emit('selectedProtocolsChange');
|
||||
if (props.notShowOperation) return;
|
||||
protocolIsEmptyVisible.value = !val.length;
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<template>
|
||||
<MsDrawer
|
||||
:width="680"
|
||||
:width="800"
|
||||
:visible="currentVisible"
|
||||
unmount-on-close
|
||||
:footer="false"
|
||||
:title="t('system.organization.addMember')"
|
||||
:title="t('system.memberList')"
|
||||
:mask="false"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
|
@ -35,6 +35,37 @@
|
|||
`(${t('common.admin')})`
|
||||
}}</span>
|
||||
</template>
|
||||
<template #userGroup="{ record }">
|
||||
<MsTagGroup
|
||||
v-if="!record.selectUserGroupVisible"
|
||||
:tag-list="record.userRoleList"
|
||||
type="primary"
|
||||
theme="outline"
|
||||
@click="handleTagClick(record)"
|
||||
/>
|
||||
<MsSelect
|
||||
v-else
|
||||
v-model:model-value="record.userRoleList"
|
||||
:placeholder="t('system.user.createUserUserGroupPlaceholder')"
|
||||
:options="userGroupOptions"
|
||||
:search-keys="['name']"
|
||||
:loading="record.selectUserGroupLoading"
|
||||
:disabled="record.selectUserGroupLoading"
|
||||
:fallback-option="(val) => ({
|
||||
label: (val as Record<string, any>).name,
|
||||
value: val,
|
||||
})"
|
||||
value-key="id"
|
||||
label-key="name"
|
||||
class="w-full max-w-[300px]"
|
||||
allow-clear
|
||||
multiple
|
||||
at-least-one
|
||||
:object-value="true"
|
||||
@popup-visible-change="(value) => handleUserGroupChange(value, record)"
|
||||
>
|
||||
</MsSelect>
|
||||
</template>
|
||||
<template #operation="{ record }">
|
||||
<MsRemoveButton
|
||||
v-permission="['ORGANIZATION_PROJECT:READ+DELETE_MEMBER']"
|
||||
|
@ -62,14 +93,20 @@
|
|||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import MsTagGroup from '@/components/pure/ms-tag/ms-tag-group.vue';
|
||||
import MsRemoveButton from '@/components/business/ms-remove-button/MsRemoveButton.vue';
|
||||
import MsSelect from '@/components/business/ms-select';
|
||||
import AddUserModal from './addUserModal.vue';
|
||||
|
||||
import { addOrUpdateProjectMember, getProjectUserGroup } from '@/api/modules/project-management/projectMember';
|
||||
import { deleteProjectMemberByOrg, postProjectMemberByProjectId } from '@/api/modules/setting/organizationAndProject';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { formatPhoneNumber } from '@/utils';
|
||||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import type { LinkList } from '@/models/setting/member';
|
||||
import type { UserListItem } from '@/models/setting/user';
|
||||
|
||||
export interface projectDrawerProps {
|
||||
visible: boolean;
|
||||
organizationId?: string;
|
||||
|
@ -98,11 +135,18 @@
|
|||
showTooltip: true,
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: 'system.user.tableColumnUserGroup',
|
||||
dataIndex: 'userRoleList',
|
||||
slotName: 'userGroup',
|
||||
isTag: true,
|
||||
width: 300,
|
||||
},
|
||||
{
|
||||
title: 'system.organization.email',
|
||||
dataIndex: 'email',
|
||||
width: 180,
|
||||
showTooltip: true,
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: 'system.organization.phone',
|
||||
|
@ -129,6 +173,8 @@
|
|||
return {
|
||||
...record,
|
||||
phone: formatPhoneNumber(record.phone || ''),
|
||||
selectUserGroupVisible: false,
|
||||
selectUserGroupLoading: false,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
@ -147,6 +193,44 @@
|
|||
await loadList();
|
||||
};
|
||||
|
||||
const userGroupOptions = ref<LinkList>([]);
|
||||
const getUserGroupOptions = async () => {
|
||||
try {
|
||||
if (props.projectId) {
|
||||
userGroupOptions.value = await getProjectUserGroup(props.projectId);
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
function handleTagClick(record: UserListItem & Record<string, any>) {
|
||||
if (hasAnyPermission(['ORGANIZATION_PROJECT:READ+UPDATE_MEMBER'])) {
|
||||
record.selectUserGroupVisible = true;
|
||||
}
|
||||
}
|
||||
async function handleUserGroupChange(val: boolean, record: UserListItem & Record<string, any>) {
|
||||
try {
|
||||
if (!val) {
|
||||
record.selectUserGroupLoading = true;
|
||||
if (props.projectId) {
|
||||
await addOrUpdateProjectMember({
|
||||
projectId: props.projectId,
|
||||
userId: record.id,
|
||||
roleIds: record.userRoleList.map((e) => e.id),
|
||||
});
|
||||
}
|
||||
Message.success(t('system.user.updateUserSuccess'));
|
||||
fetchData();
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
record.selectUserGroupLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
const handleAddMember = () => {
|
||||
userVisible.value = true;
|
||||
};
|
||||
|
@ -185,6 +269,7 @@
|
|||
currentVisible.value = visible;
|
||||
if (visible) {
|
||||
fetchData();
|
||||
getUserGroupOptions();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -195,4 +280,12 @@
|
|||
height: 100vh !important;
|
||||
border: 1px solid red;
|
||||
}
|
||||
// 下拉不折行
|
||||
:deep(.arco-select-view) {
|
||||
height: 32px;
|
||||
.arco-select-view-inner {
|
||||
@apply overflow-y-auto overflow-x-hidden;
|
||||
.ms-scroll-bar();
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -34,7 +34,11 @@
|
|||
</MsButton>
|
||||
</div>
|
||||
</template>
|
||||
<MsIcon v-if="record.deleted" type="icon-icon_alarm_clock" class="ml-[4px] text-[rgb(var(--danger-6))]" />
|
||||
<MsIcon
|
||||
v-if="record.deleted"
|
||||
type="icon-icon_delete_countdown"
|
||||
class="ml-[4px] text-[rgb(var(--danger-6))]"
|
||||
/>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template #creator="{ record }">
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
>
|
||||
</div>
|
||||
</template>
|
||||
<MsIcon v-if="record.deleted" type="icon-icon_alarm_clock" class="ml-[4px] text-[rgb(var(--danger-6))]" />
|
||||
<MsIcon v-if="record.deleted" type="icon-icon_delete_countdown" class="ml-[4px] text-[rgb(var(--danger-6))]" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template #creator="{ record }">
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
>
|
||||
</div>
|
||||
</template>
|
||||
<MsIcon v-if="record.deleted" type="icon-icon_alarm_clock" class="ml-[4px] text-[rgb(var(--danger-6))]" />
|
||||
<MsIcon v-if="record.deleted" type="icon-icon_delete_countdown" class="ml-[4px] text-[rgb(var(--danger-6))]" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template #creator="{ record }">
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<template>
|
||||
<ms-drawer
|
||||
:mask="false"
|
||||
:width="680"
|
||||
:width="800"
|
||||
:visible="currentVisible"
|
||||
unmount-on-close
|
||||
:footer="false"
|
||||
class="ms-drawer-no-mask"
|
||||
:title="t('system.organization.addMemberTitle')"
|
||||
:title="t('system.memberList')"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<div>
|
||||
|
@ -36,6 +36,37 @@
|
|||
`(${t('common.admin')})`
|
||||
}}</span>
|
||||
</template>
|
||||
<template #userGroup="{ record }">
|
||||
<MsTagGroup
|
||||
v-if="!record.selectUserGroupVisible"
|
||||
:tag-list="record.userRoleList"
|
||||
type="primary"
|
||||
theme="outline"
|
||||
@click="handleTagClick(record)"
|
||||
/>
|
||||
<MsSelect
|
||||
v-else
|
||||
v-model:model-value="record.userRoleList"
|
||||
:placeholder="t('system.user.createUserUserGroupPlaceholder')"
|
||||
:options="userGroupOptions"
|
||||
:search-keys="['name']"
|
||||
:loading="record.selectUserGroupLoading"
|
||||
:disabled="record.selectUserGroupLoading"
|
||||
:fallback-option="(val) => ({
|
||||
label: (val as Record<string, any>).name,
|
||||
value: val,
|
||||
})"
|
||||
value-key="id"
|
||||
label-key="name"
|
||||
class="w-full max-w-[300px]"
|
||||
allow-clear
|
||||
multiple
|
||||
at-least-one
|
||||
:object-value="true"
|
||||
@popup-visible-change="(value) => handleUserGroupChange(value, record)"
|
||||
>
|
||||
</MsSelect>
|
||||
</template>
|
||||
<template #operation="{ record }">
|
||||
<MsRemoveButton
|
||||
v-permission="['SYSTEM_ORGANIZATION_PROJECT:READ+DELETE_MEMBER']"
|
||||
|
@ -64,9 +95,13 @@
|
|||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import MsTagGroup from '@/components/pure/ms-tag/ms-tag-group.vue';
|
||||
import MsRemoveButton from '@/components/business/ms-remove-button/MsRemoveButton.vue';
|
||||
import MsSelect from '@/components/business/ms-select';
|
||||
import AddUserModal from './addUserModal.vue';
|
||||
|
||||
import { addOrUpdateProjectMember, getProjectUserGroup } from '@/api/modules/project-management/projectMember';
|
||||
import { addOrUpdate, getGlobalUserGroup } from '@/api/modules/setting/member';
|
||||
import {
|
||||
deleteUserFromOrgOrProject,
|
||||
postUserTableByOrgIdOrProjectId,
|
||||
|
@ -75,6 +110,9 @@
|
|||
import { characterLimit } from '@/utils';
|
||||
import { hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import type { LinkList } from '@/models/setting/member';
|
||||
import type { UserListItem } from '@/models/setting/user';
|
||||
|
||||
export interface projectDrawerProps {
|
||||
visible: boolean;
|
||||
organizationId?: string;
|
||||
|
@ -110,10 +148,17 @@
|
|||
showTooltip: true,
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: 'system.user.tableColumnUserGroup',
|
||||
dataIndex: 'userRoleList',
|
||||
slotName: 'userGroup',
|
||||
isTag: true,
|
||||
width: 300,
|
||||
},
|
||||
{
|
||||
title: 'system.organization.email',
|
||||
dataIndex: 'email',
|
||||
width: 200,
|
||||
width: 180,
|
||||
showTooltip: true,
|
||||
},
|
||||
{
|
||||
|
@ -136,6 +181,8 @@
|
|||
(record: any) => ({
|
||||
...record,
|
||||
nameTooltip: record.name + (record.adminFlag ? `(${t('common.admin')})` : ''),
|
||||
selectUserGroupVisible: false,
|
||||
selectUserGroupLoading: false,
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -159,6 +206,55 @@
|
|||
await loadList();
|
||||
};
|
||||
|
||||
const userGroupOptions = ref<LinkList>([]);
|
||||
const getUserGroupOptions = async () => {
|
||||
try {
|
||||
if (props.organizationId) {
|
||||
userGroupOptions.value = await getGlobalUserGroup(props.organizationId);
|
||||
} else if (props.projectId) {
|
||||
userGroupOptions.value = await getProjectUserGroup(props.projectId);
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
function handleTagClick(record: UserListItem & Record<string, any>) {
|
||||
if (hasAnyPermission(['SYSTEM_ORGANIZATION_PROJECT:READ+UPDATE_MEMBER'])) {
|
||||
record.selectUserGroupVisible = true;
|
||||
}
|
||||
}
|
||||
async function handleUserGroupChange(val: boolean, record: UserListItem & Record<string, any>) {
|
||||
try {
|
||||
if (!val) {
|
||||
record.selectUserGroupLoading = true;
|
||||
if (props.organizationId) {
|
||||
await addOrUpdate(
|
||||
{
|
||||
organizationId: props.organizationId,
|
||||
memberId: record.id,
|
||||
userRoleIds: record.userRoleList.map((e) => e.id),
|
||||
},
|
||||
'edit'
|
||||
);
|
||||
} else if (props.projectId) {
|
||||
await addOrUpdateProjectMember({
|
||||
projectId: props.projectId,
|
||||
userId: record.id,
|
||||
roleIds: record.userRoleList.map((e) => e.id),
|
||||
});
|
||||
}
|
||||
Message.success(t('system.user.updateUserSuccess'));
|
||||
fetchData();
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
record.selectUserGroupLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
const handleAddMember = () => {
|
||||
userVisible.value = true;
|
||||
};
|
||||
|
@ -206,7 +302,19 @@
|
|||
currentVisible.value = visible;
|
||||
if (visible) {
|
||||
fetchData();
|
||||
getUserGroupOptions();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
// 下拉不折行
|
||||
:deep(.arco-select-view) {
|
||||
height: 32px;
|
||||
.arco-select-view-inner {
|
||||
@apply overflow-y-auto overflow-x-hidden;
|
||||
.ms-scroll-bar();
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -2,7 +2,13 @@
|
|||
<MsCard simple>
|
||||
<MsTrialAlert :tip-content="t('system.authorized.orgAndProTipContent')" />
|
||||
<div class="mb-4 flex items-center justify-between">
|
||||
<div>
|
||||
<div class="flex items-center">
|
||||
<a-radio-group v-model="currentTable" size="medium" class="mr-[14px]" type="button">
|
||||
<a-radio value="organization">
|
||||
{{ t('system.organization.organizationCount', { count: organizationCount }) }}
|
||||
</a-radio>
|
||||
<a-radio value="project">{{ t('system.organization.projectCount', { count: projectCount }) }}</a-radio>
|
||||
</a-radio-group>
|
||||
<a-button
|
||||
v-if="currentTable !== 'organization' || licenseStore.hasLicense()"
|
||||
v-permission="['SYSTEM_ORGANIZATION_PROJECT:READ+ADD']"
|
||||
|
@ -15,23 +21,15 @@
|
|||
}}</a-button
|
||||
>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<a-input-search
|
||||
v-model="keyword"
|
||||
:placeholder="t('system.organization.searchIndexPlaceholder')"
|
||||
class="w-[240px]"
|
||||
allow-clear
|
||||
@press-enter="handleEnter"
|
||||
@search="handleSearch"
|
||||
@clear="handleSearch('')"
|
||||
></a-input-search>
|
||||
<a-radio-group v-model="currentTable" class="ml-[14px]" type="button">
|
||||
<a-radio value="organization">{{
|
||||
t('system.organization.organizationCount', { count: organizationCount })
|
||||
}}</a-radio>
|
||||
<a-radio value="project">{{ t('system.organization.projectCount', { count: projectCount }) }}</a-radio>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
<a-input-search
|
||||
v-model="keyword"
|
||||
:placeholder="t('system.organization.searchIndexPlaceholder')"
|
||||
class="w-[240px]"
|
||||
allow-clear
|
||||
@press-enter="handleEnter"
|
||||
@search="handleSearch"
|
||||
@clear="handleSearch('')"
|
||||
></a-input-search>
|
||||
</div>
|
||||
<div>
|
||||
<SystemOrganization v-if="currentTable === 'organization'" ref="orgTableRef" :keyword="currentKeyword" />
|
||||
|
|
|
@ -83,4 +83,5 @@ export default {
|
|||
'system.project.pleaseSelectAdmin': 'Please select project administrator',
|
||||
'system.project.poolIsNotNull': 'Resource pool cannot be empty',
|
||||
'system.project.enterOrganization': 'Enter the organization',
|
||||
'system.memberList': 'Member list',
|
||||
};
|
||||
|
|
|
@ -79,4 +79,5 @@ export default {
|
|||
'system.project.pleaseSelectAdmin': '请选择项目管理员',
|
||||
'system.project.poolIsNotNull': '资源池不能为空',
|
||||
'system.project.enterOrganization': '进入组织',
|
||||
'system.memberList': '成员列表',
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue