RoleDrawer.vue 9.42 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"
            :treeData="treeData"
            :replaceFields="{ title: 'name', key: 'id' }"
            :checkedKeys="roleMenus"
            @check="handleCheckClick"
            @unSelectAll="handleUnSelectAll"
            checkable
            toolbar
            ref="treeRef"
            :title="t('system.tenantRole.text.authAssign')"
          />
        </Spin>
      </template>
    </BasicForm>
  </BasicDrawer>
</template>
<script lang="ts" setup>
  import { ref, computed, unref, nextTick } from 'vue';
  import { BasicForm, useForm } from '/@/components/Form/index';
  import { formSchema } from './role.data';
  import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  import { BasicTree, CheckEvent, TreeActionType, TreeItem, CheckKeys } from '/@/components/Tree';
  const { t } = useI18n(); // 加载国际化
  // 加载菜单数据
  import { getAdminMenuList, getMenuList, 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 { RoleEnum } from '/@/enums/roleEnum';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { findDictItemByCode } from '/@/api/system/dict';
  import { Spin } from 'ant-design-vue';
  import { useRole } from '/@/hooks/business/useRole';
  import { RoleMenuDictEnum, KeysTypeEnum } from '../custom/role.data';

  type TreeData = MenuRecord & TreeItem;

  const emit = defineEmits(['success', 'register']);

  const isUpdate = ref(true);
  const treeData = ref<TreeData[]>([]);
  const roleMenus = ref<string[]>([]);
  const roleId = ref('');
  const treeRef = ref<Nullable<TreeActionType>>(null);
  const checked = ref<string[]>([]); //需要选中的节点
  const spinning = ref(false);
  const checkedKeysWithHalfChecked = ref<(string | number)[]>([]);

  const [registerForm, { resetFields, setFieldsValue, validate, updateSchema }] = useForm({
    labelWidth: 90,
    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 { isPlatformAdmin } = useRole();
  const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
    if (data?.isUpdate) {
      updateSchema({
        field: 'status',
        componentProps: {
          options: [
            { label: t('common.enabledText'), value: 1 },
            { label: t('common.disableText'), value: 0 },
          ],
          disabled: data.record.status == 1 ? true : false,
        },
      });
    } else {
      updateSchema({
        field: 'status',
        componentProps: {
          options: [
            { label: t('common.enabledText'), value: 1 },
            { label: t('common.disableText'), value: 0 },
          ],
          disabled: false,
        },
      });
    }
    resetFields();
    roleId.value = '';
    // 在打开弹窗时清除所有选择的菜单
    treeRef.value && treeRef.value?.setCheckedKeys([]);
    isUpdate.value = data.isUpdate;
    const roleType = RoleEnum.TENANT_ADMIN;
    const commonTenantRoleType = RoleEnum.COMMON_TENANT;
    try {
      spinning.value = true;

      if (!unref(treeData).length) {
        // 获取全部的菜单
        const menuListModel = unref(isPlatformAdmin)
          ? await getAdminMenuList()
          : await getMenuList();
        treeData.value = transformName(menuListModel as unknown as TreeData[]);
      }
      const keys = await getPermissionByRole(roleType);
      const commonTenantkeys = await getPermissionByRole(commonTenantRoleType);
      const mergeKeys = [...keys, ...commonTenantkeys];
      const { keyType } = RoleMenuDictEnum[roleType];
      treeData.value = filterPermissionTreeData(
        unref(treeData) as unknown as TreeData[],
        mergeKeys,
        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();
        treeRef.value?.setCheckedKeys(roleMenus.value);
        setFieldsValue(data.record);
      } else {
      }
    } catch (error) {
      throw error;
    } finally {
      spinning.value = false;
    }
  });
  const getTitle = computed(() =>
    !unref(isUpdate)
      ? t('system.tenantRole.text.createTitle')
      : t('system.tenantRole.text.editTitle')
  );

  // 取消全部的时候清除回显时获取的
  const handleUnSelectAll = () => {
    checkedKeysWithHalfChecked.value = [];
  };

  async function handleSubmit() {
    setDrawerProps({ loading: true, confirmLoading: true });
    const { createMessage } = useMessage();
    let treeCheckedKeys: string[] | CheckKeys =
      (unref(treeRef)?.getCheckedKeys() as string[] | CheckKeys) || [];
    //fix 取消层级独立后(unref(treeRef)?.getCheckedKeys() as string[])的数据不是数组,是{checked:[],halfChecked:[]}对象,迭代报错
    if (!Array.isArray(treeCheckedKeys)) {
      treeCheckedKeys = treeCheckedKeys?.checked;
    }
    const menu = [...new Set([...unref(checkedKeysWithHalfChecked), ...treeCheckedKeys])];
    try {
      const values = await validate();
      const req = {
        id: roleId.value,
        name: values.name,
        remark: values.remark,
        status: values.status,
        roleType: RoleEnum.TENANT_ADMIN,
        menu,
      };
      if (req.menu == undefined || !req.menu.length)
        return createMessage.error(t('system.tenantRole.valid.authAssignIsRequire'));
      const res = await saveOrUpdateRoleInfoWithMenu(req);
      if (res) {
        closeDrawer();
        emit('success');
        createMessage.success(
          unref(isUpdate) ? t('common.editSuccessText') : t('common.createSuccessText')
        );
        setDrawerProps({ loading: false });
        setDrawerProps({ confirmLoading: false });
      }
    } finally {
      setTimeout(() => {
        setDrawerProps({ loading: false });
        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: CheckKeys, event: CheckEvent) => {
    //fix 取消层级独立后selectedKeys不是数组,是{checked:[],halfChecked:[]}对象 迭代报错
    if (!Array.isArray(selectedKeys)) {
      selectedKeys = selectedKeys?.checked;
      event.halfCheckedKeys = [];
    }
    checkedKeysWithHalfChecked.value = [...selectedKeys, ...(event.halfCheckedKeys as string[])];
  };
</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>