vue-app-sdk
Version:
309 lines (308 loc) • 11.8 kB
TypeScript
import { Awaitable, MaybeFn, WithChildren } from '@rhao/types-base';
import { ToTreeArrayOptions } from 'nice-fns';
import { AppSDKInternalInstance, Plugin, PluginID } from '../..';
import { RouteComponent, RouteLocationNormalizedLoaded, RouteMeta, RouteRecordNormalized, RouteRecordRaw } from 'vue-router';
import { PageMetadata, PageMetadataWithChildren, RoleList } from './interface';
import { MaybeRefOrGetter } from 'vue';
export interface PageOptions {
/**
* 是否为移动端应用,设为 `true` 时在调用 `handleMenuClick` 时将禁用动画插件(若存在)的导航动画并使用 `router.replace` 跳转
*/
isMobile?: MaybeRefOrGetter<boolean>;
/**
* 跳转外链时若存在已打开的外链窗口是否重复使用进行跳转
* @default false
*/
linkSingleWindow?: boolean;
/**
* 调用 `handleMenuClick` 时是否允许跳转外链,返回假值时走正常页面跳转
* @default (menu) => menu.link
*/
allowLink?: (menu: PageMetadata) => boolean;
/**
* 根据 `page.file` 获取真实组件
* @example
* ```ts
* const page = createPage({ resolveComponent: (file) => () => import(`src/${file}.vue`) })
*
* const route = page.pageToRoute({ file: 'home/index' })
* route.component // () => import('src/home/index.vue')
*/
resolveComponent: (file: string, page: PageMetadata) => MaybeFn<Awaitable<RouteComponent>, []>;
/**
* 校准不符合 `PageMetadata` 的元数据
* @param data 不符合的元数据
* @returns 符合的元数据
*
* @example
* ```ts
* // ❌ 不符合 PageMetadata 的元数据
* { id: 1, routeName: 'home', routePath: '/home', sort: 0, ... }
*
* // 校准后 ↓
*
* // ✔️ 符合 PageMetadata 的元数据
* { id: 1, name: 'home', path: '/home', index: 0, ... }
* ```
*/
calibrateMetadata?: (data: any) => PageMetadata;
}
/**
* Page Plugin ID
*/
export declare const PAGE_ID: PluginID<Page>;
/**
* 应用页面管理插件
*/
export declare class Page implements Plugin {
/**
* 配置项
*/
options: PageOptions;
constructor(
/**
* 配置项
*/
options: PageOptions);
id: PluginID<Page>;
/**
* AppSDK 实例
*/
private _sdk;
/**
* 移除路由函数列表
*/
private _removeRouteFns;
/**
* 已打开的窗口实例
*/
private openedWindow;
/**
* 校准页面元数据
* @readonly
*/
get calibrateMetadata(): (data: any) => PageMetadata;
/**
* 是否允许跳转外链
* @readonly
*/
get allowLink(): (menu: PageMetadata) => boolean;
/**
* 重置路由列表为初始创建路由器时传入的列表
*/
resetRoutes: () => void;
/**
* 获取路由上的页面元数据(浅拷贝)
* @param data `route` 或 `route.meta`
*/
getPageMetadata: (data: Pick<RouteRecordNormalized, "meta"> | RouteMeta) => Partial<PageMetadata>;
/**
* 将树形元数据列表扁平化为符合 `PageMetadata` 的页面元数据列表
* @param data 树形元数据列表
* @param options 配置项
* @returns 扁平化的页面元数据列表
*/
toFlattenPages: <T extends {}, Calibrate extends boolean = false>(data: T[], options?: Pick<ToTreeArrayOptions, "childrenKey"> & {
/**
* 是否克隆源数据,避免转换时影响到源数据
* @default false
*/
clone?: boolean;
/**
* 是否校准元数据,数据格式不符合 `PageMetadata` 时可以设为 `true`
* @default false
*/
calibrate?: Calibrate;
/**
* 是否补全路径,设为 `true` 后会对 `path` 进行拼接补全,可以在 `addRoute()` 时不受父子级限制
* @default false
*/
completePath?: boolean;
}) => Calibrate extends true ? PageMetadata[] : T[];
/**
* 将元数据列表转为符合 `PageMetaWithChildren` 的树形页面元数据列表
* @param data 元数据列表
* @param options 配置项
* @param options.strict 严格模式,开启后将移除父子关联不存在的数据
* @param options.clone 是否克隆源数据,避免转换时影响到源数据
* @param options.calibrate 是否校准元数据,数据格式不符合 `PageMetadata` 时可以设为 `true`
* @param options.completePath 是否补全路径,设为 `true` 后会对 `path` 进行拼接补全,可以在 `addRoute()` 时不受父子级限制
* @returns 树形页面元数据列表
*/
toTreePages: <T extends {}, Calibrate extends boolean = false>(data: T[], options?: {
/**
* 严格模式,开启后将移除父子关联不存在的数据
*/
strict?: boolean;
/**
* 是否克隆源数据,避免转换时影响到源数据
* @default false
*/
clone?: boolean;
/**
* 是否校准元数据,数据格式不符合 `PageMetadata` 时可以设为 `true`
* @default false
*/
calibrate?: Calibrate;
/**
* 是否补全路径,设为 `true` 后会对 `path` 进行拼接补全,可以在 `addRoute()` 时不受父子级限制
* @default false
*/
completePath?: boolean;
}) => Calibrate extends true ? PageMetadataWithChildren[] : WithChildren<T, "children", false>[];
/**
* 父子关联页面元数据列表转为树形菜单列表,返回深克隆数据,与源数据不共用内存引用
* @param pages 页面元数据列表
* @param strict 严格模式
* @returns 树形菜单元数据列表
*/
toMenus: (pages: PageMetadata[], strict: boolean) => WithChildren<PageMetadata, "children", false>[];
/**
* 指定角色列表是否可以访问页面
* @param page 页面元数据
* @param roleList 角色列表
* @param strict 严格模式
* @returns 是否可以访问页面
*/
canVisitPage: (page: PageMetadata, roleList: RoleList, strict: boolean) => boolean;
/**
* 过滤指定角色可以访问的页面元数据列表
* @param pages 页面元数据列表
* @param roleList 角色列表
* @param strict 严格模式
* @returns 可以访问的页面元数据列表
*/
filterVisitPages: (pages: PageMetadata[], roleList: RoleList, strict: boolean) => PageMetadata[];
/**
* 创建不同场景下的页面元数据状态
* @param pages 页面元数据列表
* @param options 配置项
*/
createStates: <T extends {}, ActiveMenu = string>(pages: MaybeRefOrGetter<T[]>, options: Pick<ToTreeArrayOptions, "childrenKey"> & {
/**
* `pages` 格式
*/
format: MaybeRefOrGetter<"list" | "tree">;
/**
* 严格模式,开启后扁平化列表转为树形列表时将移除父子关联不存在的数据
*/
strict?: MaybeRefOrGetter<boolean>;
/**
* 角色列表,用于过滤页面
* @default []
*/
roleList?: MaybeRefOrGetter<RoleList>;
/**
* 严格访问模式,开启时若指定角色列表或页面角色列表为空时则不能访问页面
* @default true
*/
strictVisit?: MaybeRefOrGetter<boolean>;
/**
* 角色过滤页面时是否子级优先
* - `true`: 子级存在权限时父级必定存在
* - `false`: 父级无权限时子级必定不存在
* @default true
*/
childrenFirst?: MaybeRefOrGetter<boolean>;
/**
* 是否补全路径,设为 `true` 后会对 `path` 进行拼接补全,可以在 `addRoute()` 时不受父子级限制
* @default true
*/
completePath?: MaybeRefOrGetter<boolean>;
/**
* 根据当前路由获取激活菜单标识
* @default
* ```ts
* (route) => this.getPageMetadata(route).activeMenu || this.getPageMetadata(route).name || ''
* ```
*/
resolveActiveMenu?: (route: RouteLocationNormalizedLoaded, states: {
flattenPages: PageMetadata[];
treePages: PageMetadataWithChildren[];
visitablePages: PageMetadata[];
visitableTreePages: PageMetadataWithChildren[];
visitableMenus: PageMetadataWithChildren[];
visitablePageMap: Record<PageMetadata["id"], PageMetadata>;
visitableTreeLinkMap: Record<PageMetadata["id"], PageMetadataWithChildren[]>;
}) => ActiveMenu;
}) => {
/**
* 扁平化的页面元数据列表
*/
flattenPages: import('vue').ShallowRef<PageMetadata[]>;
/**
* 树形页面元数据列表
*/
treePages: import('vue').ShallowRef<PageMetadataWithChildren[]>;
/**
* 可访问的树形页面元数据列表
*/
visitableTreePages: import('vue').ShallowRef<PageMetadataWithChildren[]>;
/**
* 可访问的页面元数据列表
*/
visitablePages: import('vue').ShallowRef<PageMetadata[]>;
/**
* 可访问的页面元数据映射
*/
visitablePageMap: import('vue').ShallowRef<Record<string | number, PageMetadata>>;
/**
* 可访问的树形页面元数据链路映射
*/
visitableTreeLinkMap: import('vue').ShallowRef<Record<string | number, PageMetadataWithChildren[]>>;
/**
* 可访问的菜单页面元数据列表
*/
visitableMenus: import('vue').ShallowRef<PageMetadataWithChildren[]>;
/**
* 激活的菜单页面标识
*/
activeMenu: import('vue').ComputedRef<ActiveMenu>;
};
/**
* 页面元数据转为路由配置
* @param page 页面元数据
* @param extraProps 路由额外参数
* @param syncName 同步组件 `name` 为路由 `name`,可以更好的配合 `KeepAlive` 组件缓存
* @returns 路由配置
*/
pageToRoute: (page: PageMetadata, extraProps?: Omit<RouteRecordRaw, "path" | "name" | "redirect" | "component">, syncName?: boolean | ((name: string, page: PageMetadata) => string)) => RouteRecordRaw;
/**
* 获取页面元数据设置的外链地址
* @param page 页面元数据
* @param selfLink 获取自身的外链地址(等同于 `page.link=true`)
* @returns 外链地址
*
* @example
* ```ts
* resolveLink({ path: '/test', name: 'test', link: true })
* // => '/test'
*
* resolveLink({ path: '/test', name: 'test', link: '//www.test.com' })
* // => '//www.test.com'
*
* resolveLink({ path: '/test', name: 'test' })
* // => ''
*
* resolveLink({ path: '/test/:id', name: 'test', routeParams: { id: 1 } }, true)
* // => '/test/1'
* ```
*/
resolveLink: (page: PageMetadata, selfLink?: boolean) => string;
/**
* 处理菜单点击,设置 `link` 时将会在客户端新标签页打开指定路由页或网站,
* 在 `options.isMobile` 设为 `true` 时将禁用动画插件(若存在)的导航动画并使用 `router.replace` 跳转
* @param menu 页面元数据
* @param singleWindow 跳转外链时若存在已打开的外链窗口是否重复使用进行跳转
*/
handleMenuClick: (menu: PageMetadata, singleWindow?: boolean | undefined) => void;
install(sdk: AppSDKInternalInstance): () => void;
}
declare module 'vue-router' {
interface RouteMeta {
/**
* 页面元数据
*/
_metadata?: PageMetadata;
}
}