Ever Gauzy Onboarding UI 插件实战指南:从零构建新用户引导流程

原创2026-09-30 15:10:001,459 阅读
文章标签:后端前端企业应用MCP 服务

Ever Gauzy Onboarding UI 插件实战指南:从零构建新用户引导流程

导读

本文聚焦 Ever Gauzy 开源商业管理平台中的 @gauzy/plugin-onboarding-ui 插件,系统讲解其核心职责、路由结构与源码级实现原理。通过本文,你将掌握该插件的构建、测试、发布与安装方式,理解新用户注册后“创建租户 → 创建组织 → 注册为员工 → 完成引导”的完整链路,并学会如何将插件集成进 Gauzy 平台。文中所有结论均以当前仓库 packages/plugins/onboarding-ui 的实际代码与配置为依据。

一、插件是什么:面向新用户的引导界面

@gauzy/plugin-onboarding-ui 是 Ever Gauzy 平台中的一个 Angular 前端插件,由 Nx 工作区生成。它在官方 README(packages/plugins/onboarding-ui/README.md)中被定位为:

Provides a user-friendly interface for onboarding new users into the Gauzy platform.

即:为新注册用户提供一套友好的引导式界面,帮助他们在进入系统后快速完成第一轮关键配置——创建属于自己的租户(Tenant)与默认组织(Organization)。

从工程结构看,插件的源码全部位于 src/lib 下,包含三个核心 UI 组件与一个模块、一组路由:

  • onboarding.module.ts:模块定义与依赖装配
  • onboarding.routes.ts:路由注册
  • components/onboarding.component.ts:外层布局壳
  • components/tenant-onboarding/:租户/组织创建页
  • components/onboarding-complete/:引导完成页(功能快捷入口)

在 package.json 中,插件被描述为 “A plugin for the onboarding UI in the Ever Gauzy platform, providing user-friendly components and modules to facilitate the onboarding process”,许可证为 AGPL-3.0,标记为 "private": true 并声明 "sideEffects": false,说明它作为纯 UI 库被发布,不影响摇树优化。

二、构建、测试、发布与安装:完整的库生命周期

2.1 构建

使用 Nx 提供的构建命令(须在仓库根目录执行):

yarn nx build plugin-onboarding-ui

插件自身的 package.json 还封装了三种常用构建模式:

yarn lib:build        # yarn nx build plugin-onboarding-ui --configuration=development
yarn lib:build:prod   # yarn nx build plugin-onboarding-ui --configuration=production
yarn lib:watch        # yarn nx build plugin-onboarding-ui --watch --configuration=development
  • --configuration=development 产出开发态构建,适合调试;
  • --configuration=production 产出生产态构建,用于发布;
  • --watch 模式在本地开发组件时持续监听文件变更并自动重新构建。

2.2 运行单元测试

执行以下命令运行插件的单元测试:

yarn nx test plugin-onboarding-ui

测试基础设施由仓库根目录的 jest.config.ts、插件目录下的 jest.config.ts 与 test-setup.ts 提供,测试框架为 Jest(配合 jest-preset-angular),因此该命令实际执行的是 Angular 组件级的单元测试。

2.3 发布

构建完成后,进入 Nx 输出的 dist 目录并发布到 npm:

cd dist/packages/plugins/onboarding-ui
npm publish

发布内容由 packages/plugins/onboarding-ui/ng-package.json 控制(Angular Package Format),产物只包含编译后的组件与模块,不含源码与测试文件。

2.4 安装

在目标应用中通过你偏好的包管理器安装:

npm install @gauzy/plugin-onboarding-ui
# or
yarn add @gauzy/plugin-onboarding-ui

安装到宿主应用后,通常还需在应用的路由/模块配置中注册该插件(见下一节的路由装配机制),再配合 Gauzy 平台自身的 @gauzy/ui-core 服务使用。

三、源码级剖析:模块装配与路由注册

3.1 模块如何组织依赖

打开 packages/plugins/onboarding-ui/src/lib/onboarding.module.ts,可以看到模块的 imports 分为几类:

  • UI 组件库:@nebular/theme 的 NbButtonModule、NbCardModule、NbIconModule、NbLayoutModule、NbSpinnerModule;
  • 国际化与权限:@ngx-translate/core 的 TranslateModule.forChild()、ngx-permissions 的 NgxPermissionsModule.forRoot();
  • Gauzy UI 生态:@gauzy/ui-core/theme 的 ThemeModule、ThemeSelectorModule、ThemeSettingsModule,以及 @gauzy/ui-core/shared 的 OrganizationsStepFormModule 与 EmailVerificationNoticeComponent;
  • 路由:RouterModule.forChild([])。

