UNPKG

vue-app-sdk

Version:
309 lines (308 loc) 11.8 kB
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; } }