How to add permissions to vxetable right-click menu options and render based on row data

How to add permissions to vxetable right-click menu options and render based on row data

Business scenario:

? The page has button permissions, and the right-click menu function is also implemented on the form. It is also necessary to control the permission function of the right-click menu.

Solution ideas:

  1. By viewing the document, right-click the configuration menu-config and select the attribute visibleMethod (Document description: The return value of this function is used to determine whether to allow the right-click menu to be displayed (for menus that need to be It may be used for permission control)), which can obtain these data

    ({<!-- --> type, options, columns, row?, rowIndex?, column?, columnIndex? }) => boolean
    // options is our configuration data
    // row is the currently clicked row
    
  2. When configuring the right-click options, add an attribute auth: ["Permission Encoding"]

  3. You need to use the usePermission method in hooks to verify permissions

  4. In visibleMethod, traverse the auth attribute in options to verify whether you have permission.

Code reference

vxeTable configuration

 ...
menuConfig: {<!-- -->
      // Right click configuration
      body: {<!-- -->
        options: [Options()],
      },
      visibleMethod: visibleMethod,
    },
 ...
 
//options configuration
 const orderClassTableMenuConfigOptions = () => {<!-- -->
  return [
    {<!-- -->
      code: 'refresh',
      name: 'Refresh',
      prefixIcon: 'vxe-icon-refresh',
      visible: true,
      disabled: false,
    },
    {<!-- -->
      code: 'add',
      name: 'New',
      prefixIcon: 'vxe-icon-feedback',
      visible: true,
      disabled: false,
      auth: ["yanjun202.com_add"],
    },
    {<!-- -->
      code: 'copy',
      name: 'Copy',
      prefixIcon: 'vxe-icon-paste',
      visible: true,
      disabled: true,
      auth: ["yanjun202.com_copy"],
    },] ;
//visibleMethod
function visibleMethod(Opt) {<!-- -->
  const {<!-- --> options, row, rowIndex, columns } = Opt;

  //Permission processing
  const {<!-- --> isPermission } = usePermission();

  options[0].forEach((item) => {<!-- -->
    if (item.auth) {<!-- -->
      //Can be set to hide or disable, controlled according to business scenarios
      item.visible = isPermission(item.auth);
    }
  });
   // Or you can determine whether to disable the button based on the row data
  if (row.orderClass == 'A' & amp; & amp; row.orderStatus !== '8') {<!-- -->
    // Enable or disable copying
    const index = options[0].findIndex((item) => item.code === 'copy');
    options[0][index].disabled = false;
  }
     return true;
}
 

Reference for writing usePermission: Source: Front-end Junge


/**
 * Whether maxList contains minList
 *
 * @param maxList large array
 * @param minList small array
 */
function containsAll(maxList: string[], minList: string[]) {<!-- -->
  return intersection(maxList, minList).length == minList.length;
}

/**
 * Determine whether there is permission
 *
 * @param permissionsOwns The permissions owned by the user (the set of permissions queried by the background/anyone/visible/resource interface)
 * @param toBeVerified Permission to be verified (the resource code written on the button, such as <a-button v-hasPermission="['system:menu:delete']">)
 */
function isPermitted(permissionsOwns: WildcardPermission[], toBeVerified: WildcardPermission) {<!-- -->
  if (permissionsOwns == null || permissionsOwns.length === 0) {<!-- -->
    return false;
  }
  // Traverse the permissions owned by the user and determine whether each one contains permissions to be verified.
  for (const owned of permissionsOwns) {<!-- -->
    if (owned.implies(toBeVerified)) {<!-- -->
      return true;
    }
  }
  return false;
}

const WILDCARD_TOKEN = '*'; // wildcard
const PART_DIVIDER_TOKEN = ':'; // module separator
const SUBPART_DIVIDER_TOKEN = ','; // Function separator

/**
 * Wildcard permission parsing object
 */
class WildcardPermission {<!-- -->
  //The parsed permission set contains only :
  parts: string[][];

  /**
   * Parse and store wildcardString into parts
   *
   * @param wildcardString original wildcard string
   * @param caseSensitive whether it is case-sensitive true: distinguish; false: ignore case
   */
  constructor(wildcardString: string, caseSensitive: boolean) {<!-- -->
    this.parts = [];
    this._init_(wildcardString, caseSensitive);
  }

  // Parse wildcards
  _init_(wildcardString: string, caseSensitive: boolean) {<!-- -->
    if (wildcardString == null || wildcardString.trim().length === 0) {<!-- -->
      throw new Error('The permission encoding wildcard string cannot be null or empty. Make sure the permission string is in the correct format.');
    }
    wildcardString = wildcardString.trim();
    const parts: string[] = wildcardString.split(PART_DIVIDER_TOKEN);
    this.parts = [];
    for (const part of parts) {<!-- -->
      let subParts: string[] = part.split(SUBPART_DIVIDER_TOKEN);
      if (!caseSensitive) {<!-- -->
        const lowerSubParts: string[] = [];
        for (const subPart of subParts) {<!-- -->
          lowerSubParts.push(subPart.toLocaleLowerCase());
        }
        subParts = lowerSubParts;
      }
      if (subParts.length <= 0) {<!-- -->
        throw new Error(
          'The permission encoding wildcard string cannot contain parts with only delimiters. Ensure that the permission encoding string is in the correct format. ',
        );
      }
      this.parts.push(subParts);
    }

    if (this.parts.length <= 0) {<!-- -->
      throw new Error('The permission encoding wildcard string cannot only contain delimiters, make sure the format of the permission encoding string is correct.');
    }
  }

  //The real judgment logic
  implies(toBeVerified: WildcardPermission) {<!-- -->
    const toBeVerifiedParts = toBeVerified.parts;
    let i = 0;
    for (const toBeVerifiedPart of toBeVerifiedParts) {<!-- -->
      // If this permission has fewer parts than other permissions, everything after the number of parts contained in this permission will automatically be implicit, so return true
      if (this.parts.length - 1 < i) {<!-- -->
        return false;
      } else {<!-- -->
        const part = this.parts[i];
        if (!part.includes(WILDCARD_TOKEN) & amp; & amp; !containsAll(part, toBeVerifiedPart)) {<!-- -->
          return false;
        }
        i + + ;
      }
    }

    // If this permission has more parts than others, it will only be implied if all other parts are wildcards
    for (; i <this.parts.length; i + + ) {<!-- -->
      const part = this.parts[i];
      if (!part.includes(WILDCARD_TOKEN)) {<!-- -->
        return false;
      }
    }
    return true;
  }
}

const permMap = {<!-- -->};

// User permissions related operations
export function usePermission() {<!-- -->
  const userStore = useUserStore();
  const appStore = useAppStore();
  const permissionStore = usePermissionStore();
  const {<!-- --> closeAll } = useTabs(router);

  /**
   * Change permission mode
   */
  async function togglePermissionMode() {<!-- -->
    appStore.setProjectConfig({<!-- -->
      permissionMode:
        projectSetting.permissionMode === PermissionModeEnum.BACK
          ?PermissionModeEnum.ROUTE_MAPPING
          : PermissionModeEnum.BACK,
    });
    location.reload();
  }

  /**
   * Reset and regain authority resource information
   * @param id
   */
  async function resume() {<!-- -->
    const tabStore = useMultipleTabStore();
    tabStore.clearCacheTabs();
    resetRouter();
    const routes = await permissionStore.buildRoutesAction();
    routes.forEach((route) => {<!-- -->
      router.addRoute(route as unknown as RouteRecordRaw);
    });
    permissionStore.setLastBuildMenuTime();
    closeAll();
  }
  /**
   * Must contain all permissions listed for the element to be displayed
   */
  function hasPermission(value?: RoleEnum | RoleEnum[] | string | string[], def = true): boolean {<!-- -->
    return isPermission(value, def, PermModeEnum.Has);
  }
  /**
   * Renders this element when all permissions listed are not included
   */
  function withoutPermission(
    value?: RoleEnum | RoleEnum[] | string | string[],
    def = true,
  ): boolean {<!-- -->
    return isPermission(value, def, PermModeEnum.Without);
  }
  /**
   * Renders this element when none of the listed permissions are included
   */
  function withoutAnyPermission(
    value?: RoleEnum | RoleEnum[] | string | string[],
    def = true,
  ): boolean {<!-- -->
    return isPermission(value, def, PermModeEnum.WithoutAny);
  }
  /**
   * As long as any of the listed permissions are included, the element will be displayed
   */
  function hasAnyPermission(
    value?: RoleEnum | RoleEnum[] | string | string[],
    def = true,
  ): boolean {<!-- -->
    return isPermission(value, def, PermModeEnum.HasAny);
  }
  /**
   * Judgment authority
   *
   * @param value needs to determine whether the current user owns the resource code
   * @param def value When it is empty, whether it is owned by default
   * @param mode mode optional values: have all have any none
   */
  function isPermission(
    value?: RoleEnum | RoleEnum[] | string | string[],
    def = true,
    mode = PermModeEnum.Has,
  ): boolean {<!-- -->
    // Visible by default
    if (!value) {<!-- -->
      return def;
    }

    const permMode = projectSetting.permissionMode;

    if ([PermissionModeEnum.ROUTE_MAPPING, PermissionModeEnum.ROLE].includes(permMode)) {<!-- -->
      if (!isArray(value)) {<!-- -->
        return userStore.getRoleList?.includes(value as RoleEnum);
      }
      return (intersection(value, userStore.getRoleList) as RoleEnum[]).length > 0;
    }

    if (PermissionModeEnum.BACK === permMode) {<!-- -->
      const visibleResource = permissionStore.getVisibleResource;
      const enabled = visibleResource?.enabled;
      if (!enabled) {<!-- -->
        return true;
      }

      let flag = true;
      if (mode === PermModeEnum.HasAny || mode === PermModeEnum.WithoutAny) {<!-- -->
        flag = false;
      }
      const resourceList = visibleResource.resourceList;
      const caseSensitive = visibleResource.caseSensitive;
      // The permissions to be verified must be an array
      let permissions = value;
      if (!isArray(value)) {<!-- -->
        permissions = [value];
      }

      if (permissions != null & amp; & amp; permissions.length > 0) {<!-- -->
        //Convert the permissions you have
        const permissionsOwns: WildcardPermission[] = [];
        // Bug: After exiting from the developer system, logging in to the basic platform will prompt that there is no permission.
        // if (map.permissionsOwns & amp; & amp; map.permissionsOwns.length > 0) {<!-- -->
        // permissionsOwns = map.permissionsOwns;
        // } else {<!-- -->
        for (const resource of resourceList) {<!-- -->
          // let wp: WildcardPermission;
          // if (permMap[resource]) {<!-- -->
          // wp = permMap[resource];
          // } else {<!-- -->
          // wp = new WildcardPermission(resource, caseSensitive);
          // }
          permissionsOwns.push(new WildcardPermission(resource, caseSensitive));
        }
        // map.permissionsOwns = permissionsOwns;
        // }

        for (const strPerm of permissions) {<!-- -->
          let toBeVerified;
          if (permMap[strPerm]) {<!-- -->
            toBeVerified = permMap[strPerm];
          } else {<!-- -->
            toBeVerified = new WildcardPermission(strPerm, caseSensitive);
          }
          // Different modes have different verification rules.
          if (mode === PermModeEnum.Has) {<!-- -->
            //Have all permissions
            if (!isPermitted(permissionsOwns, toBeVerified)) {<!-- -->
              flag = false;
            }
          } else if (mode === PermModeEnum.Without) {<!-- -->
            // Without all permissions `Insert image description here
`
            if (isPermitted(permissionsOwns, toBeVerified)) {<!-- -->
              flag = false;
            }
          } else if (mode === PermModeEnum.HasAny) {<!-- -->
            //Have any permission
            if (isPermitted(permissionsOwns, toBeVerified)) {<!-- -->
              flag = true;
            }
          } else if (mode === PermModeEnum.WithoutAny) {<!-- -->
            // Does not have any permissions
            if (!isPermitted(permissionsOwns, toBeVerified)) {<!-- -->
              flag = true;
            }
          }
        }
      }

      return flag;
    }
    return true;
  }

  /**
   * Change roles
   * @param roles
   */
  async function changeRole(roles: RoleEnum | RoleEnum[]): Promise<void> {<!-- -->
    if (projectSetting.permissionMode !== PermissionModeEnum.ROUTE_MAPPING) {<!-- -->
      throw new Error(
        'Please switch PermissionModeEnum to ROUTE_MAPPING mode in the configuration to operate!',
      );
    }

    if (!isArray(roles)) {<!-- -->
      roles = [roles];
    }
    userStore.setRoleList(roles);
    await resume();
  }

  /**
   * refresh menu data
   */
  async function refreshMenu() {<!-- -->
    resume();
  }

  return {<!-- -->
    changeRole,
    isPermission,
    hasPermission,
    withoutPermission,
    withoutAnyPermission,
    hasAnyPermission,
    togglePermissionMode,
    refreshMenu,
  };
}