模块 declarations 声明了三个组件,exports 导出 RouterModule,并在 providers 中注入了 AuthService、FeatureStoreService、TenantService、RoleGuard 等服务。

关键的设计亮点是路由提供者:

{
    provide: ROUTES,
    useFactory: (service: PageRouteRegistryService) => createOnboardingRoutes(service),
    deps: [PageRouteRegistryService],
    multi: true
}

它借助 PageRouteRegistryService(来自 @gauzy/ui-core/core)以工厂方式动态生成路由,并通过 multi: true 注册到 Angular 路由系统。这种“按需注册路由”的模式是 Gauzy 插件体系的标准做法——插件可以独立贡献路由,而无需修改宿主应用的主路由表。

3.2 路由结构

packages/plugins/onboarding-ui/src/lib/onboarding.routes.ts 定义了三条路由:

export const createOnboardingRoutes = (_pageRouteRegistryService: PageRouteRegistryService): Route[] => [
    {
        path: '',
        component: OnboardingComponent,
        children: [
            {
                path: 'tenant',
                component: TenantOnboardingComponent,
                resolve: { user: OnboardingResolver }
            },
            {
                path: 'complete',
                component: OnboardingCompleteComponent
            }
        ]
    }
];
  • 根路由挂载 OnboardingComponent 作为布局壳;
  • /onboarding/tenant:租户/组织创建页,通过 OnboardingResolver(来自 @gauzy/ui-core/core)预解析当前用户数据,确保页面渲染前用户信息已就绪;
  • /onboarding/complete:引导完成页,展示可用的功能快捷入口。

3.3 外层布局壳

components/onboarding.component.ts 是纯布局组件,模板如下:

<nb-layout windowMode>
    <ngx-theme-settings></ngx-theme-settings>
    <nb-layout-column>
        <router-outlet></router-outlet>
    </nb-layout-column>
</nb-layout>

它使用 Nebular 的 windowMode 全屏布局,嵌入主题设置组件 ngx-theme-settings,并通过 <router-outlet> 渲染子路由,两个引导子页面共用这一套布局与主题。

四、核心业务流:tenant-onboarding 组件

4.1 页面结构

tenant-onboarding.component.html 展示了引导首页的界面要素:

  • 顶部主题切换器 <gauzy-switch-theme>(无文字模式);
  • Gauzy Logo 与多语言标题 ONBOARDING.FIRST_ORGANIZATION(“创建第一个组织”);
  • 邮箱验证提示 <ngx-email-verification-notice>——因为注册即登录,所以在这第一页就明确告知用户验证邮件已发送并提供“重新发送”入口,而不是等到进入仪表盘才提示;
  • 核心表单 <ga-organizations-step-form [loading]="loading" [isOnboarding]="true" (createOrganization)="onboardUser($event)">,这是来自 @gauzy/ui-core/shared 的 OrganizationsStepFormModule 提供的组织创建分步表单,以 isOnboarding 标志切换为引导模式,并把提交事件回传给 onboardUser 方法。

4.2 初始化与用户数据加载

组件初始化时订阅 ActivatedRoute.data:

ngOnInit() {
    this._activatedRoute.data
        .pipe(
            filter(({ user }: Data) => !!user),
            tap(({ user }: Data) => (this._store.user = user)),
            tap(() => (this.loading = false)),
            untilDestroyed(this)
        )
        .subscribe();
}

它从路由解析器拿到的 user 写入全局 Store,并通过 @ngneat/until-destroy 的 untilDestroyed 防止内存泄漏。

4.3 onboardUser:完整引导链路

onboardUser(见 tenant-onboarding.component.ts)是整个引导流程的引擎,按以下步骤执行:

  1. 读取 Stripe 会话(可选):调用 readRememberedCheckoutSession() 读取注册表单记住的 Stripe Checkout Session。若用户是通过共享结账页(shared checkout)注册的买家,这个 session id 会随租户创建一起发送给 API,使 API 能在验证 Stripe 后立即把新租户关联到对应的 Stripe customer,而无需等待邮箱确认;
  2. 创建租户:this._tenantService.create({ name: organization.name, ...(stripeCheckoutSessionId ? { stripeCheckoutSessionId } : {}) }),随后 clearRememberedCheckoutSession() 清理会话残留;
  3. 拉取最新用户信息:this._usersService.getMe(['tenant']) 重新获取带 tenant 关系的用户数据并写入 Store;
  4. 创建默认组织:this._organizationsService.create({ ...organization, tenant, isDefault: true }),即把表单数据与刚创建的租户绑定,并标记为默认组织;
  5. 刷新令牌:调用 getAccessTokenFromRefreshToken()——若 Store 中存在 refresh_token,则通过 _authService.refreshToken(refresh_token) 换取新 access token 写回 Store;
  6. 注册员工(后台执行):registerEmployeeFeature(organization, createdOrganization) 不阻塞主流程;
  7. 跳转完成页:this._router.navigate(['/onboarding/complete'])。

