refactor(系统设置): 用户组重构
This commit is contained in:
parent
3d55d8c456
commit
6ee22eaddf
|
@ -19,10 +19,7 @@
|
|||
<MsUserSelector
|
||||
v-model:value="form.name"
|
||||
:type="UserRequesetTypeEnum.ORGANIZATION_USER_GROUP"
|
||||
:load-option-params="{
|
||||
roleId: store.currentId,
|
||||
organizationId: currentOrgId,
|
||||
}"
|
||||
:load-option-params="loadOptionParmas"
|
||||
disabled-key="checkRoleFlag"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
@ -41,20 +38,21 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { reactive, ref, watchEffect, computed } from 'vue';
|
||||
import useUserGroupStore from '@/store/modules/setting/organization/usergroup';
|
||||
import { reactive, ref, watchEffect, computed, inject } from 'vue';
|
||||
import { useAppStore } from '@/store';
|
||||
import { addOrgUserToUserGroup } from '@/api/modules/setting/usergroup';
|
||||
import { addOrgUserToUserGroup, addUserToUserGroup } from '@/api/modules/setting/usergroup';
|
||||
import { Message, type FormInstance, type ValidatedError } from '@arco-design/web-vue';
|
||||
import MsUserSelector from '@/components/business/ms-user-selector/index.vue';
|
||||
import { UserRequesetTypeEnum } from '@/components/business/ms-user-selector/utils';
|
||||
import { AuthScopeEnum } from '@/enums/commonEnum';
|
||||
|
||||
const { t } = useI18n();
|
||||
const systemType = inject<AuthScopeEnum>('systemType');
|
||||
const props = defineProps<{
|
||||
visible: boolean;
|
||||
currentId: string;
|
||||
}>();
|
||||
|
||||
const store = useUserGroupStore();
|
||||
const appStore = useAppStore();
|
||||
const currentOrgId = computed(() => appStore.currentOrgId);
|
||||
|
||||
|
@ -64,6 +62,18 @@
|
|||
|
||||
const currentVisible = ref(props.visible);
|
||||
const loading = ref(false);
|
||||
const loadOptionParmas = computed(() => {
|
||||
if (systemType === AuthScopeEnum.SYSTEM) {
|
||||
return {
|
||||
roleId: props.currentId,
|
||||
};
|
||||
}
|
||||
return {
|
||||
roleId: props.currentId,
|
||||
organizationId: currentOrgId.value,
|
||||
};
|
||||
// TODO 项目-用户组
|
||||
});
|
||||
|
||||
const form = reactive({
|
||||
name: [],
|
||||
|
@ -90,11 +100,16 @@
|
|||
}
|
||||
try {
|
||||
loading.value = true;
|
||||
await addOrgUserToUserGroup({
|
||||
userRoleId: store.currentId,
|
||||
userIds: form.name,
|
||||
organizationId: currentOrgId.value,
|
||||
});
|
||||
if (systemType === AuthScopeEnum.SYSTEM) {
|
||||
await addUserToUserGroup({ roleId: props.currentId, userIds: form.name });
|
||||
}
|
||||
if (systemType === AuthScopeEnum.ORGANIZATION) {
|
||||
await addOrgUserToUserGroup({
|
||||
userRoleId: props.currentId,
|
||||
userIds: form.name,
|
||||
organizationId: currentOrgId.value,
|
||||
});
|
||||
}
|
||||
handleCancel(true);
|
||||
Message.success(t('common.addSuccess'));
|
||||
} catch (e) {
|
|
@ -51,11 +51,22 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { RenderFunction, VNodeChild, ref, watchEffect, computed } from 'vue';
|
||||
import { RenderFunction, VNodeChild, ref, watchEffect, computed, inject } from 'vue';
|
||||
import { Message, type TableColumnData, type TableData } from '@arco-design/web-vue';
|
||||
import useUserGroupStore from '@/store/modules/setting/organization/usergroup';
|
||||
import { getGlobalUSetting, getOrgUSetting, saveOrgUSetting } from '@/api/modules/setting/usergroup';
|
||||
import { UserGroupAuthSetting, AuthTableItem, type AuthScopeType, SavePermissions } from '@/models/setting/usergroup';
|
||||
import {
|
||||
getGlobalUSetting,
|
||||
getOrgUSetting,
|
||||
saveGlobalUSetting,
|
||||
saveOrgUSetting,
|
||||
} from '@/api/modules/setting/usergroup';
|
||||
import {
|
||||
UserGroupAuthSetting,
|
||||
AuthTableItem,
|
||||
type AuthScopeType,
|
||||
SavePermissions,
|
||||
CurrentUserGroupItem,
|
||||
} from '@/models/setting/usergroup';
|
||||
import { AuthScopeEnum } from '@/enums/commonEnum';
|
||||
|
||||
export declare type OperationName = 'selection-checkbox' | 'selection-radio' | 'expand' | 'drag-handle';
|
||||
|
||||
|
@ -68,8 +79,13 @@
|
|||
isLastLeftFixed?: boolean;
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
current: CurrentUserGroupItem;
|
||||
}>();
|
||||
|
||||
const systemType = inject<AuthScopeEnum>('systemType');
|
||||
|
||||
const loading = ref(false);
|
||||
const store = useUserGroupStore();
|
||||
|
||||
const systemSpan = ref(1);
|
||||
const projectSpan = ref(1);
|
||||
|
@ -83,7 +99,7 @@
|
|||
const canSave = ref(false);
|
||||
// 内部用户不可编辑
|
||||
const currentInternal = computed(() => {
|
||||
return store.userGroupInfo.currentInternal;
|
||||
return props.current.internal;
|
||||
});
|
||||
|
||||
const dataSpanMethod = (data: {
|
||||
|
@ -241,11 +257,19 @@
|
|||
try {
|
||||
let res: UserGroupAuthSetting[] = [];
|
||||
loading.value = true;
|
||||
if (internal) {
|
||||
if (systemType === AuthScopeEnum.SYSTEM) {
|
||||
res = await getGlobalUSetting(id);
|
||||
} else if (systemType === AuthScopeEnum.ORGANIZATION) {
|
||||
if (internal) {
|
||||
res = await getGlobalUSetting(id);
|
||||
} else {
|
||||
res = await getOrgUSetting(id);
|
||||
}
|
||||
} else {
|
||||
// TODO 项目的
|
||||
res = await getOrgUSetting(id);
|
||||
}
|
||||
|
||||
tableData.value = transformData(res);
|
||||
handleAllChange(true);
|
||||
} catch (error) {
|
||||
|
@ -271,12 +295,21 @@
|
|||
});
|
||||
});
|
||||
try {
|
||||
await saveOrgUSetting({
|
||||
userRoleId: store.currentId,
|
||||
permissions,
|
||||
});
|
||||
if (systemType === AuthScopeEnum.SYSTEM) {
|
||||
await saveGlobalUSetting({
|
||||
userRoleId: props.current.id,
|
||||
permissions,
|
||||
});
|
||||
} else if (systemType === AuthScopeEnum.ORGANIZATION) {
|
||||
await saveOrgUSetting({
|
||||
userRoleId: props.current.id,
|
||||
permissions,
|
||||
});
|
||||
} else {
|
||||
// TODO 项目的
|
||||
}
|
||||
Message.success(t('common.saveSuccess'));
|
||||
initData(store.currentId, store.currentInternal);
|
||||
initData(props.current.id, props.current.internal);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
|
@ -285,14 +318,14 @@
|
|||
|
||||
// 恢复默认值
|
||||
const handleReset = () => {
|
||||
if (store.currentId) {
|
||||
initData(store.currentId, store.currentInternal);
|
||||
if (props.current.id) {
|
||||
initData(props.current.id, props.current.internal);
|
||||
}
|
||||
};
|
||||
|
||||
watchEffect(() => {
|
||||
if (store.currentId) {
|
||||
initData(store.currentId, store.currentInternal);
|
||||
if (props.current.id) {
|
||||
initData(props.current.id, props.current.internal);
|
||||
}
|
||||
});
|
||||
defineExpose({
|
||||
|
@ -323,4 +356,3 @@
|
|||
}
|
||||
}
|
||||
</style>
|
||||
@/store/modules/setting/system/usergroup
|
|
@ -114,6 +114,7 @@
|
|||
if (systemType === AuthScopeEnum.SYSTEM) {
|
||||
res = await updateOrAddUserGroup({ id: props.id, name: form.name, type: props.authScope });
|
||||
} else if (systemType === AuthScopeEnum.ORGANIZATION) {
|
||||
debugger;
|
||||
// 组织用户组
|
||||
res = await updateOrAddOrgUserGroup({
|
||||
id: props.id,
|
|
@ -63,7 +63,7 @@
|
|||
>
|
||||
</a-tooltip>
|
||||
<div v-if="element.id === currentId && !element.internal" class="flex flex-row items-center gap-[8px]">
|
||||
<MsMoreAction :list="addMemberActionItem" @select="handleAddMember">
|
||||
<MsMoreAction v-if="element.type === systemType" :list="addMemberActionItem" @select="handleAddMember">
|
||||
<div class="icon-button">
|
||||
<MsIcon type="icon-icon_add_outlined" size="16" />
|
||||
</div>
|
||||
|
@ -141,7 +141,7 @@
|
|||
>
|
||||
</a-tooltip>
|
||||
<div v-if="element.id === currentId && !element.internal" class="flex flex-row items-center gap-[8px]">
|
||||
<MsMoreAction :list="addMemberActionItem" @select="handleAddMember">
|
||||
<MsMoreAction v-if="element.type === systemType" :list="addMemberActionItem" @select="handleAddMember">
|
||||
<div class="icon-button">
|
||||
<MsIcon type="icon-icon_add_outlined" size="16" />
|
||||
</div>
|
||||
|
@ -158,11 +158,11 @@
|
|||
</div>
|
||||
</CreateUserGroupPopup>
|
||||
</div>
|
||||
<a-divider class="my-[0px] mt-[6px]" />
|
||||
<a-divider v-if="showSystem" class="my-[0px] mt-[6px]" />
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
<div v-if="showProject" class="mt-2">
|
||||
<CreateUserGroupPopup
|
||||
:list="projectUserGroupList"
|
||||
:visible="projectUserGroupVisible"
|
||||
|
@ -219,7 +219,7 @@
|
|||
>
|
||||
</a-tooltip>
|
||||
<div v-if="element.id === currentId && !element.internal" class="flex flex-row items-center gap-[8px]">
|
||||
<MsMoreAction :list="addMemberActionItem" @select="handleAddMember">
|
||||
<MsMoreAction v-if="element.type === systemType" :list="addMemberActionItem" @select="handleAddMember">
|
||||
<div class="icon-button">
|
||||
<MsIcon type="icon-icon_add_outlined" size="16" />
|
||||
</div>
|
||||
|
@ -240,7 +240,7 @@
|
|||
</Transition>
|
||||
</div>
|
||||
|
||||
<AddUserModal :visible="userModalVisible" @cancel="userModalVisible = false" />
|
||||
<AddUserModal :visible="userModalVisible" :current-id="currentItem.id" @cancel="userModalVisible = false" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -248,17 +248,17 @@
|
|||
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import MsMoreAction from '@/components/pure/ms-table-more-action/index.vue';
|
||||
import { UserGroupItem, PopVisible, PopVisibleItem } from '@/models/setting/usergroup';
|
||||
import { UserGroupItem, PopVisible, PopVisibleItem, CurrentUserGroupItem } from '@/models/setting/usergroup';
|
||||
import {
|
||||
getUserGroupList,
|
||||
deleteUserGroup,
|
||||
getOrgUserGroupList,
|
||||
getProjectUserGroupList,
|
||||
deleteOrgUserGroup,
|
||||
} from '@/api/modules/setting/usergroup';
|
||||
import { computed, onMounted, ref, inject } from 'vue';
|
||||
import CreateUserGroupPopup from './createOrUpdateUserGroup.vue';
|
||||
import AddUserModal from './addUserModal.vue';
|
||||
import useUserGroupStore from '@/store/modules/setting/system/usergroup';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import useModal from '@/hooks/useModal';
|
||||
import { characterLimit } from '@/utils';
|
||||
|
@ -267,7 +267,9 @@
|
|||
|
||||
const { t } = useI18n();
|
||||
|
||||
const store = useUserGroupStore();
|
||||
const emit = defineEmits<{
|
||||
(e: 'onSelect', element: UserGroupItem): void;
|
||||
}>();
|
||||
const appStore = useAppStore();
|
||||
const { openModal } = useModal();
|
||||
|
||||
|
@ -275,11 +277,14 @@
|
|||
|
||||
const showSystem = computed(() => systemType === AuthScopeEnum.SYSTEM);
|
||||
const showOrg = computed(() => systemType === AuthScopeEnum.SYSTEM || systemType === AuthScopeEnum.ORGANIZATION);
|
||||
const showProject = computed(() => systemType === AuthScopeEnum.SYSTEM || systemType === AuthScopeEnum.PROJECT);
|
||||
|
||||
// 用户组列表
|
||||
const userGroupList = ref<UserGroupItem[]>([]);
|
||||
|
||||
const currentId = ref('');
|
||||
const currentItem = ref<CurrentUserGroupItem>({ id: '', name: '', internal: false, type: AuthScopeEnum.SYSTEM });
|
||||
const currentId = computed(() => currentItem.value.id);
|
||||
const currentName = computed(() => currentItem.value.name);
|
||||
|
||||
const userModalVisible = ref(false);
|
||||
|
||||
|
@ -343,14 +348,8 @@
|
|||
// 点击用户组列表
|
||||
const handleListItemClick = (element: UserGroupItem) => {
|
||||
const { id, name, type, internal } = element;
|
||||
currentId.value = id;
|
||||
store.setInfo({
|
||||
currentName: name,
|
||||
currentTitle: type,
|
||||
currentId: id,
|
||||
currentType: type,
|
||||
currentInternal: internal,
|
||||
});
|
||||
currentItem.value = { id, name, type, internal };
|
||||
emit('onSelect', element);
|
||||
};
|
||||
|
||||
// 用户组数据初始化
|
||||
|
@ -394,7 +393,7 @@
|
|||
if (item.eventTag === 'delete') {
|
||||
openModal({
|
||||
type: 'error',
|
||||
title: t('system.userGroup.isDeleteUserGroup', { name: characterLimit(store.currentName) }),
|
||||
title: t('system.userGroup.isDeleteUserGroup', { name: characterLimit(currentName.value) }),
|
||||
content: t('system.userGroup.beforeDeleteUserGroup'),
|
||||
okText: t('system.userGroup.confirmDelete'),
|
||||
cancelText: t('system.userGroup.cancel'),
|
||||
|
@ -403,7 +402,13 @@
|
|||
},
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
await deleteUserGroup(id);
|
||||
if (systemType === AuthScopeEnum.SYSTEM) {
|
||||
await deleteUserGroup(id);
|
||||
}
|
||||
if (systemType === AuthScopeEnum.ORGANIZATION) {
|
||||
await deleteOrgUserGroup(id);
|
||||
}
|
||||
// TODO 项目用户组删除用户组
|
||||
Message.success(t('system.user.deleteUserSuccess'));
|
||||
initData();
|
||||
} catch (error) {
|
|
@ -9,7 +9,7 @@
|
|||
/>
|
||||
</template>
|
||||
</MsBaseTable>
|
||||
<AddUserModal :visible="userVisible" @cancel="handleAddUserModalCancel" />
|
||||
<AddUserModal :current-id="props.current.id" :visible="userVisible" @cancel="handleAddUserModalCancel" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
@ -17,21 +17,28 @@
|
|||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import { useAppStore } from '@/store';
|
||||
import useUserGroupStore from '@/store/modules/setting/organization/usergroup';
|
||||
import { watchEffect, ref, computed } from 'vue';
|
||||
import { postOrgUserByUserGroup, deleteOrgUserFromUserGroup } from '@/api/modules/setting/usergroup';
|
||||
import { UserTableItem } from '@/models/setting/usergroup';
|
||||
import { watchEffect, ref, computed, inject } from 'vue';
|
||||
import {
|
||||
postOrgUserByUserGroup,
|
||||
deleteOrgUserFromUserGroup,
|
||||
postUserByUserGroup,
|
||||
deleteUserFromUserGroup,
|
||||
} from '@/api/modules/setting/usergroup';
|
||||
import { CurrentUserGroupItem, UserTableItem } from '@/models/setting/usergroup';
|
||||
import { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import AddUserModal from './addUserModal.vue';
|
||||
import MsRemoveButton from '@/components/business/ms-remove-button/MsRemoveButton.vue';
|
||||
import { AuthScopeEnum } from '@/enums/commonEnum';
|
||||
|
||||
const systemType = inject<AuthScopeEnum>('systemType');
|
||||
|
||||
const { t } = useI18n();
|
||||
const store = useUserGroupStore();
|
||||
const appStore = useAppStore();
|
||||
const currentOrgId = computed(() => appStore.currentOrgId);
|
||||
const userVisible = ref(false);
|
||||
const props = defineProps<{
|
||||
keyword: string;
|
||||
current: CurrentUserGroupItem;
|
||||
}>();
|
||||
|
||||
const userGroupUsercolumns: MsTableColumn = [
|
||||
|
@ -55,7 +62,16 @@
|
|||
},
|
||||
];
|
||||
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, setKeyword } = useTable(postOrgUserByUserGroup, {
|
||||
const getRequestBySystemType = () => {
|
||||
if (systemType === AuthScopeEnum.SYSTEM) {
|
||||
return postUserByUserGroup;
|
||||
}
|
||||
|
||||
return postOrgUserByUserGroup;
|
||||
// TODO: 项目
|
||||
};
|
||||
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, setKeyword } = useTable(getRequestBySystemType(), {
|
||||
columns: userGroupUsercolumns,
|
||||
scroll: { y: 'auto', x: '600px' },
|
||||
selectable: false,
|
||||
|
@ -70,11 +86,16 @@
|
|||
};
|
||||
const handleRemove = async (record: UserTableItem) => {
|
||||
try {
|
||||
await deleteOrgUserFromUserGroup({
|
||||
organizationId: currentOrgId.value,
|
||||
userRoleId: store.currentId,
|
||||
userIds: [record.id],
|
||||
});
|
||||
if (systemType === AuthScopeEnum.SYSTEM) {
|
||||
await deleteUserFromUserGroup(record.id);
|
||||
} else if (systemType === AuthScopeEnum.ORGANIZATION) {
|
||||
await deleteOrgUserFromUserGroup({
|
||||
organizationId: currentOrgId.value,
|
||||
userRoleId: props.current.id,
|
||||
userIds: [record.id],
|
||||
});
|
||||
}
|
||||
// TODO 项目-用户组
|
||||
await fetchData();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
@ -91,8 +112,13 @@
|
|||
userVisible.value = false;
|
||||
};
|
||||
watchEffect(() => {
|
||||
if (store.currentId && currentOrgId.value) {
|
||||
setLoadListParams({ userRoleId: store.currentId, organizationId: currentOrgId.value });
|
||||
if (props.current.id && currentOrgId.value) {
|
||||
if (systemType === AuthScopeEnum.SYSTEM) {
|
||||
setLoadListParams({ roleId: props.current.id });
|
||||
} else if (systemType === AuthScopeEnum.ORGANIZATION) {
|
||||
setLoadListParams({ userRoleId: props.current.id, organizationId: currentOrgId.value });
|
||||
}
|
||||
// TODO 项目-用户组
|
||||
fetchData();
|
||||
}
|
||||
});
|
|
@ -1,106 +0,0 @@
|
|||
<template>
|
||||
<a-modal
|
||||
v-model:visible="currentVisible"
|
||||
class="ms-modal-form ms-modal-medium"
|
||||
width="680px"
|
||||
text-align="start"
|
||||
:ok-text="t('system.userGroup.add')"
|
||||
unmount-on-close
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<template #title> {{ t('system.userGroup.addUser') }} </template>
|
||||
<div class="form">
|
||||
<a-form ref="formRef" :model="form" size="large" :style="{ width: '600px' }" layout="vertical">
|
||||
<a-form-item
|
||||
field="name"
|
||||
:label="t('system.userGroup.user')"
|
||||
:rules="[{ required: true, message: t('system.userGroup.pleaseSelectUser') }]"
|
||||
asterisk-position="end"
|
||||
>
|
||||
<MsUserSelector
|
||||
v-model:value="form.name"
|
||||
disabled-key="exclude"
|
||||
:load-option-params="{ roleId: store.currentId }"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button type="secondary" :loading="loading" @click="handleCancel">
|
||||
{{ t('common.cancel') }}
|
||||
</a-button>
|
||||
<a-button type="primary" :loading="loading" :disabled="form.name.length === 0" @click="handleBeforeOk">
|
||||
{{ t('common.add') }}
|
||||
</a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { reactive, ref, watchEffect } from 'vue';
|
||||
import useUserGroupStore from '@/store/modules/setting/system/usergroup';
|
||||
import { addUserToUserGroup } from '@/api/modules/setting/usergroup';
|
||||
import type { FormInstance, ValidatedError } from '@arco-design/web-vue';
|
||||
import MsUserSelector from '@/components/business/ms-user-selector/index.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
visible: boolean;
|
||||
}>();
|
||||
|
||||
const store = useUserGroupStore();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'cancel'): void;
|
||||
(e: 'submit', value: string[]): void;
|
||||
}>();
|
||||
|
||||
const currentVisible = ref(props.visible);
|
||||
const loading = ref(false);
|
||||
|
||||
const form = reactive({
|
||||
name: [],
|
||||
});
|
||||
|
||||
const labelCache = new Map();
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
|
||||
watchEffect(() => {
|
||||
currentVisible.value = props.visible;
|
||||
});
|
||||
|
||||
const handleCancel = () => {
|
||||
labelCache.clear();
|
||||
form.name = [];
|
||||
emit('cancel');
|
||||
};
|
||||
|
||||
const handleBeforeOk = () => {
|
||||
formRef.value?.validate(async (errors: undefined | Record<string, ValidatedError>) => {
|
||||
if (errors) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
loading.value = true;
|
||||
await addUserToUserGroup({ roleId: store.currentId, userIds: form.name });
|
||||
handleCancel();
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(e);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.option-name {
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
.option-email {
|
||||
color: var(--color-text-4);
|
||||
}
|
||||
</style>
|
|
@ -39,6 +39,16 @@ export interface UserGroupItem {
|
|||
// 自定义排序
|
||||
pos: number;
|
||||
}
|
||||
export interface CurrentUserGroupItem {
|
||||
// 组ID
|
||||
id: string;
|
||||
// 组名称
|
||||
name: string;
|
||||
// 所属类型
|
||||
type: AuthScopeEnum;
|
||||
// 是否是内置用户组
|
||||
internal: boolean;
|
||||
}
|
||||
|
||||
export interface SystemUserGroupParams {
|
||||
id?: string; // 组ID
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
import { defineStore } from 'pinia';
|
||||
import { UserGroupState } from '../types';
|
||||
|
||||
const useOrgUserGroupStore = defineStore('orgUserGroup', {
|
||||
state: (): UserGroupState => ({
|
||||
currentName: '',
|
||||
currentTitle: '',
|
||||
currentId: '',
|
||||
currentType: '',
|
||||
currentInternal: false,
|
||||
collapse: true,
|
||||
}),
|
||||
getters: {
|
||||
userGroupInfo(state: UserGroupState): UserGroupState {
|
||||
return state;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
// 设置当前用户组信息
|
||||
setInfo(partial: Partial<UserGroupState>) {
|
||||
this.$patch(partial);
|
||||
},
|
||||
// 设置用户组菜单开启关闭
|
||||
setCollapse(collapse: boolean) {
|
||||
this.collapse = collapse;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default useOrgUserGroupStore;
|
|
@ -1,30 +0,0 @@
|
|||
import { defineStore } from 'pinia';
|
||||
import { UserGroupState } from '../types';
|
||||
|
||||
const useProjectUserGroupStore = defineStore('projectUserGroup', {
|
||||
state: (): UserGroupState => ({
|
||||
currentName: '',
|
||||
currentTitle: '',
|
||||
currentId: '',
|
||||
currentType: '',
|
||||
currentInternal: false,
|
||||
collapse: true,
|
||||
}),
|
||||
getters: {
|
||||
userGroupInfo(state: UserGroupState): UserGroupState {
|
||||
return state;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
// 设置当前用户组信息
|
||||
setInfo(partial: Partial<UserGroupState>) {
|
||||
this.$patch(partial);
|
||||
},
|
||||
// 设置用户组菜单开启关闭
|
||||
setCollapse(collapse: boolean) {
|
||||
this.collapse = collapse;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default useProjectUserGroupStore;
|
|
@ -1,30 +0,0 @@
|
|||
import { defineStore } from 'pinia';
|
||||
import { UserGroupState } from '../types';
|
||||
|
||||
const useSystemUserGroupStore = defineStore('systemUserGroup', {
|
||||
state: (): UserGroupState => ({
|
||||
currentName: '',
|
||||
currentTitle: '',
|
||||
currentId: '',
|
||||
currentType: '',
|
||||
currentInternal: false,
|
||||
collapse: true,
|
||||
}),
|
||||
getters: {
|
||||
userGroupInfo(state: UserGroupState): UserGroupState {
|
||||
return state;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
// 设置当前用户组信息
|
||||
setInfo(partial: Partial<UserGroupState>) {
|
||||
this.$patch(partial);
|
||||
},
|
||||
// 设置用户组菜单开启关闭
|
||||
setCollapse(collapse: boolean) {
|
||||
this.collapse = collapse;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default useSystemUserGroupStore;
|
|
@ -1,127 +0,0 @@
|
|||
<template>
|
||||
<a-popover :popup-visible="currentVisible" position="bl" trigger="click" class="w-[276px]">
|
||||
<template #content>
|
||||
<div class="form">
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
size="large"
|
||||
layout="vertical"
|
||||
:label-col-props="{ span: 0 }"
|
||||
:wrapper-col-props="{ span: 24 }"
|
||||
>
|
||||
<a-form-item>
|
||||
<div class="text-[14px] text-[var(--color-text-1)]">{{
|
||||
props.id ? t('system.userGroup.rename') : t('system.userGroup.createUserGroup')
|
||||
}}</div>
|
||||
</a-form-item>
|
||||
<a-form-item field="name" :rules="[{ validator: validateName }]">
|
||||
<a-input
|
||||
v-model="form.name"
|
||||
class="w-[228px]"
|
||||
:placeholder="t('system.userGroup.pleaseInputUserGroupName')"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
<div class="flex flex-row flex-nowrap justify-end gap-2">
|
||||
<a-button type="secondary" size="mini" :disabled="loading" @click="handleCancel">
|
||||
{{ t('common.cancel') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
size="mini"
|
||||
:loading="loading"
|
||||
:disabled="form.name.length === 0"
|
||||
@click="handleBeforeOk"
|
||||
>
|
||||
{{ props.id ? t('common.rename') : t('common.create') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</template>
|
||||
<slot></slot>
|
||||
</a-popover>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { reactive, ref, computed, watchEffect } from 'vue';
|
||||
import { UserGroupItem } from '@/models/setting/usergroup';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import type { FormInstance, ValidatedError } from '@arco-design/web-vue';
|
||||
import { updateOrAddOrgUserGroup } from '@/api/modules/setting/usergroup';
|
||||
import { useAppStore } from '@/store';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
id?: string;
|
||||
list: UserGroupItem[];
|
||||
visible: boolean;
|
||||
defaultName?: string;
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
(e: 'cancel', value: boolean): void;
|
||||
(e: 'search'): void;
|
||||
}>();
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
const currentVisible = ref(props.visible);
|
||||
|
||||
const form = reactive({
|
||||
name: '',
|
||||
});
|
||||
|
||||
const appStore = useAppStore();
|
||||
const currentOrgId = computed(() => appStore.currentOrgId);
|
||||
const loading = ref(false);
|
||||
|
||||
const validateName = (value: string | undefined, callback: (error?: string) => void) => {
|
||||
if (value === undefined || 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();
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
form.name = '';
|
||||
loading.value = false;
|
||||
emit('cancel', false);
|
||||
};
|
||||
|
||||
const handleBeforeOk = () => {
|
||||
formRef.value?.validate(async (errors: undefined | Record<string, ValidatedError>) => {
|
||||
if (errors) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await updateOrAddOrgUserGroup({ id: props.id, name: form.name, scopeId: currentOrgId.value });
|
||||
if (res) {
|
||||
Message.success(
|
||||
props.id ? t('system.userGroup.updateUserGroupSuccess') : t('system.userGroup.addUserGroupSuccess')
|
||||
);
|
||||
emit('search');
|
||||
handleCancel();
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
watchEffect(() => {
|
||||
currentVisible.value = props.visible;
|
||||
form.name = props.defaultName || '';
|
||||
});
|
||||
</script>
|
|
@ -1,244 +0,0 @@
|
|||
<template>
|
||||
<a-input-search
|
||||
class="w-[252px]"
|
||||
:placeholder="t('system.userGroup.searchHolder')"
|
||||
allow-clear
|
||||
@press-enter="enterData"
|
||||
@search="searchData"
|
||||
/>
|
||||
<div class="mt-2 flex flex-col">
|
||||
<div class="flex h-[38px] items-center px-[8px] leading-[24px]">
|
||||
<div class="text-[var(--color-text-input-border)]"> {{ t('system.userGroup.global') }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
v-for="element in globalUserGroupList"
|
||||
:key="element.id"
|
||||
class="flex h-[38px] cursor-pointer items-center px-[8px]"
|
||||
:class="{
|
||||
'bg-[rgb(var(--primary-1))]': element.id === currentId,
|
||||
}"
|
||||
@click="handleListItemClick(element)"
|
||||
>
|
||||
<div class="flex flex-row flex-nowrap">
|
||||
<div class="one-line-text max-w-[156px] text-[var(--color-text-1)]">{{ element.name }}</div>
|
||||
<div v-if="element.type" class="text-[var(--color-text-4)]"
|
||||
>({{ t(`system.userGroup.${element.type}`) }})</div
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a-divider class="mt-2" />
|
||||
<div class="mt-2 flex flex-col">
|
||||
<AddOrUpdateUserGroupPopup
|
||||
:visible="addUserGroupVisible"
|
||||
:list="customUserGroupList"
|
||||
@cancel="handleAddUserGroupCancel"
|
||||
@search="initData"
|
||||
>
|
||||
<div class="flex h-[38px] items-center justify-between px-[8px] leading-[24px]">
|
||||
<div class="text-[var(--color-text-input-border)]"> {{ t('system.userGroup.custom') }}</div>
|
||||
<div class="cursor-pointer text-[rgb(var(--primary-5))]"
|
||||
><icon-plus-circle-fill style="font-size: 20px" @click="addUserGroup"
|
||||
/></div>
|
||||
</div>
|
||||
</AddOrUpdateUserGroupPopup>
|
||||
<div>
|
||||
<div
|
||||
v-for="element in customUserGroupList"
|
||||
:key="element.id"
|
||||
class="flex h-[38px] cursor-pointer items-center"
|
||||
:class="{ 'bg-[rgb(var(--primary-1))]': element.id === currentId }"
|
||||
@click="handleListItemClick(element)"
|
||||
>
|
||||
<AddOrUpdateUserGroupPopup
|
||||
:id="element.id"
|
||||
:visible="popVisible[element.id]"
|
||||
:default-name="popDefaultName"
|
||||
:list="customUserGroupList"
|
||||
@cancel="() => handlePopConfirmCancel(element.id)"
|
||||
>
|
||||
<div class="flex grow flex-row justify-between px-[8px]">
|
||||
<a-tooltip :content="element.name">
|
||||
<div class="flex flex-row flex-nowrap">
|
||||
<div class="one-line-text max-w-[156px] text-[var(--color-text-1)]">{{ element.name }}</div>
|
||||
<div v-if="element.type" class="text-[var(--color-text-4)]"
|
||||
>({{ t(`system.userGroup.${element.type}`) }})</div
|
||||
>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
<div v-if="element.id === currentId && !element.internal">
|
||||
<MsTableMoreAction :list="customAction" @select="(value) => handleMoreAction(value, element.id)" />
|
||||
</div>
|
||||
</div>
|
||||
</AddOrUpdateUserGroupPopup>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<AddUserModal :visible="addUserVisible" @cancel="addUserVisible = false" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { RenameType, UserGroupItem } from '@/models/setting/usergroup';
|
||||
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 AddOrUpdateUserGroupPopup from './addOrUpdateUserGroupPopup.vue';
|
||||
import useModal from '@/hooks/useModal';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import useUserGroupStore from '@/store/modules/setting/organization/usergroup';
|
||||
import { useAppStore } from '@/store';
|
||||
import { getOrgUserGroupList, deleteOrgUserGroup } from '@/api/modules/setting/usergroup';
|
||||
import { characterLimit } from '@/utils';
|
||||
|
||||
interface PopVisibleItem {
|
||||
[key: string]: boolean;
|
||||
}
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const store = useUserGroupStore();
|
||||
const appStore = useAppStore();
|
||||
const { openModal } = useModal();
|
||||
// 请求loading
|
||||
const currentId = ref('');
|
||||
const addUserVisible = ref(false);
|
||||
const addUserGroupVisible = ref(false);
|
||||
// 修改用户组名字,权限范围
|
||||
const popVisible = ref<PopVisibleItem>({});
|
||||
// 用户组和权限范围的状态
|
||||
const popType = ref<RenameType>('rename');
|
||||
const popDefaultName = ref('');
|
||||
// 用户列表
|
||||
const userGroupList = ref<UserGroupItem[]>([]);
|
||||
const currentOrgId = computed(() => appStore.currentOrgId);
|
||||
|
||||
const globalUserGroupList = computed(() => {
|
||||
return userGroupList.value.filter((ele) => ele.internal);
|
||||
});
|
||||
const customUserGroupList = computed(() => {
|
||||
return userGroupList.value.filter((ele) => !ele.internal);
|
||||
});
|
||||
|
||||
const customAction: ActionsItem[] = [
|
||||
{
|
||||
label: 'system.userGroup.rename',
|
||||
danger: false,
|
||||
eventTag: 'rename',
|
||||
},
|
||||
{
|
||||
isDivider: true,
|
||||
},
|
||||
{
|
||||
label: 'system.userGroup.delete',
|
||||
danger: true,
|
||||
eventTag: 'delete',
|
||||
},
|
||||
];
|
||||
|
||||
// 点击用户组列表
|
||||
const handleListItemClick = (element: UserGroupItem) => {
|
||||
const { id, name, type, internal } = element;
|
||||
currentId.value = id;
|
||||
store.setInfo({
|
||||
currentName: name,
|
||||
currentTitle: type,
|
||||
currentId: id,
|
||||
currentType: type,
|
||||
currentInternal: internal,
|
||||
});
|
||||
};
|
||||
|
||||
// 用户组数据初始化
|
||||
const initData = async () => {
|
||||
try {
|
||||
const res = await getOrgUserGroupList(currentOrgId.value);
|
||||
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);
|
||||
}
|
||||
};
|
||||
// 新增用户组
|
||||
const addUserGroup = () => {
|
||||
addUserGroupVisible.value = true;
|
||||
};
|
||||
// 关闭创建用户组
|
||||
const handleAddUserGroupCancel = () => {
|
||||
addUserGroupVisible.value = false;
|
||||
};
|
||||
// 点击更多操作
|
||||
const handleMoreAction = (item: ActionsItem, id: string) => {
|
||||
if (item.eventTag !== 'delete') {
|
||||
popType.value = item.eventTag as RenameType;
|
||||
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 {
|
||||
openModal({
|
||||
type: 'error',
|
||||
title: t('system.userGroup.isDeleteUserGroup', { name: characterLimit(store.currentName) }),
|
||||
content: t('system.userGroup.beforeDeleteUserGroup'),
|
||||
okText: t('system.userGroup.confirmDelete'),
|
||||
cancelText: t('system.userGroup.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
await deleteOrgUserGroup(id);
|
||||
Message.success(t('system.user.deleteUserSuccess'));
|
||||
initData();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 关闭confirm 弹窗
|
||||
const handlePopConfirmCancel = (id: string) => {
|
||||
popVisible.value = { ...popVisible.value, [id]: false };
|
||||
initData();
|
||||
};
|
||||
|
||||
function enterData(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;
|
||||
}
|
||||
function searchData(value: string) {
|
||||
if (!value) {
|
||||
initData();
|
||||
return;
|
||||
}
|
||||
const keyword = value;
|
||||
const tmpArr = userGroupList.value.filter((ele) => ele.name.includes(keyword));
|
||||
userGroupList.value = tmpArr;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initData();
|
||||
});
|
||||
</script>
|
|
@ -1,17 +1,17 @@
|
|||
<template>
|
||||
<MsCard simple>
|
||||
<div class="flex flex-row">
|
||||
<div class="user-group-left" :style="{ padding: collapse ? '24px 24px 24px 0' : 0 }">
|
||||
<user-group-left v-if="collapse" />
|
||||
<div class="user-group-left" :style="{ padding: leftCollapse ? '24px 24px 24px 0' : 0 }">
|
||||
<UserGroupLeft v-if="leftCollapse" @on-select="handleSelect" />
|
||||
<div class="usergroup-collapse" @click="handleCollapse">
|
||||
<MsIcon v-if="collapse" type="icon-icon_up-left_outlined" class="icon" />
|
||||
<MsIcon v-if="leftCollapse" type="icon-icon_up-left_outlined" class="icon" />
|
||||
<MsIcon v-else type="icon-icon_down-right_outlined" class="icon" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative w-[100%] overflow-x-scroll p-[24px]">
|
||||
<div class="flex flex-row items-center justify-between">
|
||||
<a-tooltip :content="store.userGroupInfo.currentName">
|
||||
<div class="one-line-text max-w-[300px]">{{ store.userGroupInfo.currentName }}</div>
|
||||
<a-tooltip :content="currentUserGroupItem.name">
|
||||
<div class="one-line-text max-w-[300px]">{{ currentUserGroupItem.name }}</div>
|
||||
</a-tooltip>
|
||||
<div class="flex items-center">
|
||||
<a-input-search
|
||||
|
@ -29,8 +29,13 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="mt-[16px]">
|
||||
<user-table v-if="currentTable === 'user' && couldShowUser" ref="userRef" :keyword="currentKeyword" />
|
||||
<auth-table v-if="currentTable === 'auth' && couldShowAuth" ref="authRef" />
|
||||
<UserTable
|
||||
v-if="currentTable === 'user' && couldShowUser"
|
||||
ref="userRef"
|
||||
:keyword="currentKeyword"
|
||||
:current="currentUserGroupItem"
|
||||
/>
|
||||
<AuthTable v-if="currentTable === 'auth' && couldShowAuth" ref="authRef" :current="currentUserGroupItem" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -48,21 +53,31 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, watchEffect, nextTick } from 'vue';
|
||||
import { ref, computed, watchEffect, nextTick, provide } from 'vue';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||
import useUserGroupStore from '@/store/modules/setting/organization/usergroup';
|
||||
import UserGroupLeft from './components/index.vue';
|
||||
import UserTable from './components/userTable.vue';
|
||||
import AuthTable from './components/authTable.vue';
|
||||
import UserGroupLeft from '@/components/business/ms-user-group-comp/msUserGroupLeft.vue';
|
||||
import UserTable from '@/components/business/ms-user-group-comp//userTable.vue';
|
||||
import AuthTable from '@/components/business/ms-user-group-comp/authTable.vue';
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import { useAppStore } from '@/store';
|
||||
import { AuthScopeEnum } from '@/enums/commonEnum';
|
||||
import { CurrentUserGroupItem } from '@/models/setting/usergroup';
|
||||
|
||||
// 注入系统层级
|
||||
provide('systemType', AuthScopeEnum.ORGANIZATION);
|
||||
const currentTable = ref('user');
|
||||
const leftCollapse = ref(true);
|
||||
|
||||
const { t } = useI18n();
|
||||
const currentKeyword = ref('');
|
||||
const currentUserGroupItem = ref<CurrentUserGroupItem>({
|
||||
id: '',
|
||||
name: '',
|
||||
type: AuthScopeEnum.ORGANIZATION,
|
||||
internal: true,
|
||||
});
|
||||
const authRef = ref<{
|
||||
handleReset: () => void;
|
||||
handleSave: () => void;
|
||||
|
@ -90,16 +105,19 @@
|
|||
tableSearch();
|
||||
};
|
||||
|
||||
const store = useUserGroupStore();
|
||||
const couldShowUser = computed(() => store.userGroupInfo.currentType === 'ORGANIZATION');
|
||||
const couldShowAuth = computed(() => store.userGroupInfo.currentId !== 'admin');
|
||||
const handleCollapse = () => {
|
||||
store.setCollapse(!store.collapse);
|
||||
const couldShowUser = computed(() => currentUserGroupItem.value.type === AuthScopeEnum.ORGANIZATION);
|
||||
const couldShowAuth = computed(() => currentUserGroupItem.value.id !== 'admin');
|
||||
|
||||
const handleSelect = (item: CurrentUserGroupItem) => {
|
||||
currentUserGroupItem.value = item;
|
||||
};
|
||||
|
||||
const handleCollapse = () => {
|
||||
leftCollapse.value = !leftCollapse.value;
|
||||
};
|
||||
const collapse = computed(() => store.collapse);
|
||||
const menuWidth = computed(() => {
|
||||
const width = appStore.menuCollapse ? 86 : appStore.menuWidth;
|
||||
if (store.collapse) {
|
||||
if (leftCollapse.value) {
|
||||
return width + 300;
|
||||
}
|
||||
return width + 24;
|
||||
|
|
|
@ -1,106 +0,0 @@
|
|||
<template>
|
||||
<a-modal
|
||||
v-model:visible="currentVisible"
|
||||
class="ms-modal-form ms-modal-medium"
|
||||
width="680px"
|
||||
text-align="start"
|
||||
:ok-text="t('system.userGroup.add')"
|
||||
unmount-on-close
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<template #title> {{ t('system.userGroup.addUser') }} </template>
|
||||
<div class="form">
|
||||
<a-form ref="formRef" :model="form" size="large" :style="{ width: '600px' }" layout="vertical">
|
||||
<a-form-item
|
||||
field="name"
|
||||
:label="t('system.userGroup.user')"
|
||||
:rules="[{ required: true, message: t('system.userGroup.pleaseSelectUser') }]"
|
||||
asterisk-position="end"
|
||||
>
|
||||
<MsUserSelector
|
||||
v-model:value="form.name"
|
||||
disabled-key="exclude"
|
||||
:load-option-params="{ roleId: store.currentId }"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button type="secondary" :loading="loading" @click="handleCancel">
|
||||
{{ t('common.cancel') }}
|
||||
</a-button>
|
||||
<a-button type="primary" :loading="loading" :disabled="form.name.length === 0" @click="handleBeforeOk">
|
||||
{{ t('common.add') }}
|
||||
</a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { reactive, ref, watchEffect } from 'vue';
|
||||
import useUserGroupStore from '@/store/modules/setting/system/usergroup';
|
||||
import { addUserToUserGroup } from '@/api/modules/setting/usergroup';
|
||||
import type { FormInstance, ValidatedError } from '@arco-design/web-vue';
|
||||
import MsUserSelector from '@/components/business/ms-user-selector/index.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
visible: boolean;
|
||||
}>();
|
||||
|
||||
const store = useUserGroupStore();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'cancel'): void;
|
||||
(e: 'submit', value: string[]): void;
|
||||
}>();
|
||||
|
||||
const currentVisible = ref(props.visible);
|
||||
const loading = ref(false);
|
||||
|
||||
const form = reactive({
|
||||
name: [],
|
||||
});
|
||||
|
||||
const labelCache = new Map();
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
|
||||
watchEffect(() => {
|
||||
currentVisible.value = props.visible;
|
||||
});
|
||||
|
||||
const handleCancel = () => {
|
||||
labelCache.clear();
|
||||
form.name = [];
|
||||
emit('cancel');
|
||||
};
|
||||
|
||||
const handleBeforeOk = () => {
|
||||
formRef.value?.validate(async (errors: undefined | Record<string, ValidatedError>) => {
|
||||
if (errors) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
loading.value = true;
|
||||
await addUserToUserGroup({ roleId: store.currentId, userIds: form.name });
|
||||
handleCancel();
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(e);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.option-name {
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
.option-email {
|
||||
color: var(--color-text-4);
|
||||
}
|
||||
</style>
|
|
@ -1,318 +0,0 @@
|
|||
<template>
|
||||
<div class="usergroup-auth-table">
|
||||
<a-table
|
||||
:span-method="dataSpanMethod"
|
||||
:scroll="{ y: '500px', x: '800px' }"
|
||||
:data="tableData"
|
||||
:loading="loading"
|
||||
:bordered="{ wrapper: true, cell: true }"
|
||||
size="small"
|
||||
:pagination="false"
|
||||
>
|
||||
<template #columns>
|
||||
<a-table-column :width="100" :title="t('system.userGroup.function')" data-index="ability" />
|
||||
<a-table-column :width="150" :title="t('system.userGroup.operationObject')" data-index="operationObject" />
|
||||
<a-table-column :title="t('system.userGroup.auth')">
|
||||
<template #cell="{ record, rowIndex }">
|
||||
<a-checkbox-group v-model="record.perChecked" @change="(v) => handleCellAuthChange(v, rowIndex)">
|
||||
<a-checkbox
|
||||
v-for="item in record.permissions"
|
||||
:key="item.id"
|
||||
:disabled="item.license || currentInternal"
|
||||
:value="item.id"
|
||||
>{{ t(item.name) }}</a-checkbox
|
||||
>
|
||||
</a-checkbox-group>
|
||||
</template>
|
||||
</a-table-column>
|
||||
<a-table-column :width="50" fixed="right" align="center" :bordered="false">
|
||||
<template #title>
|
||||
<a-checkbox
|
||||
v-if="tableData && tableData?.length > 0"
|
||||
:model-value="allChecked"
|
||||
:indeterminate="allIndeterminate"
|
||||
:disabled="currentInternal"
|
||||
@change="handleAllAuthChangeByCheckbox"
|
||||
></a-checkbox>
|
||||
</template>
|
||||
<template #cell="{ record, rowIndex }">
|
||||
<a-checkbox
|
||||
:model-value="record.enable"
|
||||
:indeterminate="record.indeterminate"
|
||||
:disabled="currentInternal"
|
||||
@change="(value) => handleRowAuthChange(value, rowIndex)"
|
||||
/>
|
||||
</template>
|
||||
</a-table-column>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { RenderFunction, VNodeChild, ref, watchEffect, computed } from 'vue';
|
||||
import { type TableColumnData, type TableData } from '@arco-design/web-vue';
|
||||
import useUserGroupStore from '@/store/modules/setting/system/usergroup';
|
||||
import { getGlobalUSetting, saveGlobalUSetting } from '@/api/modules/setting/usergroup';
|
||||
import { UserGroupAuthSetting, AuthTableItem, type AuthScopeType, SavePermissions } from '@/models/setting/usergroup';
|
||||
|
||||
export declare type OperationName = 'selection-checkbox' | 'selection-radio' | 'expand' | 'drag-handle';
|
||||
|
||||
export interface TableOperationColumn {
|
||||
name: OperationName | string;
|
||||
title?: string | RenderFunction;
|
||||
width?: number;
|
||||
fixed?: boolean;
|
||||
render?: (record: TableData) => VNodeChild;
|
||||
isLastLeftFixed?: boolean;
|
||||
}
|
||||
|
||||
const loading = ref(false);
|
||||
const store = useUserGroupStore();
|
||||
|
||||
const systemSpan = ref(1);
|
||||
const projectSpan = ref(1);
|
||||
const organizationSpan = ref(1);
|
||||
// 表格的总全选
|
||||
const allChecked = ref(false);
|
||||
const allIndeterminate = ref(false);
|
||||
|
||||
const tableData = ref<AuthTableItem[]>();
|
||||
// 是否可以保存
|
||||
const canSave = ref(false);
|
||||
// 内部用户不可编辑
|
||||
const currentInternal = computed(() => {
|
||||
return store.userGroupInfo.currentInternal;
|
||||
});
|
||||
|
||||
const dataSpanMethod = (data: {
|
||||
record: TableData;
|
||||
column: TableColumnData | TableOperationColumn;
|
||||
rowIndex: number;
|
||||
columnIndex: number;
|
||||
}) => {
|
||||
const { record, column } = data;
|
||||
if ((column as TableColumnData).dataIndex === 'ability') {
|
||||
if (record.isSystem) {
|
||||
return {
|
||||
rowspan: systemSpan.value,
|
||||
};
|
||||
}
|
||||
if (record.isOrganization) {
|
||||
return {
|
||||
rowspan: organizationSpan.value,
|
||||
};
|
||||
}
|
||||
if (record.isProject) {
|
||||
return {
|
||||
rowspan: projectSpan.value,
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
/**
|
||||
* 生成数据
|
||||
* @param item
|
||||
* @param type
|
||||
*/
|
||||
const makeData = (item: UserGroupAuthSetting, type: AuthScopeType) => {
|
||||
const result: AuthTableItem[] = [];
|
||||
item.children?.forEach((child, index) => {
|
||||
const perChecked =
|
||||
child?.permissions?.reduce((acc: string[], cur) => {
|
||||
if (cur.enable) {
|
||||
acc.push(cur.id);
|
||||
}
|
||||
return acc;
|
||||
}, []) || [];
|
||||
const perCheckedLength = perChecked.length;
|
||||
let indeterminate = false;
|
||||
if (child?.permissions) {
|
||||
indeterminate = perCheckedLength > 0 && perCheckedLength < child?.permissions?.length;
|
||||
}
|
||||
result.push({
|
||||
id: child?.id,
|
||||
license: child?.license,
|
||||
enable: child?.enable,
|
||||
permissions: child?.permissions,
|
||||
indeterminate,
|
||||
perChecked,
|
||||
ability: index === 0 ? t(`system.userGroup.${type}`) : undefined,
|
||||
operationObject: t(child.name),
|
||||
isSystem: index === 0 && type === 'SYSTEM',
|
||||
isOrganization: index === 0 && type === 'ORGANIZATION',
|
||||
isProject: index === 0 && type === 'PROJECT',
|
||||
});
|
||||
});
|
||||
return result;
|
||||
};
|
||||
// 转换数据 计算系统,组织,项目的合并行数
|
||||
const transformData = (data: UserGroupAuthSetting[]) => {
|
||||
const result: AuthTableItem[] = [];
|
||||
data.forEach((item) => {
|
||||
if (item.type === 'SYSTEM') {
|
||||
systemSpan.value = item.children?.length || 0;
|
||||
}
|
||||
if (item.type === 'PROJECT') {
|
||||
projectSpan.value = item.children?.length || 0;
|
||||
}
|
||||
if (item.type === 'ORGANIZATION') {
|
||||
organizationSpan.value = item.children?.length || 0;
|
||||
}
|
||||
result.push(...makeData(item, item.id));
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
// 表格总全选change事件
|
||||
const handleAllAuthChangeByCheckbox = () => {
|
||||
if (!tableData.value) return;
|
||||
allChecked.value = !allChecked.value;
|
||||
allIndeterminate.value = false;
|
||||
const tmpArr = tableData.value;
|
||||
tmpArr.forEach((item) => {
|
||||
item.enable = allChecked.value;
|
||||
item.indeterminate = false;
|
||||
item.perChecked = allChecked.value ? item.permissions?.map((ele) => ele.id) : [];
|
||||
});
|
||||
if (!canSave.value) canSave.value = true;
|
||||
};
|
||||
|
||||
// 表格总全选联动触发事件
|
||||
const handleAllChange = (isInit = false) => {
|
||||
if (!tableData.value) return;
|
||||
const tmpArr = tableData.value;
|
||||
const { length: allLength } = tmpArr;
|
||||
const { length } = tmpArr.filter((item) => item.enable);
|
||||
if (length === allLength) {
|
||||
allChecked.value = true;
|
||||
allIndeterminate.value = false;
|
||||
} else if (length === 0) {
|
||||
allChecked.value = false;
|
||||
allIndeterminate.value = false;
|
||||
} else {
|
||||
allChecked.value = false;
|
||||
allIndeterminate.value = true;
|
||||
}
|
||||
if (!isInit && !canSave.value) canSave.value = true;
|
||||
};
|
||||
|
||||
// 表格最后一列的复选框change事件
|
||||
const handleRowAuthChange = (value: boolean | (string | number | boolean)[], rowIndex: number) => {
|
||||
if (!tableData.value) return;
|
||||
const tmpArr = tableData.value;
|
||||
tmpArr[rowIndex].indeterminate = false;
|
||||
if (value) {
|
||||
tmpArr[rowIndex].enable = true;
|
||||
tmpArr[rowIndex].perChecked = tmpArr[rowIndex].permissions?.map((item) => item.id);
|
||||
} else {
|
||||
tmpArr[rowIndex].enable = false;
|
||||
tmpArr[rowIndex].perChecked = [];
|
||||
}
|
||||
tableData.value = [...tmpArr];
|
||||
handleAllChange();
|
||||
if (!canSave.value) canSave.value = true;
|
||||
};
|
||||
|
||||
// 表格第三列的复选框change事件
|
||||
const handleCellAuthChange = (values: (string | number | boolean)[], rowIndex: number) => {
|
||||
if (!tableData.value) return;
|
||||
const tmpArr = tableData.value;
|
||||
const length = tmpArr[rowIndex].permissions?.length || 0;
|
||||
if (values.length === length) {
|
||||
tmpArr[rowIndex].enable = true;
|
||||
tmpArr[rowIndex].indeterminate = false;
|
||||
} else if (values.length === 0) {
|
||||
tmpArr[rowIndex].enable = false;
|
||||
tmpArr[rowIndex].indeterminate = false;
|
||||
} else {
|
||||
tmpArr[rowIndex].enable = false;
|
||||
tmpArr[rowIndex].indeterminate = true;
|
||||
}
|
||||
handleAllChange();
|
||||
};
|
||||
|
||||
const initData = async (id: string) => {
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await getGlobalUSetting(id);
|
||||
tableData.value = transformData(res);
|
||||
handleAllChange(true);
|
||||
} catch (error) {
|
||||
tableData.value = [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 保存
|
||||
const handleSave = async () => {
|
||||
if (!tableData.value) return;
|
||||
const permissions: SavePermissions[] = [];
|
||||
|
||||
const tmpArr = tableData.value;
|
||||
tmpArr.forEach((item) => {
|
||||
item.permissions?.forEach((ele) => {
|
||||
ele.enable = item.perChecked?.includes(ele.id) || false;
|
||||
permissions.push({
|
||||
id: ele.id,
|
||||
enable: ele.enable,
|
||||
});
|
||||
});
|
||||
});
|
||||
try {
|
||||
await saveGlobalUSetting({
|
||||
userRoleId: store.currentId,
|
||||
permissions,
|
||||
});
|
||||
initData(store.currentId);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('error', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 恢复默认值
|
||||
const handleReset = () => {
|
||||
if (store.currentId) {
|
||||
initData(store.currentId);
|
||||
}
|
||||
};
|
||||
|
||||
watchEffect(() => {
|
||||
if (store.currentId) {
|
||||
initData(store.currentId);
|
||||
}
|
||||
});
|
||||
defineExpose({
|
||||
handleReset,
|
||||
handleSave,
|
||||
canSave,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.usergroup-auth-table {
|
||||
position: relative;
|
||||
min-height: calc(100vh - 230px);
|
||||
:deep(.arco-table-container) {
|
||||
border-top: 1px solid var(--color-text-n8) !important;
|
||||
border-right: 1px solid var(--color-text-n8) !important;
|
||||
border-left: 1px solid var(--color-text-n8) !important;
|
||||
}
|
||||
.action {
|
||||
position: absolute;
|
||||
right: 24px;
|
||||
bottom: 0;
|
||||
left: 24px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: calc(100% - 24px);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,128 +0,0 @@
|
|||
<template>
|
||||
<a-popover :popup-visible="currentVisible" position="bl" trigger="click" class="w-[276px]">
|
||||
<template #content>
|
||||
<div class="form">
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
size="large"
|
||||
layout="vertical"
|
||||
:label-col-props="{ span: 0 }"
|
||||
:wrapper-col-props="{ span: 24 }"
|
||||
>
|
||||
<a-form-item>
|
||||
<div class="text-[14px] text-[var(--color-text-1)]">{{
|
||||
props.id ? t('system.userGroup.rename') : t('system.userGroup.createUserGroup')
|
||||
}}</div>
|
||||
</a-form-item>
|
||||
<a-form-item field="name" :rules="[{ validator: validateName }]">
|
||||
<a-input
|
||||
v-model="form.name"
|
||||
class="w-[228px]"
|
||||
:placeholder="t('system.userGroup.pleaseInputUserGroupName')"
|
||||
@press-enter="handleBeforeOk"
|
||||
@keyup.esc="handleCancel"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
<div class="flex flex-row flex-nowrap justify-end gap-2">
|
||||
<a-button type="secondary" size="mini" :disabled="loading" @click="handleCancel">
|
||||
{{ t('common.cancel') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
size="mini"
|
||||
:loading="loading"
|
||||
:disabled="form.name.length === 0"
|
||||
@click="handleBeforeOk"
|
||||
>
|
||||
{{ props.id ? t('common.rename') : t('common.create') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</template>
|
||||
<slot></slot>
|
||||
</a-popover>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { reactive, ref, watchEffect } from 'vue';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import type { FormInstance, ValidatedError } from '@arco-design/web-vue';
|
||||
import { updateOrAddUserGroup } from '@/api/modules/setting/usergroup';
|
||||
import { UserGroupItem, AuthScopeType } from '@/models/setting/usergroup';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
id?: string;
|
||||
list: UserGroupItem[];
|
||||
visible: boolean;
|
||||
defaultName?: string;
|
||||
// 权限范围
|
||||
authScope: AuthScopeType;
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
(e: 'cancel', value: boolean): void;
|
||||
(e: 'submit', currentId: string): void;
|
||||
}>();
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
const currentVisible = ref(props.visible);
|
||||
|
||||
const form = reactive({
|
||||
name: '',
|
||||
});
|
||||
|
||||
const loading = ref(false);
|
||||
|
||||
const validateName = (value: string | undefined, callback: (error?: string) => void) => {
|
||||
if (value === undefined || 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();
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
form.name = '';
|
||||
loading.value = false;
|
||||
emit('cancel', false);
|
||||
};
|
||||
|
||||
const handleBeforeOk = () => {
|
||||
formRef.value?.validate(async (errors: undefined | Record<string, ValidatedError>) => {
|
||||
if (errors) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await updateOrAddUserGroup({ id: props.id, name: form.name, type: props.authScope });
|
||||
if (res) {
|
||||
Message.success(
|
||||
props.id ? t('system.userGroup.updateUserGroupSuccess') : t('system.userGroup.addUserGroupSuccess')
|
||||
);
|
||||
emit('submit', res.id);
|
||||
handleCancel();
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
watchEffect(() => {
|
||||
currentVisible.value = props.visible;
|
||||
form.name = props.defaultName || '';
|
||||
});
|
||||
</script>
|
|
@ -1,461 +0,0 @@
|
|||
<template>
|
||||
<a-input-search
|
||||
class="w-[252px]"
|
||||
:placeholder="t('system.userGroup.searchHolder')"
|
||||
allow-clear
|
||||
@press-enter="enterData"
|
||||
@search="searchData"
|
||||
/>
|
||||
<div class="mt-2">
|
||||
<CreateUserGroupPopup
|
||||
:list="systemUserGroupList"
|
||||
:visible="systemUserGroupVisible"
|
||||
auth-scope="SYSTEM"
|
||||
@cancel="systemUserGroupVisible = false"
|
||||
@submit="handleCreateUserGroup"
|
||||
>
|
||||
<div class="flex items-center justify-between px-[4px] py-[7px]">
|
||||
<div class="flex flex-row items-center gap-1 text-[var(--color-text-4)]">
|
||||
<MsIcon
|
||||
v-if="systemToggle"
|
||||
class="cursor-pointer"
|
||||
type="icon-icon_expand-down_filled"
|
||||
size="12"
|
||||
@click="systemToggle = false"
|
||||
/>
|
||||
<MsIcon
|
||||
v-else
|
||||
class="cursor-pointer"
|
||||
type="icon-icon_expand-right_filled"
|
||||
size="12"
|
||||
@click="systemToggle = true"
|
||||
/>
|
||||
<div class="text-[14px]">
|
||||
{{ t('system.userGroup.systemUserGroup') }}
|
||||
</div>
|
||||
</div>
|
||||
<MsMoreAction :list="createSystemUGActionItem" @select="systemUserGroupVisible = true">
|
||||
<icon-plus-circle-fill class="text-[rgb(var(--primary-7))]" size="20" />
|
||||
</MsMoreAction>
|
||||
</div>
|
||||
</CreateUserGroupPopup>
|
||||
<Transition>
|
||||
<div v-if="systemToggle">
|
||||
<div
|
||||
v-for="element in systemUserGroupList"
|
||||
:key="element.id"
|
||||
class="flex h-[38px] cursor-pointer items-center py-[7px] pl-[20px] pr-[4px]"
|
||||
:class="{ 'bg-[rgb(var(--primary-1))]': element.id === currentId }"
|
||||
@click="handleListItemClick(element)"
|
||||
>
|
||||
<CreateUserGroupPopup
|
||||
:list="systemUserGroupList"
|
||||
v-bind="popVisible[element.id]"
|
||||
@cancel="handleRenameCancel(element)"
|
||||
@submit="handleRenameCancel(element, element.id)"
|
||||
>
|
||||
<div class="flex grow flex-row items-center justify-between">
|
||||
<a-tooltip :content="element.name">
|
||||
<div
|
||||
class="one-line-text max-w-[156px] text-[var(--color-text-1)]"
|
||||
:class="{ 'text-[rgb(var(--primary-7))]': element.id === currentId }"
|
||||
>{{ element.name }}</div
|
||||
>
|
||||
</a-tooltip>
|
||||
<div v-if="element.id === currentId && !element.internal" class="flex flex-row items-center gap-[8px]">
|
||||
<MsMoreAction :list="addMemberActionItem" @select="handleAddMember">
|
||||
<div class="icon-button">
|
||||
<MsIcon type="icon-icon_add_outlined" size="16" />
|
||||
</div>
|
||||
</MsMoreAction>
|
||||
<MsMoreAction
|
||||
:list="moreAction"
|
||||
@select="(value) => handleMoreAction(value, element.id, AuthScopeEnum.SYSTEM)"
|
||||
>
|
||||
<div class="icon-button">
|
||||
<MsIcon type="icon-icon_more_outlined" size="16" />
|
||||
</div>
|
||||
</MsMoreAction>
|
||||
</div>
|
||||
</div>
|
||||
</CreateUserGroupPopup>
|
||||
</div>
|
||||
<a-divider class="my-[0px] mt-[6px]" />
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
<CreateUserGroupPopup
|
||||
:list="orgUserGroupList"
|
||||
:visible="orgUserGroupVisible"
|
||||
auth-scope="ORGANIZATION"
|
||||
@cancel="orgUserGroupVisible = false"
|
||||
@submit="handleCreateUserGroup"
|
||||
>
|
||||
<div class="flex items-center justify-between px-[4px] py-[7px]">
|
||||
<div class="flex flex-row items-center gap-1 text-[var(--color-text-4)]">
|
||||
<MsIcon
|
||||
v-if="orgToggle"
|
||||
class="cursor-pointer"
|
||||
type="icon-icon_expand-down_filled"
|
||||
size="12"
|
||||
@click="orgToggle = false"
|
||||
/>
|
||||
<MsIcon
|
||||
v-else
|
||||
class="cursor-pointer"
|
||||
type="icon-icon_expand-right_filled"
|
||||
size="12"
|
||||
@click="orgToggle = true"
|
||||
/>
|
||||
<div class="text-[14px]">
|
||||
{{ t('system.userGroup.orgUserGroup') }}
|
||||
</div>
|
||||
</div>
|
||||
<MsMoreAction :list="createOrgUGActionItem" @select="orgUserGroupVisible = true">
|
||||
<icon-plus-circle-fill class="text-[rgb(var(--primary-7))]" size="20" />
|
||||
</MsMoreAction>
|
||||
</div>
|
||||
</CreateUserGroupPopup>
|
||||
<Transition>
|
||||
<div v-if="orgToggle">
|
||||
<div
|
||||
v-for="element in orgUserGroupList"
|
||||
:key="element.id"
|
||||
class="flex h-[38px] cursor-pointer items-center py-[7px] pl-[20px] pr-[4px]"
|
||||
:class="{ 'bg-[rgb(var(--primary-1))]': element.id === currentId }"
|
||||
@click="handleListItemClick(element)"
|
||||
>
|
||||
<CreateUserGroupPopup
|
||||
:list="orgUserGroupList"
|
||||
v-bind="popVisible[element.id]"
|
||||
@cancel="handleRenameCancel(element)"
|
||||
@submit="handleRenameCancel(element, element.id)"
|
||||
>
|
||||
<div class="flex grow flex-row items-center justify-between">
|
||||
<a-tooltip :content="element.name">
|
||||
<div
|
||||
class="one-line-text max-w-[156px] text-[var(--color-text-1)]"
|
||||
:class="{ 'text-[rgb(var(--primary-7))]': element.id === currentId }"
|
||||
>{{ element.name }}</div
|
||||
>
|
||||
</a-tooltip>
|
||||
<div v-if="element.id === currentId && !element.internal" class="flex flex-row items-center gap-[8px]">
|
||||
<MsMoreAction :list="addMemberActionItem" @select="handleAddMember">
|
||||
<div class="icon-button">
|
||||
<MsIcon type="icon-icon_add_outlined" size="16" />
|
||||
</div>
|
||||
</MsMoreAction>
|
||||
<MsMoreAction
|
||||
:list="moreAction"
|
||||
@select="(value) => handleMoreAction(value, element.id, AuthScopeEnum.ORGANIZATION)"
|
||||
>
|
||||
<div class="icon-button">
|
||||
<MsIcon type="icon-icon_more_outlined" size="16" />
|
||||
</div>
|
||||
</MsMoreAction>
|
||||
</div>
|
||||
</div>
|
||||
</CreateUserGroupPopup>
|
||||
</div>
|
||||
<a-divider class="my-[0px] mt-[6px]" />
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
<CreateUserGroupPopup
|
||||
:list="projectUserGroupList"
|
||||
:visible="projectUserGroupVisible"
|
||||
auth-scope="PROJECT"
|
||||
@cancel="projectUserGroupVisible = false"
|
||||
@submit="handleCreateUserGroup"
|
||||
>
|
||||
<div class="flex items-center justify-between px-[4px] py-[7px]">
|
||||
<div class="flex flex-row items-center gap-1 text-[var(--color-text-4)]">
|
||||
<MsIcon
|
||||
v-if="projectToggle"
|
||||
class="cursor-pointer"
|
||||
type="icon-icon_expand-down_filled"
|
||||
size="12"
|
||||
@click="projectToggle = false"
|
||||
/>
|
||||
<MsIcon
|
||||
v-else
|
||||
class="cursor-pointer"
|
||||
type="icon-icon_expand-right_filled"
|
||||
size="12"
|
||||
@click="projectToggle = true"
|
||||
/>
|
||||
<div class="text-[14px]">
|
||||
{{ t('system.userGroup.projectUserGroup') }}
|
||||
</div>
|
||||
</div>
|
||||
<MsMoreAction :list="createProjectUGActionItem" @select="projectUserGroupVisible = true">
|
||||
<icon-plus-circle-fill class="text-[rgb(var(--primary-7))]" size="20" />
|
||||
</MsMoreAction>
|
||||
</div>
|
||||
</CreateUserGroupPopup>
|
||||
<Transition>
|
||||
<div v-if="projectToggle">
|
||||
<div
|
||||
v-for="element in projectUserGroupList"
|
||||
:key="element.id"
|
||||
class="flex h-[38px] cursor-pointer items-center py-[7px] pl-[20px] pr-[4px]"
|
||||
:class="{ 'bg-[rgb(var(--primary-1))]': element.id === currentId }"
|
||||
@click="handleListItemClick(element)"
|
||||
>
|
||||
<CreateUserGroupPopup
|
||||
:list="projectUserGroupList"
|
||||
v-bind="popVisible[element.id]"
|
||||
@cancel="handleRenameCancel(element)"
|
||||
@submit="handleRenameCancel(element, element.id)"
|
||||
>
|
||||
<div class="flex grow flex-row items-center justify-between">
|
||||
<a-tooltip :content="element.name">
|
||||
<div
|
||||
class="one-line-text max-w-[156px] text-[var(--color-text-1)]"
|
||||
:class="{ 'text-[rgb(var(--primary-7))]': element.id === currentId }"
|
||||
>{{ element.name }}</div
|
||||
>
|
||||
</a-tooltip>
|
||||
<div v-if="element.id === currentId && !element.internal" class="flex flex-row items-center gap-[8px]">
|
||||
<MsMoreAction :list="addMemberActionItem" @select="handleAddMember">
|
||||
<div class="icon-button">
|
||||
<MsIcon type="icon-icon_add_outlined" size="16" />
|
||||
</div>
|
||||
</MsMoreAction>
|
||||
<MsMoreAction
|
||||
:list="moreAction"
|
||||
@select="(value) => handleMoreAction(value, element.id, AuthScopeEnum.PROJECT)"
|
||||
>
|
||||
<div class="icon-button">
|
||||
<MsIcon type="icon-icon_more_outlined" size="16" />
|
||||
</div>
|
||||
</MsMoreAction>
|
||||
</div>
|
||||
</div>
|
||||
</CreateUserGroupPopup>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
<AddUserModal :visible="userModalVisible" @cancel="userModalVisible = false" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import MsMoreAction from '@/components/pure/ms-table-more-action/index.vue';
|
||||
import { UserGroupItem, PopVisible, PopVisibleItem } from '@/models/setting/usergroup';
|
||||
import { getUserGroupList, deleteUserGroup } from '@/api/modules/setting/usergroup';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import CreateUserGroupPopup from './createOrUpdateUserGroup.vue';
|
||||
import AddUserModal from './addUserModal.vue';
|
||||
import useUserGroupStore from '@/store/modules/setting/system/usergroup';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import useModal from '@/hooks/useModal';
|
||||
import { characterLimit } from '@/utils';
|
||||
import { AuthScopeEnum } from '@/enums/commonEnum';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const store = useUserGroupStore();
|
||||
const { openModal } = useModal();
|
||||
|
||||
// 用户组列表
|
||||
const userGroupList = ref<UserGroupItem[]>([]);
|
||||
|
||||
const currentId = ref('');
|
||||
|
||||
const userModalVisible = ref(false);
|
||||
|
||||
// 气泡弹窗
|
||||
const popVisible = ref<PopVisible>({});
|
||||
|
||||
// 系统用户创建用户组visible
|
||||
const systemUserGroupVisible = ref(false);
|
||||
// 组织用户创建用户组visible
|
||||
const orgUserGroupVisible = ref(false);
|
||||
// 项目用户创建用户组visible
|
||||
const projectUserGroupVisible = ref(false);
|
||||
|
||||
// 系统用户组Toggle
|
||||
const systemToggle = ref(true);
|
||||
// 组织用户组Toggle
|
||||
const orgToggle = ref(true);
|
||||
// 项目用户组Toggle
|
||||
const projectToggle = ref(true);
|
||||
|
||||
// 系统用户组列表
|
||||
const systemUserGroupList = computed(() => {
|
||||
return userGroupList.value.filter((ele) => ele.type === 'SYSTEM');
|
||||
});
|
||||
// 组织用户组列表
|
||||
const orgUserGroupList = computed(() => {
|
||||
return userGroupList.value.filter((ele) => ele.type === 'ORGANIZATION');
|
||||
});
|
||||
// 项目用户组列表
|
||||
const projectUserGroupList = computed(() => {
|
||||
return userGroupList.value.filter((ele) => ele.type === 'PROJECT');
|
||||
});
|
||||
|
||||
const createSystemUGActionItem: ActionsItem[] = [
|
||||
{ label: 'system.userGroup.addSysUserGroup', eventTag: 'createUserGroup' },
|
||||
];
|
||||
const createOrgUGActionItem: ActionsItem[] = [
|
||||
{ label: 'system.userGroup.addOrgUserGroup', eventTag: 'createUserGroup' },
|
||||
];
|
||||
const createProjectUGActionItem: ActionsItem[] = [
|
||||
{ label: 'system.userGroup.addProjectUserGroup', eventTag: 'createUserGroup' },
|
||||
];
|
||||
|
||||
const addMemberActionItem: ActionsItem[] = [{ label: 'system.userGroup.addMember', eventTag: 'addMember' }];
|
||||
const moreAction: ActionsItem[] = [
|
||||
{
|
||||
label: 'system.userGroup.rename',
|
||||
danger: false,
|
||||
eventTag: 'rename',
|
||||
},
|
||||
{
|
||||
isDivider: true,
|
||||
},
|
||||
{
|
||||
label: 'system.userGroup.delete',
|
||||
danger: true,
|
||||
eventTag: 'delete',
|
||||
},
|
||||
];
|
||||
|
||||
// 点击用户组列表
|
||||
const handleListItemClick = (element: UserGroupItem) => {
|
||||
const { id, name, type, internal } = element;
|
||||
currentId.value = id;
|
||||
store.setInfo({
|
||||
currentName: name,
|
||||
currentTitle: type,
|
||||
currentId: id,
|
||||
currentType: type,
|
||||
currentInternal: internal,
|
||||
});
|
||||
};
|
||||
|
||||
// 用户组数据初始化
|
||||
const initData = async (id?: string) => {
|
||||
try {
|
||||
const res = await getUserGroupList();
|
||||
if (res.length > 0) {
|
||||
userGroupList.value = res;
|
||||
let tmpItem = res[0];
|
||||
if (id) {
|
||||
tmpItem = res.find((i) => i.id === id) || res[0];
|
||||
}
|
||||
handleListItemClick(tmpItem);
|
||||
// 弹窗赋值
|
||||
const tmpObj: PopVisible = {};
|
||||
res.forEach((element) => {
|
||||
tmpObj[element.id] = { visible: false, authScope: element.type, defaultName: '', id: element.id };
|
||||
});
|
||||
popVisible.value = tmpObj;
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
// 点击更多操作
|
||||
const handleMoreAction = (item: ActionsItem, id: string, authScope: AuthScopeEnum) => {
|
||||
if (item.eventTag === 'rename') {
|
||||
const tmpObj = userGroupList.value.filter((ele) => ele.id === id)[0];
|
||||
const visibleItem: PopVisibleItem = { visible: true, authScope, defaultName: tmpObj.name, id };
|
||||
popVisible.value[id] = visibleItem;
|
||||
}
|
||||
if (item.eventTag === 'delete') {
|
||||
openModal({
|
||||
type: 'error',
|
||||
title: t('system.userGroup.isDeleteUserGroup', { name: characterLimit(store.currentName) }),
|
||||
content: t('system.userGroup.beforeDeleteUserGroup'),
|
||||
okText: t('system.userGroup.confirmDelete'),
|
||||
cancelText: t('system.userGroup.cancel'),
|
||||
okButtonProps: {
|
||||
status: 'danger',
|
||||
},
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
await deleteUserGroup(id);
|
||||
Message.success(t('system.user.deleteUserSuccess'));
|
||||
initData();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
hideCancel: false,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 点击添加成员
|
||||
const handleAddMember = () => {
|
||||
userModalVisible.value = true;
|
||||
};
|
||||
|
||||
function enterData(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;
|
||||
}
|
||||
function searchData(value: string) {
|
||||
if (!value) {
|
||||
initData();
|
||||
return;
|
||||
}
|
||||
const keyword = value;
|
||||
const tmpArr = userGroupList.value.filter((ele) => ele.name.includes(keyword));
|
||||
userGroupList.value = tmpArr;
|
||||
}
|
||||
const handleCreateUserGroup = (id: string) => {
|
||||
initData(id);
|
||||
};
|
||||
const handleRenameCancel = (element: UserGroupItem, id?: string) => {
|
||||
if (id) {
|
||||
initData(id);
|
||||
}
|
||||
popVisible.value[element.id].visible = false;
|
||||
};
|
||||
onMounted(() => {
|
||||
initData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.icon-increase {
|
||||
background-color: rgb(var(--primary-7));
|
||||
}
|
||||
.icon-button {
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: rgb(var(--primary-7));
|
||||
}
|
||||
.icon-button:hover {
|
||||
background-color: rgb(var(--primary-9));
|
||||
}
|
||||
.v-enter-active,
|
||||
.v-leave-active {
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
.v-enter-from,
|
||||
.v-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
|
@ -1,95 +0,0 @@
|
|||
<template>
|
||||
<a-button type="primary" @click="handleAddUser">{{ t('system.userGroup.quickAddUser') }}</a-button>
|
||||
<MsBaseTable class="mt-[16px]" v-bind="propsRes" v-on="propsEvent">
|
||||
<template #action="{ record }">
|
||||
<MsRemoveButton
|
||||
:title="t('system.userGroup.removeName', { name: record.name })"
|
||||
:sub-title-tip="t('system.userGroup.removeTip')"
|
||||
:loading="removeLoading"
|
||||
@ok="handleRemove(record)"
|
||||
/>
|
||||
</template>
|
||||
</MsBaseTable>
|
||||
<AddUserModal :visible="userVisible" @cancel="handleAddUserModalCancel" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import useUserGroupStore from '@/store/modules/setting/system/usergroup';
|
||||
import { watchEffect, ref } from 'vue';
|
||||
import { postUserByUserGroup, deleteUserFromUserGroup } from '@/api/modules/setting/usergroup';
|
||||
import { UserTableItem } from '@/models/setting/usergroup';
|
||||
import { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import AddUserModal from './addUserModal.vue';
|
||||
import MsRemoveButton from '@/components/business/ms-remove-button/MsRemoveButton.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const store = useUserGroupStore();
|
||||
const userVisible = ref(false);
|
||||
const removeLoading = ref(false);
|
||||
const props = defineProps<{
|
||||
keyword: string;
|
||||
}>();
|
||||
|
||||
const userGroupUsercolumns: MsTableColumn = [
|
||||
{
|
||||
title: 'system.userGroup.name',
|
||||
dataIndex: 'name',
|
||||
},
|
||||
{
|
||||
title: 'system.userGroup.email',
|
||||
dataIndex: 'email',
|
||||
},
|
||||
{
|
||||
title: 'system.userGroup.phone',
|
||||
dataIndex: 'email',
|
||||
},
|
||||
{
|
||||
title: 'system.userGroup.operation',
|
||||
slotName: 'action',
|
||||
fixed: 'right',
|
||||
width: 200,
|
||||
},
|
||||
];
|
||||
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams, setKeyword } = useTable(postUserByUserGroup, {
|
||||
columns: userGroupUsercolumns,
|
||||
scroll: { x: '600px' },
|
||||
noDisable: true,
|
||||
});
|
||||
|
||||
const fetchData = async () => {
|
||||
setKeyword(props.keyword);
|
||||
await loadList();
|
||||
};
|
||||
const handleRemove = async (record: UserTableItem) => {
|
||||
try {
|
||||
removeLoading.value = true;
|
||||
await deleteUserFromUserGroup(record.id);
|
||||
await fetchData();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
removeLoading.value = false;
|
||||
}
|
||||
};
|
||||
const handleAddUser = () => {
|
||||
userVisible.value = true;
|
||||
};
|
||||
const handleAddUserModalCancel = () => {
|
||||
fetchData();
|
||||
userVisible.value = false;
|
||||
};
|
||||
watchEffect(() => {
|
||||
if (store.currentId) {
|
||||
setLoadListParams({ roleId: store.currentId });
|
||||
fetchData();
|
||||
}
|
||||
});
|
||||
defineExpose({
|
||||
fetchData,
|
||||
});
|
||||
</script>
|
|
@ -1,17 +1,17 @@
|
|||
<template>
|
||||
<MsCard simple>
|
||||
<div class="flex flex-row">
|
||||
<div class="user-group-left" :style="{ padding: collapse ? '24px 24px 24px 0' : 0 }">
|
||||
<UserGroupLeft v-if="collapse" :type="AuthScopeEnum.SYSTEM" />
|
||||
<div class="user-group-left" :style="{ padding: leftCollapse ? '24px 24px 24px 0' : 0 }">
|
||||
<UserGroupLeft v-if="leftCollapse" @on-select="handleSelect" />
|
||||
<div class="usergroup-collapse" @click="handleCollapse">
|
||||
<MsIcon v-if="collapse" type="icon-icon_up-left_outlined" class="icon" />
|
||||
<MsIcon v-if="leftCollapse" type="icon-icon_up-left_outlined" class="icon" />
|
||||
<MsIcon v-else type="icon-icon_down-right_outlined" class="icon" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative w-[100%] overflow-x-scroll p-[24px]">
|
||||
<div class="flex flex-row items-center justify-between">
|
||||
<a-tooltip :content="store.userGroupInfo.currentName">
|
||||
<div class="one-line-text max-w-[300px]">{{ store.userGroupInfo.currentName }}</div>
|
||||
<a-tooltip :content="currentUserGroupItem.name">
|
||||
<div class="one-line-text max-w-[300px]">{{ currentUserGroupItem.name }}</div>
|
||||
</a-tooltip>
|
||||
<div class="flex items-center">
|
||||
<a-input-search
|
||||
|
@ -29,8 +29,13 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="mt-[16px]">
|
||||
<user-table v-if="currentTable === 'user' && couldShowUser" ref="userRef" :keyword="currentKeyword" />
|
||||
<auth-table v-if="currentTable === 'auth' && couldShowAuth" ref="authRef" />
|
||||
<UserTable
|
||||
v-if="currentTable === 'user' && couldShowUser"
|
||||
ref="userRef"
|
||||
:keyword="currentKeyword"
|
||||
:current="currentUserGroupItem"
|
||||
/>
|
||||
<AuthTable v-if="currentTable === 'auth' && couldShowAuth" ref="authRef" :current="currentUserGroupItem" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -51,20 +56,29 @@
|
|||
import { ref, computed, watchEffect, nextTick, provide } from 'vue';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||
import useUserGroupStore from '@/store/modules/setting/system/usergroup';
|
||||
import UserGroupLeft from '@/components/business/ms-user-group-left/msUserGroupLeft.vue';
|
||||
import UserTable from './components/userTable.vue';
|
||||
import AuthTable from './components/authTable.vue';
|
||||
import UserGroupLeft from '@/components/business/ms-user-group-comp/msUserGroupLeft.vue';
|
||||
import UserTable from '@/components/business/ms-user-group-comp/userTable.vue';
|
||||
import AuthTable from '@/components/business/ms-user-group-comp/authTable.vue';
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import { useAppStore } from '@/store';
|
||||
import { AuthScopeEnum } from '@/enums/commonEnum';
|
||||
import { CurrentUserGroupItem } from '@/models/setting/usergroup';
|
||||
|
||||
const currentTable = ref('auth');
|
||||
provide('systemType', AuthScopeEnum.SYSTEM);
|
||||
|
||||
const { t } = useI18n();
|
||||
const currentKeyword = ref('');
|
||||
const currentUserGroupItem = ref<CurrentUserGroupItem>({
|
||||
id: '',
|
||||
name: '',
|
||||
type: AuthScopeEnum.SYSTEM,
|
||||
internal: true,
|
||||
});
|
||||
|
||||
const leftCollapse = ref(true);
|
||||
|
||||
const authRef = ref<{
|
||||
handleReset: () => void;
|
||||
handleSave: () => void;
|
||||
|
@ -92,16 +106,18 @@
|
|||
tableSearch();
|
||||
};
|
||||
|
||||
const store = useUserGroupStore();
|
||||
const couldShowUser = computed(() => store.userGroupInfo.currentType === 'SYSTEM');
|
||||
const couldShowAuth = computed(() => store.userGroupInfo.currentId !== 'admin');
|
||||
const handleCollapse = () => {
|
||||
store.setCollapse(!store.collapse);
|
||||
const handleSelect = (item: CurrentUserGroupItem) => {
|
||||
currentUserGroupItem.value = item;
|
||||
};
|
||||
|
||||
const couldShowUser = computed(() => currentUserGroupItem.value.type === AuthScopeEnum.SYSTEM);
|
||||
const couldShowAuth = computed(() => currentUserGroupItem.value.id !== 'admin');
|
||||
const handleCollapse = () => {
|
||||
leftCollapse.value = !leftCollapse.value;
|
||||
};
|
||||
const collapse = computed(() => store.collapse);
|
||||
const menuWidth = computed(() => {
|
||||
const width = appStore.menuCollapse ? 86 : appStore.menuWidth;
|
||||
if (store.collapse) {
|
||||
if (leftCollapse.value) {
|
||||
return width + 300;
|
||||
}
|
||||
return width + 24;
|
||||
|
|
Loading…
Reference in New Issue