RoleDrawer.vue 9.96 KB
<template>
  <BasicDrawer
    v-bind="$attrs"
    @register="registerDrawer"
    showFooter
    :title="getTitle"
    width="500px"
    @ok="handleSubmit"
  >
    <BasicForm @register="registerForm">
      <template #menu>
        <Spin :spinning="spinning">
          <BasicTree
            v-if="treeData.length"
            checkable
            toolbar
            ref="treeRef"
            :treeData="treeData"
            @check="handleCheckClick"
            :replace-fields="{ title: 'name', key: 'id' }"
            :checkedKeys="roleMenus"
            title="菜单分配"
          />
        </Spin>
      </template>
    </BasicForm>
  </BasicDrawer>
</template>
<script lang="ts">
  import { defineComponent, ref, computed, unref, nextTick } from 'vue';
  import { BasicForm, useForm } from '/@/components/Form/index';
  import { formSchema, KeysTypeEnum, RoleMenuDictEnum } from './role.data';
  import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  import { BasicTree, TreeActionType, TreeItem } from '/@/components/Tree';
  import { useMessage } from '/@/hooks/web/useMessage';
  const { t } = useI18n(); // 加载国际化
  // 加载菜单数据
  import { getMeMenuList, getMenusIdsByRoleId } from '/@/api/sys/menu';
  import { useI18n } from '/@/hooks/web/useI18n';
  import { MenuRecord } from '/@/api/sys/model/menuModel';
  import { saveOrUpdateRoleInfoWithMenu } from '/@/api/system/system';
  import { findDictItemByCode } from '/@/api/system/dict';
  import { RoleEnum } from '/@/enums/roleEnum';
  import { Spin } from 'ant-design-vue';
  import { useRole } from '/@/hooks/business/useRole';
  import { RoleListItem } from '/@/api/system/model/systemModel';

  type TreeData = MenuRecord & TreeItem;

  export default defineComponent({
    name: 'RoleDrawer',
    components: { BasicDrawer, BasicForm, BasicTree, Spin },
    emits: ['success', 'register'],
    setup(_, { emit }) {
      const isUpdate = ref<boolean>(true);
      const treeData = ref<TreeData[]>([]);
      const roleMenus = ref<string[]>([]);
      const roleId = ref<string>('');
      const treeRef = ref<Nullable<TreeActionType>>();
      const checked = ref<string[]>([]); //需要选中的节点
      const spinning = ref(false);
      const checkedKeysWithHalfChecked = ref<string[]>([]);

      const [registerForm, { resetFields, setFieldsValue, validate, updateSchema }] = useForm({
        labelWidth: 100,
        schemas: formSchema,
        showActionButtonGroup: false,
      });

      const transformName = (data: TreeData[]) => {
        return data.map((item) => {
          item.name = t(item.name);
          if (item.children && item.children.length) {
            item.children = transformName(item.children as unknown as TreeData[]);
          }
          return item;
        });
      };

      const { isTenantAdmin, isSysadmin, getRole } = useRole();
      const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(
        async (data: { isUpdate: boolean; record: RoleListItem }) => {
          if (data?.record) {
            updateSchema({
              field: 'status',
              componentProps: {
                options: [
                  { label: '启用', value: 1 },
                  { label: '停用', value: 0 },
                ],
                disabled: data.record.status == 1 ? true : false,
              },
            });
          }

          resetFields();
          roleId.value = '';
          // 在打开弹窗时清除所有选择的菜单
          treeRef.value && treeRef.value?.setCheckedKeys([]);
          isUpdate.value = data.isUpdate;
          let roleType = unref(getRole) || RoleEnum.SYS_ADMIN;

          // 租户管理员创建角色时 菜单分配为客户菜单
          if (unref(isTenantAdmin)) {
            roleType = RoleEnum.CUSTOMER_USER;
          }

          try {
            spinning.value = true;
            // 需要在setFieldsValue之前先填充treeData,否则Tree组件可能会报key not exist警告

            // if (!unref(treeData).length) {
            // 获取全部的菜单
            const menuListModel = await getMeMenuList();
            treeData.value = transformName(menuListModel as unknown as TreeData[]);
            // }

            const keys = await getPermissionByRole(roleType);
            const { keyType } = RoleMenuDictEnum[roleType];
            treeData.value = filterPermissionTreeData(
              unref(treeData) as unknown as TreeData[],
              keys,
              keyType
            );

            // 如果编辑的是超级管理员 则不再过滤平台管理员禁用的权限
            // 如果是超级管理员创建角色 创建角色属于平台管理员 因此过滤平台管理员禁用的权限
            if (data?.record?.roleType !== RoleEnum.SYS_ADMIN && unref(isSysadmin)) {
              const keys = await getPermissionByRole(RoleEnum.PLATFORM_ADMIN);
              const { keyType } = RoleMenuDictEnum[RoleEnum.PLATFORM_ADMIN];
              treeData.value = filterPermissionTreeData(
                unref(treeData) as unknown as TreeData[],
                keys,
                keyType
              );
            }

            // 更新
            if (unref(isUpdate)) {
              checked.value = [];
              roleId.value = data.record.id;

              //通过角色id去获取角色对应的菜单的ids
              checkedKeysWithHalfChecked.value = roleMenus.value = await getMenusIdsByRoleId(
                data.record.id
              );
              excludeHalfCheckedKeys(unref(treeData));
              await nextTick();
              unref(treeRef)?.setCheckedKeys(roleMenus.value);
              setFieldsValue(data.record);
            } else {
            }
          } catch (error) {
            throw error;
          } finally {
            spinning.value = false;
          }
        }
      );

      const getTitle = computed(() => (!unref(isUpdate) ? '新增客户角色' : '编辑客户角色'));

      async function handleSubmit() {
        setDrawerProps({ confirmLoading: true });
        const { createMessage } = useMessage();
        try {
          const values = await validate();
          const treeCheckedKeys: string[] = (unref(treeRef)?.getCheckedKeys() as string[]) || [];
          const menu = [...new Set([...unref(checkedKeysWithHalfChecked), ...treeCheckedKeys])];
          const req = {
            id: roleId.value,
            name: values.name,
            remark: values.remark,
            status: values.status,
            menu,
          };
          if (req.menu == undefined || !req.menu.length)
            return createMessage.error('请勾选权限菜单');
          saveOrUpdateRoleInfoWithMenu(req).then(() => {
            closeDrawer();
            emit('success');
            createMessage.success(`${unref(isUpdate) ? '编辑' : '新增'}成功`);
          });
        } finally {
          setTimeout(() => {
            setDrawerProps({ confirmLoading: false });
          }, 300);
        }
      }

      const getPermissionByRole = async (roleType: RoleEnum) => {
        try {
          const { key } = RoleMenuDictEnum[roleType];
          const res = await findDictItemByCode({ dictCode: key });
          return res.map((item) => item.itemValue);
        } catch (error) {}
        return [];
      };

      const filterPermissionTreeData = (
        data: MenuRecord[],
        permissionKeys: string[],
        keysType: KeysTypeEnum
      ): TreeData[] => {
        const permissionCompare = (
          data: MenuRecord[],
          permissionKeys: string[],
          keysType: KeysTypeEnum
        ): TreeData[] => {
          return data.filter((item) => {
            item.name = t(item.name);
            const findFlag = permissionKeys.includes(item.permission);

            item.show = findFlag ? keysType === KeysTypeEnum.ENABLED : undefined;

            if (item.children && item.children.length) {
              if (item.show) return true;
              if (item.show === undefined) {
                item.children = permissionCompare(item.children, permissionKeys, keysType);
                item.show = item.children.some((item) =>
                  keysType === KeysTypeEnum.ENABLED
                    ? item.show
                    : item.show === undefined
                    ? true
                    : item.show
                );
                return item.show;
              }
            }

            return keysType === KeysTypeEnum.ENABLED
              ? item.show
              : item.show === undefined
              ? true
              : item.show;
          }) as unknown as TreeData[];
        };

        return permissionCompare(data, permissionKeys, keysType);
      };

      const excludeHalfCheckedKeys = (treeData: MenuRecord[]) => {
        const needExcludeKeys: string[] = [];
        const query = (data: MenuRecord[]) => {
          data.forEach((item) => {
            item.checked = roleMenus.value.includes(item.id);
            if (item.children && item.children.length) {
              query(item.children);
              item.checked = item.children.every((item) => item.checked);
            }
            if (!item.checked) {
              needExcludeKeys.push(item.id);
            }
          });
        };
        query(treeData);
        roleMenus.value = unref(roleMenus).filter((key) => !needExcludeKeys.includes(key));
        return needExcludeKeys;
      };

      const handleCheckClick = (selectedKeys: string[], event: CheckEvent) => {
        checkedKeysWithHalfChecked.value = [
          ...selectedKeys,
          ...(event.halfCheckedKeys as string[]),
        ];
      };

      return {
        spinning,
        registerDrawer,
        registerForm,
        getTitle,
        handleSubmit,
        treeData,
        roleMenus,
        treeRef,
        handleCheckClick,
      };
    },
  });
</script>

<style scoped lang="less">
  :deep(.vben-basic-tree) {
    width: 100% !important;
  }

  :deep(.is-unflod) {
    display: none !important;
  }

  :deep(.is-flod) {
    display: none !important;
  }
</style>