4.4 registerEmployeeFeature:可选员工注册

registerEmployeeFeature 的逻辑是:当表单勾选了 registerAsEmployee 时,把当前用户注册为该组织的员工:

if (organization.registerAsEmployee) {
    const { id: organizationId } = createdOrganization;
    const { id: userId, tenantId } = this.user;
    await firstValueFrom(
        this._employeesService.create({
            startedWorkOn: organization.startedWorkOn ? new Date(organization.startedWorkOn) : null,
            userId,
            organizationId,
            tenantId
        })
    );
}

其中 startedWorkOn(入职日期)可为空,为空时传入 null。该调用通过 firstValueFrom 把 Observable 转为 Promise 后 await,失败时仅记录错误日志,不中断整体引导。

五、引导完成页:onboarding-complete 组件

5.1 功能入口展示

onboarding-complete.component.html 渲染两种数据流:

  • blocks$: Observable<IFeature[][]> 与 features$: Observable<IFeature[]>,均来自 FeatureStoreService;
  • 模板用 Angular 新控制流 @for 遍历 block(功能块分组)与 row(功能项),每个功能项渲染为一张 nb-card 快捷卡片,展示图标(row?.icon)、名称(row?.name)、描述(row?.description)与状态(row?.status),点击整张卡片触发 navigateTo(row?.link)。

这本质上是把平台可用的业务功能(来自 Feature Store)以卡片矩阵形式呈现,让新用户一眼看到可以进入的模块。

5.2 权限与功能初始化

onboarding-complete.component.ts 在 ngOnInit 中完成两件关键初始化:

  1. 权限装载:调用 PermissionsService.getPermissions() 获取当前用户的角色权限(IRolePermission[]),随后 initializeUiPermissions 将权限名数组 flushPermissions() 后 loadPermissions(permissions) 注入 ngx-permissions,使后续 *ngxPermissions 指令能正确控制界面元素显隐;
  2. 功能加载:getFeatures() 调用 FeatureStoreService.loadFeatures(['children']) 拉取带子功能的功能树,驱动卡片矩阵渲染。

导航方法 navigateTo(link) 先通过 link.replace(/^\/|\/$/g, '') 去掉首尾斜杠,再拼接到 pages/ 前缀下:this._router.navigate([pages/${normalizedLink}]),从而在 Gauzy 主应用中以 pages/xxx 的相对路径进入对应业务页面。

六、插件的集成方式与适用前提

6.1 集成要点

从模块源码可见,集成 OnboardingModule 需要宿主应用满足以下前提(这些均来自 peerDependencies 与实际 import):

  • Angular 运行时:@angular/common 与 @angular/core 均为 21.0.7(见 package.json),并依赖 @angular/router;
  • Gauzy UI 生态包:@gauzy/contracts、@gauzy/ui-core(提供 AuthService、FeatureStoreService、PageRouteRegistryService、OnboardingResolver、OrganizationsService、TenantService 等);
  • 第三方 UI 与工具:@nebular/theme(^17.0.0)、@ngneat/until-destroy、@ngx-translate/core、ngx-permissions、rxjs;
  • 运行时环境:engines 声明 node >= 22、yarn >= 1.22。

6.2 适用场景

该插件服务于 Ever Gauzy 的注册后引导流程(对应路径 /onboarding/tenant 与 /onboarding/complete),典型使用场景包括:

  • 新用户注册后首次进入平台,创建自己的租户与默认组织;
  • 通过共享结账购买 Gauzy 服务的用户,注册时携带 Stripe Checkout Session,实现“先创建租户、后确认邮箱”的即时开通;
  • 引导完成页集中展示平台功能入口,降低新用户上手门槛。

七、小结

@gauzy/plugin-onboarding-ui 虽是一个体量不大的前端插件,却完整示范了 Ever Gauzy 插件体系的关键模式:通过 PageRouteRegistryService 以 ROUTES 工厂动态贡献路由、复用 @gauzy/ui-core 的服务与共享组件、在组件内串联租户/组织/员工创建并同步权限与功能加载。如果你希望为 Gauzy 平台贡献类似的引导型或向导型 UI 插件,本插件的模块装配、路由注册与服务调用链是一份可直接参考的范本。

参考资料

登录后查看全文
ever-gauzy