feat(系统设置): 用户组管理删除用户

This commit is contained in:
RubyLiu 2023-06-19 19:00:13 +08:00 committed by 刘瑞斌
parent cc2c29f7b8
commit 70874bab31
18 changed files with 407 additions and 120 deletions

View File

@ -1,16 +1,16 @@
import MSR from '@/api/http/index';
import { GetApiTestList, GetApiTestListUrl } from '@/api/requrls/api-test';
import { TableQueryParams } from '@/models/common';
import { CommonList } from '@/models/api-test';
import { TableQueryParams, CommonList } from '@/models/common';
import { APIListItemI } from '@/models/api-test';
export function getTableList(params: TableQueryParams) {
const { current, pageSize, sort, filter, keyword } = params;
return MSR.post<CommonList>({
return MSR.post<CommonList<APIListItemI>>({
url: GetApiTestList,
data: { current, pageSize, sort, filter, keyword, projectId: 'test-project-id' },
});
}
export function getlist() {
return MSR.get<CommonList>({ url: GetApiTestListUrl });
return MSR.get<CommonList<APIListItemI>>({ url: GetApiTestListUrl });
}

View File

@ -0,0 +1,30 @@
import MSR from '@/api/http/index';
import { updateUserGroupU, getUserGroupU, addUserGroupU, deleteUserGroupU } from '@/api/requrls/usergroup';
// import { QueryParams, CommonList } from '@/models/common';
import { UserGroupItem } from '@/components/bussiness/usergroup/type';
export function updateOrAddUserGroup(data: Partial<UserGroupItem>) {
return MSR.post<UserGroupItem>({
url: data.id ? updateUserGroupU : addUserGroupU,
data,
});
}
export function updateSocpe(data: Partial<UserGroupItem>) {
return MSR.post<UserGroupItem>({
url: updateUserGroupU,
data,
});
}
export function getUserGroupList() {
return MSR.get<UserGroupItem[]>({ url: getUserGroupU });
}
export function deleteUserGroup(id: string) {
return MSR.get<string>({ url: `${deleteUserGroupU}${id}` });
}
export function getUsergroupInfo(id: string) {
return MSR.get<UserGroupItem>({ url: `${getUserGroupU}${id}` });
}

View File

@ -0,0 +1,21 @@
/** 修改用户组 */
export const updateUserGroupU = `/user/role/global/update`;
/** 编辑用户组对应的权限配置 */
export const editGlobalUSetting = `/user/role/global/permission/update`;
/** 添加用户组 */
export const addUserGroupU = `/user/role/global/add`;
/** 获取用户组对应的权限配置 */
export const getGlobalUSetting = `/user/role/global/permission/list`;
/** 获取用户组 */
export const getUserGroupU = `/user/role/global/list`;
/** 获取单个用户组信息 */
export const getUsergroupInfoU = `/user/role/global/get/`;
/** 删除用户组 */
export const deleteUserGroupU = `/user/role/global/delete/`;
/** 根据用户组获取用户列表 */
export const getUserByUserGroupU = `/user/role/relation/global/list/`;
/** 创建用户组添加用户 */
export const addUserToUserGroupU = `/user/role/relation/global/add/`;
/** 删除用户组用户 */
export const deleteUserFromUserGroupU = `/user/role/relation/global/delete/`;

View File

@ -0,0 +1,58 @@
<template>
<a-modal v-model:visible="currentVisible" modal-class="ug-delete">
<template #title>
<div class="flex w-full items-center">
<icon-exclamation-circle-fill class="danger" />
<span class="n1"> {{ t('system.userGroup.isDeleteUserGroup', { name: store.currentName }) }} </span>
</div>
</template>
<div>{{ t('system.userGroup.beforeDeleteUserGroup') }}</div>
<template #footer>
<a-button @click="emit('cancel')">{{ t('cancel') }}</a-button>
<a-button type="primary" @click="emit('ok')">{{ t('confirmDelete') }}</a-button>
</template>
</a-modal>
</template>
<script setup lang="ts">
import { useI18n } from '@/hooks/useI18n';
import { ref, watchEffect } from 'vue';
import useUserGroupStore from '@/store/modules/system/usergroup';
const { t } = useI18n();
const store = useUserGroupStore();
const props = defineProps<{
visible: boolean;
}>();
const currentVisible = ref(props.visible);
const emit = defineEmits<{
(e: 'cancel'): void;
(e: 'ok'): void;
}>();
watchEffect(() => {
currentVisible.value = props.visible;
});
</script>
<style scoped lang="less">
.ug-delete {
.danger {
font-size: 20px;
color: rgb(var(--danger-6));
}
.n1 {
color: var(--color-text-1);
}
.arco-modal-header {
border-bottom: none;
}
:deep(.arco-modal-title-align-center) {
justify-content: flex-start;
border: 1px solid red;
}
}
</style>

View File

@ -13,7 +13,7 @@
</div>
<div>
<div
v-for="element in customList"
v-for="element in userGroupList"
:key="element.id"
:class="{
'flex': true,
@ -28,13 +28,15 @@
:visible="popVisible[element.id]"
:type="popType"
:default-name="popDefaultName"
:list="userGroupList"
position="bl"
@cancel="() => handlePopConfirmCancel(element.id)"
@submit="(value: CustomMoreActionItem) => handlePopConfirmSubmit(value,element.id)"
>
<div class="draglist-item flex grow flex-row justify-between">
<div class="usergroup-title leading-[24px]">
<span class="n1">{{ element.name }}</span>
<span v-if="element.title" class="n4">{{ `${element.title}` }}</span>
<span v-if="element.type" class="n4">{{ t(`system.userGroup.${element.type}`) }}</span>
</div>
<div v-if="element.id === currentId">
<MsTableMoreAction :list="customAction" @select="(value) => handleMoreAction(value, element.id)" />
@ -47,43 +49,38 @@
</div>
<AddUserModal :visible="addUserVisible" @cancel="addUserVisible = false" />
<AddUserGroupModal :visible="addUserGroupVisible" @cancel="addUserGroupVisible = false" />
<DeleteUserGroupModal :visible="deleteUserGroupVisible" @cancel="deleteUserGroupVisible = false" />
</template>
<script lang="ts" setup>
import { ref, onBeforeMount } from 'vue';
import { ref, onMounted } from 'vue';
import { useI18n } from '@/hooks/useI18n';
import { PopVisibleItem, RenameType, UserGroupListItem } from './type';
import { CustomMoreActionItem, PopVisibleItem, RenameType, UserGroupItem } from './type';
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
import AddUserModal from './addUserModal.vue';
import AddUserGroupModal from './addUserGroupModal.vue';
import DeleteUserGroupModal from './deleteUserGroupModal.vue';
import popconfirm from './popconfirm.vue';
import useUserGroupStore from '@/store/modules/system/usergroup';
import { getUserGroupList, updateOrAddUserGroup } from '@/api/modules/system/usergroup';
const { t } = useI18n();
const searchKey = ref('');
const store = useUserGroupStore();
// loading
const currentId = ref(0);
const currentId = ref('');
const addUserVisible = ref(false);
const addUserGroupVisible = ref(false);
const deleteUserGroupVisible = ref(false);
//
const popVisible = ref<PopVisibleItem>({});
//
const popType = ref<RenameType>('rename');
const popDefaultName = ref('');
//
const customList = ref<UserGroupListItem[]>([
{ name: '系统管理员', title: '', id: 1, authScope: 'system' },
{ name: '系统成员', title: '', id: 2, authScope: 'system' },
{ name: '组织管理员', title: '', id: 3, authScope: 'system' },
{ name: '组织成员', title: '', id: 4, authScope: 'system' },
{ name: '项目管理员', title: '', id: 5, authScope: 'system' },
{ name: '项目成员', title: '', id: 6, authScope: 'system' },
{ name: '自定义用户组1', title: '项目', id: 7, authScope: 'project' },
{ name: '自定义用户组2', title: '组织', id: 8, authScope: 'oraganation' },
]);
const userGroupList = ref<UserGroupItem[]>([]);
const customAction: ActionsItem[] = [
{
@ -105,44 +102,99 @@
eventTag: 'delete',
},
];
//
const addUserGroup = () => {
// eslint-disable-next-line no-console
addUserGroupVisible.value = true;
};
function searchData(keyword: string) {
// eslint-disable-next-line no-console
console.log(keyword);
}
const handleMoreAction = (item: ActionsItem, id: number) => {
//
const handleMoreAction = (item: ActionsItem, id: string) => {
if (item.eventTag !== 'delete') {
popType.value = item.eventTag as RenameType;
const tmpObj = customList.value.filter((ele) => ele.id === id)[0];
const tmpObj = userGroupList.value.filter((ele) => ele.id === id)[0];
popVisible.value = { ...popVisible.value, [id]: true };
if (item.eventTag === 'rename') {
popDefaultName.value = tmpObj.name;
} else {
popDefaultName.value = tmpObj.authScope;
popDefaultName.value = tmpObj.scopeId;
}
} else {
//
deleteUserGroupVisible.value = true;
}
};
const handlePopConfirmCancel = (id: number) => {
//
const handleListItemClick = (element: UserGroupItem) => {
const { id, name, type } = element;
currentId.value = id;
store.setInfo({ currentName: name, currentTitle: type });
};
//
const initData = async () => {
try {
const res = await getUserGroupList();
if (res.length > 0) {
userGroupList.value = res;
handleListItemClick(res[0]);
//
const tmpObj: PopVisibleItem = {};
res.forEach((element) => {
tmpObj[element.id] = false;
});
popVisible.value = tmpObj;
}
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
}
};
// confirm
const handlePopConfirmCancel = (id: string) => {
popVisible.value = { ...popVisible.value, [id]: false };
};
onBeforeMount(() => {
const tmpObj: PopVisibleItem = {};
customList.value.forEach((element) => {
tmpObj[element.id] = false;
});
popVisible.value = tmpObj;
});
const handleListItemClick = (element: UserGroupListItem) => {
const { id, name, title } = element;
currentId.value = id;
store.setInfo({ currentName: name, currentTitle: title });
//
const handlePopConfirmSubmit = async (item: CustomMoreActionItem, id: string) => {
popVisible.value = { ...popVisible.value, [id]: false };
if (item.eventKey === 'rename') {
//
try {
const res = await updateOrAddUserGroup({ id, name: item.name });
if (res) {
initData();
}
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
}
} else {
//
try {
const res = await updateOrAddUserGroup({ id, scopeId: item.name });
if (res) {
initData();
}
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
}
}
initData();
};
function searchData(eve: Event) {
if (!(eve.target as HTMLInputElement).value) {
initData();
return;
}
const keyword = (eve.target as HTMLInputElement).value;
const tmpArr = userGroupList.value.filter((ele) => ele.name.includes(keyword));
userGroupList.value = tmpArr;
}
onMounted(() => {
initData();
});
</script>
<style scoped lang="less">

View File

@ -3,21 +3,23 @@
:popup-visible="renameVisible"
:ok-text="t('system.userGroup.confirm')"
:cancel-text="t('system.userGroup.cancel')"
:blur-to-close="false"
:click-to-close="false"
:click-outside-to-close="false"
@ok="handleSubmit('rename')"
@cancel="handleRenameCancel"
@ok="handleSubmit"
@cancel="handleCancel"
@popup-visible-change="() => (form.name = '')"
>
<template #icon>{{ null }}</template>
<template #content>
<a-form :model="form" :label-col-props="{ span: 0 }" :wrapper-col-props="{ span: 24 }">
<a-form ref="formRef" :model="form" :label-col-props="{ span: 0 }" :wrapper-col-props="{ span: 24 }">
<a-form-item>
<div class="title">{{ message.title }}</div>
</a-form-item>
<a-form-item field="name" :rules="[{ required: true, message: message.rule }]">
<a-input v-model="form.name" />
<a-form-item field="name" :rules="[{ validator: validateName }]">
<a-input v-if="props.type === 'rename'" v-model="form.name" />
<a-select v-else v-model="form.name" class="w-[176px]">
<a-option value="SYSTEM">{{ t('system.userGroup.SYSTEM') }}</a-option>
<a-option value="ORGANIZATION">{{ t('system.userGroup.ORGANIZATION') }}</a-option>
<a-option value="PROJECT">{{ t('system.userGroup.PROJECT') }}</a-option>
</a-select>
</a-form-item>
</a-form>
</template>
@ -27,20 +29,48 @@
<script setup lang="ts">
import { useI18n } from '@/hooks/useI18n';
import { watchEffect, reactive, ref, computed } from 'vue';
import { CustomMoreActionItem, RenameType } from './type';
import { watchEffect, reactive, ref, computed, onUnmounted } from 'vue';
import { CustomMoreActionItem, RenameType, UserGroupItem } from './type';
import { ValidatedError } from '@arco-design/web-vue';
import useUserGroupStore from '@/store/modules/system/usergroup';
const { t } = useI18n();
const formRef = ref();
const form = reactive({
name: '',
});
const store = useUserGroupStore();
const props = defineProps<{
visible: boolean;
defaultName: string;
type: RenameType;
list: UserGroupItem[];
}>();
const validateName = (value: string, callback: (error?: string) => void) => {
if (props.type === 'rename') {
if (value === '') {
callback(t('system.userGroup.userGroupNameIsNotNone'));
} else {
if (value === props.defaultName) {
callback();
} else {
const isExist = props.list.some((item) => item.name === value);
if (isExist) {
callback(t('system.userGroup.userGroupNameIsExist', { name: value }));
}
}
callback();
}
} else if (value === '') {
callback(t('system.userGroup.userGroupAuthScopeIsNotNone'));
} else {
callback();
}
};
const message = computed(() => {
if (props.type === 'rename') {
return {
@ -55,22 +85,31 @@
});
const emit = defineEmits<{
(e: 'submit', value: CustomMoreActionItem): void;
(e: 'submit', value: CustomMoreActionItem): Promise<void>;
(e: 'cancel'): void;
}>();
const renameVisible = ref(props.visible);
const handleSubmit = (type: string) => {
// eslint-disable-next-line no-console
emit('submit', { eventKey: type, name: form.name });
const handleSubmit = () => {
formRef.value.validate((errors: undefined | Record<string, ValidatedError>) => {
if (!errors) {
emit('submit', { eventKey: props.type, name: form.name });
}
});
};
const handleRenameCancel = () => {
const handleCancel = () => {
form.name = '';
emit('cancel');
};
watchEffect(() => {
renameVisible.value = props.visible;
form.name = props.defaultName;
});
onUnmounted(() => {
handleCancel();
});
</script>
<style lang="less" scoped>

View File

@ -14,7 +14,28 @@ export interface CustomMoreActionItem {
name: string;
}
export interface PopVisibleItem {
[key: number]: boolean;
[key: string]: boolean;
}
export type RenameType = 'rename' | 'auth';
export interface UserGroupItem {
// 组ID
id: string;
// 组名称
name: string;
// 组描述
description: string;
// 是否是内置用户组
internal: true;
// 所属类型
type: string;
createTime: number;
updateTime: number;
// 创建人
createUser: string;
// 应用范围
scopeId: string;
// 自定义排序
pos: number;
}

View File

@ -17,17 +17,11 @@
<slot :name="key" v-bind="{ rowIndex, record, column }"></slot>
</template>
</a-table>
<div v-if="selectCurrent > 0" class="mt-[21px]">
<div v-if="selectCurrent > 0 && attrs.showSelectAll" class="mt-[21px]">
<batch-action
:select-row-count="selectCurrent"
@batch-export="emit('batchExport')"
@batch-edit="emit('batchEdit')"
@batch-move="emit('batchMoveTo')"
@batch-copy="emit('batchCopyTo')"
@batch-related="emit('batchRelated')"
@batch-generate="emit('batchGenerate')"
@batch-add-public="emit('batchAddPublic')"
@batch-delete="emit('batchDelete')"
:action-config="props.actionConfig"
@batch-action="(item: BatchActionParams) => emit('batchAction', item)"
@clear="selectionChange([], true)"
/>
</div>
@ -37,28 +31,19 @@
<script lang="ts" setup>
import { useSlots, useAttrs, computed, ref, onMounted } from 'vue';
import selectAll from './select-all.vue';
import { MsTableProps, SelectAllEnum, MsPaginationI } from './type';
import { MsTableProps, SelectAllEnum, MsPaginationI, BatchActionParams, BatchActionConfig } from './type';
import BatchAction from './batchAction.vue';
import type { TableData } from '@arco-design/web-vue';
const batchleft = ref('10px');
const props = defineProps({
selectedKeys: {
type: Array as unknown as () => (string | number)[],
default: () => [],
},
});
const props = defineProps<{
selectedKeys?: (string | number)[];
actionConfig?: BatchActionConfig;
}>();
const emit = defineEmits<{
(e: 'selectedChange', value: (string | number)[]): void;
(e: 'batchExport'): void;
(e: 'batchEdit'): void;
(e: 'batchMoveTo'): void;
(e: 'batchCopyTo'): void;
(e: 'batchRelated'): void;
(e: 'batchGenerate'): void;
(e: 'batchAddPublic'): void;
(e: 'batchDelete'): void;
(e: 'batchAction', value: BatchActionParams): void;
}>();
const isSelectAll = ref(false);
// -

View File

@ -1,19 +1,29 @@
<template>
<div class="ms-table__patch-action">
<div v-if="props.actionConfig" class="ms-table__patch-action">
<span class="title">{{ t('msTable.batch.selected', { count: props.selectRowCount }) }}</span>
<a-button class="ml-4" type="outline" @click="emit('batchExport')">{{ t('msTable.batch.export') }}</a-button>
<a-button class="ml-3" type="outline" @click="emit('batchEdit')">{{ t('msTable.batch.edit') }}</a-button>
<a-button class="ml-3" type="outline" @click="emit('batchMoveTo')">{{ t('msTable.batch.moveTo') }}</a-button>
<a-button class="ml-3" type="outline" @click="emit('batchCopyTo')">{{ t('msTable.batch.copyTo') }}</a-button>
<div class="relative top-[2px] ml-3 inline-block">
<template v-for="element in props.actionConfig.baseAction" :key="element.label">
<a-divider v-if="element.isDivider" class="mx-0 my-[6px]" />
<a-button
v-else
:class="{
'delete': element.danger,
'ml-4': true,
}"
type="outline"
@click="emit('batchAction', element)"
>{{ t(element.label as string) }}</a-button
>
</template>
<div v-if="props.actionConfig.moreAction" class="relative top-[2px] ml-3 inline-block">
<a-dropdown position="tr">
<a-button type="outline"><a-icon-more /></a-button>
<template #content>
<a-doption @click="emit('batchRelated')">{{ t('msTable.batch.related') }}</a-doption>
<a-doption @click="emit('batchGenerate')">{{ t('msTable.batch.generateDep') }}</a-doption>
<a-doption @click="emit('batchAddTo')">{{ t('msTable.batch.addPublic') }}</a-doption>
<a-divider margin="0" />
<a-doption class="delete" @click="emit('batchExport')">{{ t('msTable.batch.delete') }}</a-doption>
<template v-for="element in props.actionConfig.moreAction" :key="element.label">
<a-divider v-if="element.isDivider" margin="0" />
<a-doption v-else :value="element" :class="{ delete: element.danger }">{{
t(element.label as string)
}}</a-doption>
</template>
</template>
</a-dropdown>
</div>
@ -23,22 +33,15 @@
<script lang="ts" setup>
import { useI18n } from '@/hooks/useI18n';
import { BatchActionConfig, BatchActionParams } from './type';
const { t } = useI18n();
const props = defineProps({
selectRowCount: {
type: Number,
},
});
const props = defineProps<{
selectRowCount?: number;
actionConfig?: BatchActionConfig;
}>();
const emit = defineEmits<{
(e: 'batchExport'): void;
(e: 'batchEdit'): void;
(e: 'batchMoveTo'): void;
(e: 'batchCopyTo'): void;
(e: 'batchRelated'): void;
(e: 'batchGenerate'): void;
(e: 'batchAddTo'): void;
(e: 'batchDelete'): void;
(e: 'batchAction', value: BatchActionParams): void;
(e: 'clear'): void;
}>();
</script>

View File

@ -70,3 +70,14 @@ export enum SelectAllEnum {
export interface SortItem {
[key: string]: string;
}
export interface BatchActionParams {
label?: string;
eventTag?: string;
isDivider?: boolean;
danger?: boolean;
}
export interface BatchActionConfig {
baseAction: BatchActionParams[];
moreAction?: BatchActionParams[];
}

View File

@ -1,4 +1,4 @@
export interface ListItemI {
export interface APIListItemI {
id: number;
type: string;
receiver: string;
@ -19,10 +19,3 @@ export interface SortItem {
export interface FilterItem {
[key: string]: any;
}
export interface CommonList {
[x: string]: any;
pageSize: number;
total: number;
current: number;
list: ListItemI;
}

View File

@ -22,8 +22,7 @@ export interface TableQueryParams {
keyword?: string;
[key: string]: any;
}
export interface TableResult<T> {
export interface CommonList<T> {
[x: string]: any;
pageSize: number;
total: number;

View File

@ -2,4 +2,5 @@ export interface UserGroupState {
// 当前用户组名字
currentName: string;
currentTitle: string;
currentId: string;
}

View File

@ -5,6 +5,7 @@ const useUserGroupStore = defineStore('userGroup', {
state: (): UserGroupState => ({
currentName: '',
currentTitle: '',
currentId: '',
}),
getters: {
userGroupInfo(state: UserGroupState): UserGroupState {

View File

@ -1,6 +1,6 @@
<template>
<div class="h-[100vh] bg-white px-[20px] py-[16px] pb-0">
<ms-base-table v-bind="propsRes" v-on="propsEvent"> </ms-base-table>
<ms-base-table v-bind="propsRes" :action-config="actionConfig" v-on="propsEvent"> </ms-base-table>
</div>
<a-divider />
</template>
@ -8,7 +8,7 @@
<script lang="ts" setup>
import { onMounted } from 'vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import { MsTableColumn } from '@/components/pure/ms-table/type';
import { BatchActionConfig, MsTableColumn } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable';
import { getTableList } from '@/api/modules/api-test/index';
@ -92,6 +92,64 @@
},
];
const actionConfig: BatchActionConfig = {
baseAction: [
{
label: 'msTable.batch.export',
eventTag: 'batchExport',
isDivider: false,
danger: false,
},
{
label: 'msTable.batch.edit',
eventTag: 'batchEdit',
isDivider: false,
danger: false,
},
{
label: 'msTable.batch.moveTo',
eventTag: 'batchMoveTo',
isDivider: false,
danger: false,
},
{
label: 'msTable.batch.copyTo',
eventTag: 'batchCopyTo',
isDivider: false,
danger: false,
},
],
moreAction: [
{
label: 'msTable.batch.related',
eventTag: 'batchRelated',
isDivider: false,
danger: false,
},
{
label: 'msTable.batch.generateDep',
eventTag: 'batchGenerate',
isDivider: false,
danger: false,
},
{
label: 'msTable.batch.addPublic',
eventTag: 'batchAddTo',
isDivider: false,
danger: false,
},
{
isDivider: true,
},
{
label: 'msTable.batch.delete',
eventTag: 'batchDelete',
isDivider: false,
danger: true,
},
],
};
const { propsRes, propsEvent, loadList } = useTable(getTableList, {
columns,
scroll: { y: 750, x: 2000 },

View File

@ -25,6 +25,7 @@ export default {
revoke: 'revoke',
pleaseSelectUser: 'Please select user',
pleaseInputUserGroupName: 'Please input user group name,and not equal to system user group name',
userGroupNameIsExist: `Usergroup {name} is exist`,
pleaseSelectAuthScope: 'Please select auth scope',
userGroupNameIsNotNone: 'User group name is not none',
authScopeIsNotNone: 'Auth scope is not none',
@ -32,6 +33,13 @@ export default {
confirm: 'Confirm',
global: 'Global',
searchPlacehoder: 'Search by ID/Name',
SYSTEM: '系统',
PROJECT: '项目',
ORGANIZATION: '组织',
isDeleteUserGroup: 'Delete or not: {name}?',
beforeDeleteUserGroup:
'After deletion, the project data under the organization will be deleted together. Please operate with caution!',
confirmDelete: 'Confirm delete',
},
},
'system.user.createUser': 'Create User',

View File

@ -30,8 +30,15 @@ export default {
authScopeIsNotNone: '权限范围不能为空',
userIsNotNone: '成员不能为空',
pleaseInputUserGroupName: '请输入用户组名称,且不与其他用户组名称重复',
userGroupNameIsExist: `用户组{name}已存在`,
pleaseSelectAuthScope: '请选择用户组所属的权限范围',
searchPlacehoder: '通过ID/名称搜索',
SYSTEM: '系统',
PROJECT: '项目',
ORGANIZATION: '组织',
isDeleteUserGroup: '是否删除: {name}?',
beforeDeleteUserGroup: '删除后,该组织下的项目数据将一起删除,请谨慎操作!',
confirmDelete: '确认删除',
},
},
'system.user.createUser': '创建用户',

View File

@ -3,8 +3,8 @@
<div class="user-group-left">
<UserGroupLeft />
</div>
<div class="grow-1 overflow-x-scroll p-[24px]">
<div class="flex flex-row items-center justify-between">
<div class="grow-1 w-[100%] overflow-x-scroll p-[24px]">
<div class="grow-1 flex flex-row items-center justify-between">
<div class="title">{{ store.userGroupInfo.currentName }}</div>
<div class="flex items-center">
<a-input class="w-[240px]" :placeholder="t('system.userGroup.searchPlacehoder')">
@ -18,7 +18,7 @@
</a-radio-group>
</div>
</div>
<div class="mt-[16px]">
<div class="grow-1 mt-[16px]">
<user-table v-if="currentTable === 'user'" />
<auth-table v-if="currentTable === 'auth'" />
</div>